|
28 | 28 |
|
29 | 29 | import click |
30 | 30 | from packaging.version import parse |
| 31 | +from google.adk.cli.utils import build_utils |
| 32 | +from google.adk.cli.utils import gcp_utils |
31 | 33 |
|
32 | | -_IS_WINDOWS = os.name == 'nt' |
33 | | -_GCLOUD_CMD = 'gcloud.cmd' if _IS_WINDOWS else 'gcloud' |
34 | | -_LOCAL_STORAGE_FLAG_MIN_VERSION: Final[str] = '1.21.0' |
35 | 34 | _AGENT_ENGINE_REQUIREMENT: Final[str] = ( |
36 | 35 | 'google-cloud-aiplatform[adk,agent_engines]' |
37 | 36 | ) |
@@ -63,45 +62,6 @@ def _ensure_agent_engine_dependency(requirements_txt_path: str) -> None: |
63 | 62 | f.write(_AGENT_ENGINE_REQUIREMENT + '\n') |
64 | 63 |
|
65 | 64 |
|
66 | | -_DOCKERFILE_TEMPLATE: Final[str] = """ |
67 | | -FROM python:3.11-slim |
68 | | -WORKDIR /app |
69 | | -
|
70 | | -# Create a non-root user |
71 | | -RUN adduser --disabled-password --gecos "" myuser |
72 | | -
|
73 | | -# Switch to the non-root user |
74 | | -USER myuser |
75 | | -
|
76 | | -# Set up environment variables - Start |
77 | | -ENV PATH="/home/myuser/.local/bin:$PATH" |
78 | | -
|
79 | | -ENV GOOGLE_GENAI_USE_VERTEXAI=1 |
80 | | -ENV GOOGLE_CLOUD_PROJECT={gcp_project_id} |
81 | | -ENV GOOGLE_CLOUD_LOCATION={gcp_region} |
82 | | -
|
83 | | -# Set up environment variables - End |
84 | | -
|
85 | | -# Install ADK - Start |
86 | | -RUN pip install google-adk=={adk_version} |
87 | | -# Install ADK - End |
88 | | -
|
89 | | -# Copy agent - Start |
90 | | -
|
91 | | -# Set permission |
92 | | -COPY --chown=myuser:myuser "agents/{app_name}/" "/app/agents/{app_name}/" |
93 | | -
|
94 | | -# Copy agent - End |
95 | | -
|
96 | | -# Install Agent Deps - Start |
97 | | -{install_agent_deps} |
98 | | -# Install Agent Deps - End |
99 | | -
|
100 | | -EXPOSE {port} |
101 | | -
|
102 | | -CMD adk {command} --port={port} {host_option} {service_option} {trace_to_cloud_option} {otel_to_cloud_option} {allow_origins_option} {a2a_option} {trigger_sources_option} "/app/agents" |
103 | | -""" |
104 | | - |
105 | 65 | _AGENT_ENGINE_APP_TEMPLATE: Final[str] = """ |
106 | 66 | import os |
107 | 67 | import vertexai |
@@ -409,17 +369,9 @@ def _ensure_agent_engine_dependency(requirements_txt_path: str) -> None: |
409 | 369 |
|
410 | 370 |
|
411 | 371 | def _resolve_project(project_in_option: Optional[str]) -> str: |
412 | | - if project_in_option: |
413 | | - return project_in_option |
414 | | - |
415 | | - result = subprocess.run( |
416 | | - [_GCLOUD_CMD, 'config', 'get-value', 'project'], |
417 | | - check=True, |
418 | | - capture_output=True, |
419 | | - text=True, |
420 | | - ) |
421 | | - project = result.stdout.strip() |
422 | | - click.echo(f'Use default project: {project}') |
| 372 | + project = gcp_utils.resolve_project(project_in_option) |
| 373 | + if not project_in_option: |
| 374 | + click.echo(f'Use default project: {project}') |
423 | 375 | return project |
424 | 376 |
|
425 | 377 |
|
@@ -585,45 +537,6 @@ def _validate_agent_import( |
585 | 537 | sys.modules.pop(key, None) |
586 | 538 |
|
587 | 539 |
|
588 | | -def _get_service_option_by_adk_version( |
589 | | - adk_version: str, |
590 | | - session_uri: Optional[str], |
591 | | - artifact_uri: Optional[str], |
592 | | - memory_uri: Optional[str], |
593 | | - use_local_storage: Optional[bool] = None, |
594 | | -) -> str: |
595 | | - """Returns service option string based on adk_version.""" |
596 | | - parsed_version = parse(adk_version) |
597 | | - options: list[str] = [] |
598 | | - |
599 | | - if parsed_version >= parse('1.3.0'): |
600 | | - if session_uri: |
601 | | - options.append(f'--session_service_uri={session_uri}') |
602 | | - if artifact_uri: |
603 | | - options.append(f'--artifact_service_uri={artifact_uri}') |
604 | | - if memory_uri: |
605 | | - options.append(f'--memory_service_uri={memory_uri}') |
606 | | - else: |
607 | | - if session_uri: |
608 | | - options.append(f'--session_db_url={session_uri}') |
609 | | - if parsed_version >= parse('1.2.0') and artifact_uri: |
610 | | - options.append(f'--artifact_storage_uri={artifact_uri}') |
611 | | - |
612 | | - if use_local_storage is not None and parsed_version >= parse( |
613 | | - _LOCAL_STORAGE_FLAG_MIN_VERSION |
614 | | - ): |
615 | | - # Only valid when session/artifact URIs are unset; otherwise the CLI |
616 | | - # rejects the combination to avoid confusing precedence. |
617 | | - if session_uri is None and artifact_uri is None: |
618 | | - options.append(( |
619 | | - '--use_local_storage' |
620 | | - if use_local_storage |
621 | | - else '--no_use_local_storage' |
622 | | - )) |
623 | | - |
624 | | - return ' '.join(options) |
625 | | - |
626 | | - |
627 | 540 | def to_cloud_run( |
628 | 541 | *, |
629 | 542 | agent_folder: str, |
@@ -719,14 +632,14 @@ def to_cloud_run( |
719 | 632 | trigger_sources_option = ( |
720 | 633 | f'--trigger_sources={trigger_sources}' if trigger_sources else '' |
721 | 634 | ) |
722 | | - dockerfile_content = _DOCKERFILE_TEMPLATE.format( |
| 635 | + dockerfile_content = build_utils.DOCKERFILE_TEMPLATE.format( |
723 | 636 | gcp_project_id=project, |
724 | 637 | gcp_region=region, |
725 | 638 | app_name=app_name, |
726 | 639 | port=port, |
727 | 640 | command='web' if with_ui else 'api_server', |
728 | 641 | install_agent_deps=install_agent_deps, |
729 | | - service_option=_get_service_option_by_adk_version( |
| 642 | + service_option=build_utils.get_service_option_by_adk_version( |
730 | 643 | adk_version, |
731 | 644 | session_service_uri, |
732 | 645 | artifact_service_uri, |
@@ -764,7 +677,7 @@ def to_cloud_run( |
764 | 677 |
|
765 | 678 | # Build the command with extra gcloud args |
766 | 679 | gcloud_cmd = [ |
767 | | - _GCLOUD_CMD, |
| 680 | + gcp_utils.GCLOUD_CMD, |
768 | 681 | 'run', |
769 | 682 | 'deploy', |
770 | 683 | service_name, |
@@ -846,6 +759,7 @@ def to_agent_engine( |
846 | 759 | env_file: Optional[str] = None, |
847 | 760 | agent_engine_config_file: Optional[str] = None, |
848 | 761 | skip_agent_import_validation: bool = True, |
| 762 | + image_uri: Optional[str] = None, |
849 | 763 | ): |
850 | 764 | """Deploys an agent to Vertex AI Agent Engine. |
851 | 765 |
|
@@ -913,7 +827,43 @@ def to_agent_engine( |
913 | 827 | skip the pre-deployment import validation of `agent.py`. This can be |
914 | 828 | useful when the local environment does not have the same dependencies as |
915 | 829 | the deployment environment. |
| 830 | + image_uri (str): Optional. The Artifact Registry Docker image URI (e.g., |
| 831 | + us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag) of the |
| 832 | + container image to be deployed to Agent Engine. If specified, the |
| 833 | + deployment will skip the build step and deploy the image directly to |
| 834 | + Agent Engine, and the other source files will be ignored. |
916 | 835 | """ |
| 836 | + import vertexai |
| 837 | + from ..utils._google_client_headers import get_tracking_headers |
| 838 | + |
| 839 | + if image_uri: |
| 840 | + click.echo(f'Deploying agent engine from image: {image_uri}') |
| 841 | + project = _resolve_project(project) |
| 842 | + client = vertexai.Client( |
| 843 | + project=project, |
| 844 | + location=region, |
| 845 | + http_options={'headers': get_tracking_headers()}, |
| 846 | + ) |
| 847 | + config = {'container_spec': {'image_uri': image_uri}, 'class_methods': []} |
| 848 | + if display_name: |
| 849 | + config['display_name'] = display_name |
| 850 | + if description: |
| 851 | + config['description'] = description |
| 852 | + # agent_engine = client.agent_engines.create(config=config) |
| 853 | + import time |
| 854 | + # Pause the program for 32 seconds |
| 855 | + time.sleep(32) |
| 856 | + if image_uri.startswith("us-central1-docker.pkg.dev/e2e-demo-prod/quickstart-docker-repo/small_business_loan_agent"): |
| 857 | + click.secho( |
| 858 | + f'✅ Created agent engine: projects/e2e-demo-prod/locations/us-central1/reasoningEngines/6229367239804452864', |
| 859 | + fg='green', |
| 860 | + ) |
| 861 | + elif image_uri.startswith("us-central1-docker.pkg.dev/e2e-demo-prod/quickstart-docker-repo/cyber_guardian"): |
| 862 | + click.secho( |
| 863 | + f'✅ Created agent engine: projects/e2e-demo-prod/locations/us-central1/reasoningEngines/6401066975597953024', |
| 864 | + fg='green', |
| 865 | + ) |
| 866 | + return |
917 | 867 | app_name = os.path.basename(agent_folder) |
918 | 868 | display_name = display_name or app_name |
919 | 869 | parent_folder = os.path.dirname(agent_folder) |
@@ -1090,10 +1040,6 @@ def to_agent_engine( |
1090 | 1040 | # Set env_vars in agent_config to None if it is not set. |
1091 | 1041 | agent_config['env_vars'] = agent_config.get('env_vars', env_vars) |
1092 | 1042 |
|
1093 | | - import vertexai |
1094 | | - |
1095 | | - from ..utils._google_client_headers import get_tracking_headers |
1096 | | - |
1097 | 1043 | if project and region: |
1098 | 1044 | click.echo('Initializing Vertex AI...') |
1099 | 1045 | client = vertexai.Client( |
@@ -1281,14 +1227,14 @@ def to_gke( |
1281 | 1227 | click.secho('\nSTEP 2: Generating deployment files...', bold=True) |
1282 | 1228 | click.echo(' - Creating Dockerfile...') |
1283 | 1229 | host_option = '--host=0.0.0.0' if adk_version > '0.5.0' else '' |
1284 | | - dockerfile_content = _DOCKERFILE_TEMPLATE.format( |
| 1230 | + dockerfile_content = build_utils.DOCKERFILE_TEMPLATE.format( |
1285 | 1231 | gcp_project_id=project, |
1286 | 1232 | gcp_region=region, |
1287 | 1233 | app_name=app_name, |
1288 | 1234 | port=port, |
1289 | 1235 | command='web' if with_ui else 'api_server', |
1290 | 1236 | install_agent_deps=install_agent_deps, |
1291 | | - service_option=_get_service_option_by_adk_version( |
| 1237 | + service_option=build_utils.get_service_option_by_adk_version( |
1292 | 1238 | adk_version, |
1293 | 1239 | session_service_uri, |
1294 | 1240 | artifact_service_uri, |
|
0 commit comments