agent-starter-pack 0.7.1__py3-none-any.whl → 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agent_starter_pack-0.7.1.dist-info → agent_starter_pack-0.9.0.dist-info}/METADATA +7 -6
- {agent_starter_pack-0.7.1.dist-info → agent_starter_pack-0.9.0.dist-info}/RECORD +63 -59
- agents/README.md +7 -0
- agents/adk_base/{template/.templateconfig.yaml → .template/templateconfig.yaml} +3 -1
- agents/adk_base/notebooks/adk_app_testing.ipynb +8 -6
- agents/adk_gemini_fullstack/{template/.templateconfig.yaml → .template/templateconfig.yaml} +3 -2
- agents/adk_gemini_fullstack/notebooks/adk_app_testing.ipynb +8 -6
- agents/agentic_rag/{template/.templateconfig.yaml → .template/templateconfig.yaml} +2 -1
- agents/agentic_rag/notebooks/adk_app_testing.ipynb +8 -6
- agents/crewai_coding_crew/{template/.templateconfig.yaml → .template/templateconfig.yaml} +1 -1
- llm.txt +7 -0
- src/base_template/Makefile +5 -1
- src/base_template/README.md +2 -2
- src/base_template/deployment/cd/deploy-to-prod.yaml +1 -16
- src/base_template/deployment/cd/staging.yaml +4 -19
- src/base_template/deployment/terraform/apis.tf +2 -2
- src/base_template/deployment/terraform/build_triggers.tf +5 -5
- src/base_template/deployment/terraform/dev/apis.tf +8 -1
- src/base_template/deployment/terraform/dev/variables.tf +3 -1
- src/base_template/deployment/terraform/iam.tf +8 -8
- src/base_template/deployment/terraform/locals.tf +9 -2
- src/base_template/deployment/terraform/log_sinks.tf +2 -2
- src/base_template/deployment/terraform/service_accounts.tf +3 -3
- src/base_template/deployment/terraform/storage.tf +7 -7
- src/base_template/deployment/terraform/variables.tf +3 -0
- src/base_template/pyproject.toml +4 -3
- src/cli/commands/create.py +191 -41
- src/cli/commands/list.py +158 -0
- src/cli/commands/setup_cicd.py +2 -2
- src/cli/main.py +2 -0
- src/cli/utils/cicd.py +2 -2
- src/cli/utils/remote_template.py +254 -0
- src/cli/utils/template.py +134 -25
- src/deployment_targets/agent_engine/app/agent_engine_app.py +7 -7
- src/deployment_targets/agent_engine/tests/load_test/README.md +1 -6
- src/deployment_targets/agent_engine/tests/load_test/load_test.py +13 -3
- src/deployment_targets/cloud_run/Dockerfile +3 -0
- src/deployment_targets/cloud_run/app/server.py +18 -0
- src/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +231 -0
- src/deployment_targets/cloud_run/deployment/terraform/service.tf +360 -0
- src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +8 -5
- src/deployment_targets/cloud_run/tests/load_test/README.md +2 -2
- src/deployment_targets/cloud_run/tests/load_test/load_test.py +21 -17
- src/frontends/adk_gemini_fullstack/frontend/src/App.tsx +2 -3
- src/resources/docs/adk-cheatsheet.md +1 -1
- src/resources/locks/uv-adk_base-agent_engine.lock +873 -236
- src/resources/locks/uv-adk_base-cloud_run.lock +1169 -283
- src/resources/locks/uv-adk_gemini_fullstack-agent_engine.lock +873 -236
- src/resources/locks/uv-adk_gemini_fullstack-cloud_run.lock +1169 -283
- src/resources/locks/uv-agentic_rag-agent_engine.lock +508 -373
- src/resources/locks/uv-agentic_rag-cloud_run.lock +668 -469
- src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +582 -587
- src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +791 -733
- src/resources/locks/uv-langgraph_base_react-agent_engine.lock +587 -478
- src/resources/locks/uv-langgraph_base_react-cloud_run.lock +799 -627
- src/resources/locks/uv-live_api-cloud_run.lock +803 -603
- src/resources/setup_cicd/github.tf +2 -2
- src/utils/lock_utils.py +1 -1
- src/deployment_targets/cloud_run/uv.lock +0 -6952
- {agent_starter_pack-0.7.1.dist-info → agent_starter_pack-0.9.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.7.1.dist-info → agent_starter_pack-0.9.0.dist-info}/entry_points.txt +0 -0
- {agent_starter_pack-0.7.1.dist-info → agent_starter_pack-0.9.0.dist-info}/licenses/LICENSE +0 -0
- /agents/langgraph_base_react/{template/.templateconfig.yaml → .template/templateconfig.yaml} +0 -0
- /agents/live_api/{template/.templateconfig.yaml → .template/templateconfig.yaml} +0 -0
@@ -24,7 +24,14 @@ locals {
|
|
24
24
|
"bigquery.googleapis.com",
|
25
25
|
"serviceusage.googleapis.com",
|
26
26
|
"logging.googleapis.com",
|
27
|
-
"cloudtrace.googleapis.com"
|
27
|
+
"cloudtrace.googleapis.com",
|
28
|
+
{%- if "adk" in cookiecutter.tags and cookiecutter.session_type == "alloydb" %}
|
29
|
+
"compute.googleapis.com",
|
30
|
+
"servicenetworking.googleapis.com",
|
31
|
+
"alloydb.googleapis.com",
|
32
|
+
"secretmanager.googleapis.com",
|
33
|
+
"dns.googleapis.com"
|
34
|
+
{%- endif %}
|
28
35
|
]
|
29
36
|
}
|
30
37
|
|
@@ -54,6 +54,9 @@ variable "agentengine_sa_roles" {
|
|
54
54
|
{% endif %}
|
55
55
|
type = list(string)
|
56
56
|
default = [
|
57
|
+
{%- if "adk" in cookiecutter.tags and cookiecutter.session_type == "alloydb" %}
|
58
|
+
"roles/secretmanager.secretAccessor",
|
59
|
+
{%- endif %}
|
57
60
|
"roles/aiplatform.user",
|
58
61
|
"roles/discoveryengine.editor",
|
59
62
|
"roles/logging.logWriter",
|
@@ -61,7 +64,6 @@ variable "agentengine_sa_roles" {
|
|
61
64
|
"roles/storage.admin"
|
62
65
|
]
|
63
66
|
}
|
64
|
-
|
65
67
|
{% if cookiecutter.data_ingestion %}
|
66
68
|
|
67
69
|
variable "pipelines_roles" {
|
@@ -25,7 +25,7 @@ resource "google_project_iam_member" "cicd_project_roles" {
|
|
25
25
|
project = var.cicd_runner_project_id
|
26
26
|
role = each.value
|
27
27
|
member = "serviceAccount:${resource.google_service_account.cicd_runner_sa.email}"
|
28
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
28
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
29
29
|
|
30
30
|
}
|
31
31
|
|
@@ -42,7 +42,7 @@ resource "google_project_iam_member" "other_projects_roles" {
|
|
42
42
|
project = each.value.project_id
|
43
43
|
role = each.value.role
|
44
44
|
member = "serviceAccount:${resource.google_service_account.cicd_runner_sa.email}"
|
45
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
45
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
46
46
|
}
|
47
47
|
{% if cookiecutter.deployment_target == 'cloud_run' %}
|
48
48
|
# 3. Allow Cloud Run service SA to pull containers stored in the CICD project
|
@@ -52,7 +52,7 @@ resource "google_project_iam_member" "cicd_run_invoker_artifact_registry_reader"
|
|
52
52
|
|
53
53
|
role = "roles/artifactregistry.reader"
|
54
54
|
member = "serviceAccount:service-${data.google_project.projects[each.key].number}@serverless-robot-prod.iam.gserviceaccount.com"
|
55
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
55
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
56
56
|
|
57
57
|
}
|
58
58
|
|
@@ -69,7 +69,7 @@ resource "google_project_iam_member" "cloud_run_app_sa_roles" {
|
|
69
69
|
project = each.value.project
|
70
70
|
role = each.value.role
|
71
71
|
member = "serviceAccount:${google_service_account.cloud_run_app_sa[split(",", each.key)[0]].email}"
|
72
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
72
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
73
73
|
}
|
74
74
|
{% elif cookiecutter.deployment_target == 'agent_engine' %}
|
75
75
|
resource "google_project_service_identity" "vertex_sa" {
|
@@ -92,7 +92,7 @@ resource "google_project_iam_member" "vertex_ai_sa_permissions" {
|
|
92
92
|
project = each.value.project
|
93
93
|
role = each.value.role
|
94
94
|
member = "serviceAccount:service-${data.google_project.projects[split("_", each.key)[0]].number}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
|
95
|
-
depends_on = [resource.google_project_service.
|
95
|
+
depends_on = [resource.google_project_service.deploy_project_services, resource.google_project_service_identity.vertex_sa]
|
96
96
|
}
|
97
97
|
{% endif %}
|
98
98
|
|
@@ -101,14 +101,14 @@ resource "google_service_account_iam_member" "cicd_run_invoker_token_creator" {
|
|
101
101
|
service_account_id = google_service_account.cicd_runner_sa.name
|
102
102
|
role = "roles/iam.serviceAccountTokenCreator"
|
103
103
|
member = "serviceAccount:${resource.google_service_account.cicd_runner_sa.email}"
|
104
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
104
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
105
105
|
}
|
106
106
|
# Special assignment: Allow the CICD SA to impersonate himself for trigger creation
|
107
107
|
resource "google_service_account_iam_member" "cicd_run_invoker_account_user" {
|
108
108
|
service_account_id = google_service_account.cicd_runner_sa.name
|
109
109
|
role = "roles/iam.serviceAccountUser"
|
110
110
|
member = "serviceAccount:${resource.google_service_account.cicd_runner_sa.email}"
|
111
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
111
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
112
112
|
}
|
113
113
|
|
114
114
|
{%- if cookiecutter.data_ingestion %}
|
@@ -125,6 +125,6 @@ resource "google_project_iam_member" "vertexai_pipeline_sa_roles" {
|
|
125
125
|
project = each.value.project
|
126
126
|
role = each.value.role
|
127
127
|
member = "serviceAccount:${google_service_account.vertexai_pipeline_app_sa[split(",", each.key)[0]].email}"
|
128
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
128
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
129
129
|
}
|
130
130
|
{%- endif %}
|
@@ -23,7 +23,7 @@ locals {
|
|
23
23
|
"cloudtrace.googleapis.com"
|
24
24
|
]
|
25
25
|
|
26
|
-
|
26
|
+
deploy_project_services = [
|
27
27
|
"aiplatform.googleapis.com",
|
28
28
|
"run.googleapis.com",
|
29
29
|
"discoveryengine.googleapis.com",
|
@@ -32,7 +32,14 @@ locals {
|
|
32
32
|
"bigquery.googleapis.com",
|
33
33
|
"serviceusage.googleapis.com",
|
34
34
|
"logging.googleapis.com",
|
35
|
-
"cloudtrace.googleapis.com"
|
35
|
+
"cloudtrace.googleapis.com",
|
36
|
+
{%- if "adk" in cookiecutter.tags and cookiecutter.session_type == "alloydb" %}
|
37
|
+
"compute.googleapis.com",
|
38
|
+
"servicenetworking.googleapis.com",
|
39
|
+
"alloydb.googleapis.com",
|
40
|
+
"secretmanager.googleapis.com",
|
41
|
+
"dns.googleapis.com"
|
42
|
+
{%- endif %}
|
36
43
|
]
|
37
44
|
|
38
45
|
deploy_project_ids = {
|
@@ -26,7 +26,7 @@ resource "google_bigquery_dataset" "feedback_dataset" {
|
|
26
26
|
dataset_id = replace("${var.project_name}_feedback", "-", "_")
|
27
27
|
friendly_name = "${var.project_name}_feedback"
|
28
28
|
location = var.region
|
29
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
29
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
30
30
|
}
|
31
31
|
|
32
32
|
resource "google_bigquery_dataset" "telemetry_logs_dataset" {
|
@@ -35,7 +35,7 @@ resource "google_bigquery_dataset" "telemetry_logs_dataset" {
|
|
35
35
|
dataset_id = replace("${var.project_name}_telemetry", "-", "_")
|
36
36
|
friendly_name = "${var.project_name}_telemetry"
|
37
37
|
location = var.region
|
38
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
38
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
39
39
|
}
|
40
40
|
|
41
41
|
module "log_export_to_bigquery" {
|
@@ -16,7 +16,7 @@ resource "google_service_account" "cicd_runner_sa" {
|
|
16
16
|
account_id = "${var.project_name}-cb"
|
17
17
|
display_name = "CICD Runner SA"
|
18
18
|
project = var.cicd_runner_project_id
|
19
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
19
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
20
20
|
}
|
21
21
|
{% if cookiecutter.deployment_target == 'cloud_run' %}
|
22
22
|
resource "google_service_account" "cloud_run_app_sa" {
|
@@ -25,7 +25,7 @@ resource "google_service_account" "cloud_run_app_sa" {
|
|
25
25
|
account_id = "${var.project_name}-cr"
|
26
26
|
display_name = "Cloud Run Generative AI app SA"
|
27
27
|
project = each.value
|
28
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
28
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
29
29
|
}
|
30
30
|
{% endif %}
|
31
31
|
|
@@ -37,6 +37,6 @@ resource "google_service_account" "vertexai_pipeline_app_sa" {
|
|
37
37
|
account_id = "${var.project_name}-rag"
|
38
38
|
display_name = "Vertex AI Pipeline app SA"
|
39
39
|
project = each.value
|
40
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
40
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
41
41
|
}
|
42
42
|
{% endif %}
|
@@ -23,7 +23,7 @@ resource "google_storage_bucket" "bucket_load_test_results" {
|
|
23
23
|
project = var.cicd_runner_project_id
|
24
24
|
uniform_bucket_level_access = true
|
25
25
|
force_destroy = true
|
26
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
26
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
27
27
|
}
|
28
28
|
|
29
29
|
resource "google_storage_bucket" "logs_data_bucket" {
|
@@ -34,7 +34,7 @@ resource "google_storage_bucket" "logs_data_bucket" {
|
|
34
34
|
uniform_bucket_level_access = true
|
35
35
|
force_destroy = true
|
36
36
|
|
37
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
37
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
38
38
|
}
|
39
39
|
{% if cookiecutter.deployment_target == 'cloud_run' %}
|
40
40
|
resource "google_artifact_registry_repository" "repo-artifacts-genai" {
|
@@ -43,7 +43,7 @@ resource "google_artifact_registry_repository" "repo-artifacts-genai" {
|
|
43
43
|
description = "Repo for Generative AI applications"
|
44
44
|
format = "DOCKER"
|
45
45
|
project = var.cicd_runner_project_id
|
46
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
46
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
47
47
|
}
|
48
48
|
{% endif %}
|
49
49
|
|
@@ -56,7 +56,7 @@ resource "google_storage_bucket" "data_ingestion_pipeline_gcs_root" {
|
|
56
56
|
uniform_bucket_level_access = true
|
57
57
|
force_destroy = true
|
58
58
|
|
59
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
59
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
60
60
|
}
|
61
61
|
|
62
62
|
{% if cookiecutter.datastore_type == "vertex_ai_search" %}
|
@@ -71,7 +71,7 @@ resource "google_discovery_engine_data_store" "data_store_staging" {
|
|
71
71
|
solution_types = ["SOLUTION_TYPE_SEARCH"]
|
72
72
|
create_advanced_site_search = false
|
73
73
|
provider = google.staging_billing_override
|
74
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
74
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
75
75
|
}
|
76
76
|
|
77
77
|
resource "google_discovery_engine_search_engine" "search_engine_staging" {
|
@@ -97,7 +97,7 @@ resource "google_discovery_engine_data_store" "data_store_prod" {
|
|
97
97
|
solution_types = ["SOLUTION_TYPE_SEARCH"]
|
98
98
|
create_advanced_site_search = false
|
99
99
|
provider = google.prod_billing_override
|
100
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
100
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
101
101
|
}
|
102
102
|
|
103
103
|
resource "google_discovery_engine_search_engine" "search_engine_prod" {
|
@@ -122,7 +122,7 @@ resource "google_storage_bucket" "vector_search_data_bucket" {
|
|
122
122
|
uniform_bucket_level_access = true
|
123
123
|
force_destroy = true
|
124
124
|
|
125
|
-
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.
|
125
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.deploy_project_services]
|
126
126
|
}
|
127
127
|
|
128
128
|
resource "google_vertex_ai_index" "vector_search_index_staging" {
|
@@ -76,6 +76,7 @@ variable "agentengine_sa_roles" {
|
|
76
76
|
default = [
|
77
77
|
{%- if cookiecutter.deployment_target == 'cloud_run' %}
|
78
78
|
"roles/run.invoker",
|
79
|
+
"roles/secretmanager.secretAccessor",
|
79
80
|
{%- endif %}
|
80
81
|
"roles/aiplatform.user",
|
81
82
|
"roles/discoveryengine.editor",
|
@@ -84,6 +85,8 @@ variable "agentengine_sa_roles" {
|
|
84
85
|
"roles/storage.admin"
|
85
86
|
]
|
86
87
|
}
|
88
|
+
{%- if cookiecutter.deployment_target == 'cloud_run' %}
|
89
|
+
{%- endif %}
|
87
90
|
|
88
91
|
variable "cicd_roles" {
|
89
92
|
description = "List of roles to assign to the CICD runner service account in the CICD project"
|
src/base_template/pyproject.toml
CHANGED
@@ -16,11 +16,12 @@ dependencies = [
|
|
16
16
|
{%- endif %}
|
17
17
|
"google-cloud-logging~=3.11.4",
|
18
18
|
{%- if cookiecutter.deployment_target == 'cloud_run' %}
|
19
|
-
"google-cloud-aiplatform[evaluation]~=1.
|
19
|
+
"google-cloud-aiplatform[evaluation]~=1.103.0",
|
20
20
|
"fastapi~=0.115.8",
|
21
|
-
"uvicorn~=0.34.0"
|
21
|
+
"uvicorn~=0.34.0",
|
22
|
+
"psycopg2-binary>=2.9.10",
|
22
23
|
{%- elif cookiecutter.deployment_target == 'agent_engine' %}
|
23
|
-
"google-cloud-aiplatform[evaluation,agent-engines]~=1.
|
24
|
+
"google-cloud-aiplatform[evaluation,agent-engines]~=1.103.0"
|
24
25
|
{%- endif %}
|
25
26
|
]
|
26
27
|
{% if cookiecutter.deployment_target == 'cloud_run' %}
|
src/cli/commands/create.py
CHANGED
@@ -25,6 +25,13 @@ from rich.prompt import IntPrompt, Prompt
|
|
25
25
|
from ..utils.datastores import DATASTORE_TYPES
|
26
26
|
from ..utils.gcp import verify_credentials, verify_vertex_connection
|
27
27
|
from ..utils.logging import handle_cli_error
|
28
|
+
from ..utils.remote_template import (
|
29
|
+
fetch_remote_template,
|
30
|
+
get_base_template_name,
|
31
|
+
load_remote_template_config,
|
32
|
+
merge_template_configs,
|
33
|
+
parse_agent_spec,
|
34
|
+
)
|
28
35
|
from ..utils.template import (
|
29
36
|
get_available_agents,
|
30
37
|
get_template_path,
|
@@ -32,6 +39,7 @@ from ..utils.template import (
|
|
32
39
|
process_template,
|
33
40
|
prompt_datastore_selection,
|
34
41
|
prompt_deployment_target,
|
42
|
+
prompt_session_type_selection,
|
35
43
|
)
|
36
44
|
|
37
45
|
console = Console()
|
@@ -74,7 +82,11 @@ def normalize_project_name(project_name: str) -> str:
|
|
74
82
|
@click.command()
|
75
83
|
@click.pass_context
|
76
84
|
@click.argument("project_name")
|
77
|
-
@click.option(
|
85
|
+
@click.option(
|
86
|
+
"--agent",
|
87
|
+
"-a",
|
88
|
+
help="Template identifier to use. Can be a local agent name (e.g., `chat_agent`), a local path (`local@/path/to/template`), an `adk-samples` shortcut (e.g., `adk@data-science`), or a remote Git URL. Both shorthand (e.g., `github.com/org/repo/path@main`) and full URLs from your browser (e.g., `https://github.com/org/repo/tree/main/path`) are supported. Lists available local templates if omitted.",
|
89
|
+
)
|
78
90
|
@click.option(
|
79
91
|
"--deployment-target",
|
80
92
|
"-d",
|
@@ -93,6 +105,11 @@ def normalize_project_name(project_name: str) -> str:
|
|
93
105
|
type=click.Choice(DATASTORE_TYPES),
|
94
106
|
help="Type of datastore to use for data ingestion (requires --include-data-ingestion)",
|
95
107
|
)
|
108
|
+
@click.option(
|
109
|
+
"--session-type",
|
110
|
+
type=click.Choice(["in_memory", "alloydb"]),
|
111
|
+
help="Type of session storage to use",
|
112
|
+
)
|
96
113
|
@click.option("--debug", is_flag=True, help="Enable debug logging")
|
97
114
|
@click.option(
|
98
115
|
"--output-dir",
|
@@ -122,6 +139,7 @@ def create(
|
|
122
139
|
deployment_target: str | None,
|
123
140
|
include_data_ingestion: bool,
|
124
141
|
datastore: str | None,
|
142
|
+
session_type: str | None,
|
125
143
|
debug: bool,
|
126
144
|
output_dir: str | None,
|
127
145
|
auto_approve: bool,
|
@@ -131,11 +149,26 @@ def create(
|
|
131
149
|
"""Create GCP-based AI agent projects from templates."""
|
132
150
|
try:
|
133
151
|
# Display welcome banner
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
152
|
+
if agent and agent.startswith("adk@"):
|
153
|
+
console.print(
|
154
|
+
"\n=== Welcome to [link=https://github.com/google/adk-samples]google/adk-samples[/link]! ✨ ===",
|
155
|
+
style="bold blue",
|
156
|
+
)
|
157
|
+
console.print(
|
158
|
+
"Powered by ([link=https://goo.gle/agent-starter-pack]Google's Agent Starter Pack [/link])\n",
|
159
|
+
)
|
160
|
+
console.print(
|
161
|
+
"This tool will help you create an end-to-end production-ready AI agent in Google Cloud!\n"
|
162
|
+
)
|
163
|
+
else:
|
164
|
+
console.print(
|
165
|
+
"\n=== Google Cloud Agent Starter Pack :rocket:===",
|
166
|
+
style="bold blue",
|
167
|
+
)
|
168
|
+
console.print("Welcome to the Agent Starter Pack!")
|
169
|
+
console.print(
|
170
|
+
"This tool will help you create an end-to-end production-ready AI agent in Google Cloud!\n"
|
171
|
+
)
|
139
172
|
# Validate project name
|
140
173
|
if len(project_name) > 26:
|
141
174
|
console.print(
|
@@ -165,23 +198,51 @@ def create(
|
|
165
198
|
)
|
166
199
|
return
|
167
200
|
|
168
|
-
# Agent selection
|
201
|
+
# Agent selection - handle remote templates
|
169
202
|
selected_agent = None
|
203
|
+
template_source_path = None
|
204
|
+
|
170
205
|
if agent:
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
206
|
+
if agent.startswith("local@"):
|
207
|
+
path_str = agent.split("@", 1)[1]
|
208
|
+
template_source_path = pathlib.Path(path_str).resolve()
|
209
|
+
if not template_source_path.is_dir():
|
210
|
+
raise click.ClickException(
|
211
|
+
f"Local path not found or not a directory: {template_source_path}"
|
212
|
+
)
|
213
|
+
selected_agent = f"local_{template_source_path.name}"
|
214
|
+
console.print(f"Using local template: {template_source_path}")
|
175
215
|
else:
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
if
|
180
|
-
|
216
|
+
# Check if it's a remote template specification
|
217
|
+
remote_spec = parse_agent_spec(agent)
|
218
|
+
if remote_spec:
|
219
|
+
if remote_spec.is_adk_samples:
|
220
|
+
console.print(
|
221
|
+
f"> Fetching template: {remote_spec.template_path}",
|
222
|
+
style="bold blue",
|
223
|
+
)
|
224
|
+
else:
|
225
|
+
console.print(f"Fetching remote template: {agent}")
|
226
|
+
template_source_path = fetch_remote_template(remote_spec)
|
227
|
+
selected_agent = f"remote_{hash(agent)}" # Generate unique name for remote template
|
228
|
+
else:
|
229
|
+
# Handle local agent selection
|
230
|
+
agents = get_available_agents()
|
231
|
+
# First check if it's a valid agent name
|
232
|
+
if any(p["name"] == agent for p in agents.values()):
|
233
|
+
selected_agent = agent
|
181
234
|
else:
|
182
|
-
|
183
|
-
|
184
|
-
|
235
|
+
# Try numeric agent selection if input is a number
|
236
|
+
try:
|
237
|
+
agent_num = int(agent)
|
238
|
+
if agent_num in agents:
|
239
|
+
selected_agent = agents[agent_num]["name"]
|
240
|
+
else:
|
241
|
+
raise ValueError(f"Invalid agent number: {agent_num}")
|
242
|
+
except ValueError as err:
|
243
|
+
raise ValueError(
|
244
|
+
f"Invalid agent name or number: {agent}"
|
245
|
+
) from err
|
185
246
|
|
186
247
|
final_agent = (
|
187
248
|
selected_agent
|
@@ -191,13 +252,54 @@ def create(
|
|
191
252
|
if debug:
|
192
253
|
logging.debug(f"Selected agent: {agent}")
|
193
254
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
255
|
+
# Load template configuration based on whether it's remote or local
|
256
|
+
if template_source_path:
|
257
|
+
# Load remote template config
|
258
|
+
source_config = load_remote_template_config(template_source_path)
|
259
|
+
|
260
|
+
# Check if remote template has the required structure
|
261
|
+
template_config_path = (
|
262
|
+
template_source_path / ".template" / "templateconfig.yaml"
|
263
|
+
)
|
264
|
+
|
265
|
+
if not template_config_path.exists():
|
266
|
+
console.print(
|
267
|
+
"Error: Template is invalid or improperly structured.",
|
268
|
+
style="bold red",
|
269
|
+
)
|
270
|
+
console.print(
|
271
|
+
"Templates must contain a '.template/templateconfig.yaml' file.\n\n"
|
272
|
+
"Expected structure:\n"
|
273
|
+
" your-template/\n"
|
274
|
+
" └── .template/\n"
|
275
|
+
" ├── templateconfig.yaml\n"
|
276
|
+
" └── [other template files...]",
|
277
|
+
style="yellow",
|
278
|
+
)
|
279
|
+
return
|
280
|
+
|
281
|
+
# Load base template config for inheritance
|
282
|
+
base_template_name = get_base_template_name(source_config)
|
283
|
+
base_template_path = (
|
284
|
+
pathlib.Path(__file__).parent.parent.parent.parent
|
285
|
+
/ "agents"
|
286
|
+
/ base_template_name
|
287
|
+
/ ".template"
|
288
|
+
)
|
289
|
+
base_config = load_template_config(base_template_path)
|
290
|
+
|
291
|
+
# Merge configs: remote inherits from and overrides base
|
292
|
+
config = merge_template_configs(base_config, source_config)
|
293
|
+
# For remote templates, use the template/ subdirectory as the template source
|
294
|
+
template_path = template_source_path / ".template"
|
295
|
+
else:
|
296
|
+
template_path = (
|
297
|
+
pathlib.Path(__file__).parent.parent.parent.parent
|
298
|
+
/ "agents"
|
299
|
+
/ final_agent
|
300
|
+
/ ".template"
|
301
|
+
)
|
302
|
+
config = load_template_config(template_path)
|
201
303
|
# Data ingestion and datastore selection
|
202
304
|
if include_data_ingestion or datastore:
|
203
305
|
# If datastore is specified but include_data_ingestion is not, set it to True
|
@@ -224,14 +326,54 @@ def create(
|
|
224
326
|
logging.debug(f"Selected datastore type: {datastore}")
|
225
327
|
|
226
328
|
# Deployment target selection
|
329
|
+
# For remote templates, we need to use the base template name for deployment target selection
|
330
|
+
deployment_agent_name = final_agent
|
331
|
+
remote_config = None
|
332
|
+
if template_source_path:
|
333
|
+
# Use the base template name from remote config for deployment target selection
|
334
|
+
deployment_agent_name = get_base_template_name(config)
|
335
|
+
remote_config = config
|
336
|
+
|
227
337
|
final_deployment = (
|
228
338
|
deployment_target
|
229
339
|
if deployment_target
|
230
|
-
else prompt_deployment_target(
|
340
|
+
else prompt_deployment_target(
|
341
|
+
deployment_agent_name, remote_config=remote_config
|
342
|
+
)
|
231
343
|
)
|
232
344
|
if debug:
|
233
345
|
logging.debug(f"Selected deployment target: {final_deployment}")
|
234
346
|
|
347
|
+
# Session type validation and selection (only for agents that require session management)
|
348
|
+
final_session_type = session_type
|
349
|
+
|
350
|
+
# Check if agent requires session management
|
351
|
+
requires_session = config.get("settings", {}).get("requires_session", False)
|
352
|
+
|
353
|
+
if requires_session:
|
354
|
+
if final_deployment == "agent_engine" and session_type:
|
355
|
+
console.print(
|
356
|
+
"Error: --session-type cannot be used with agent_engine deployment target. "
|
357
|
+
"Agent Engine handles session management internally.",
|
358
|
+
style="bold red",
|
359
|
+
)
|
360
|
+
return
|
361
|
+
|
362
|
+
if final_deployment in ("cloud_run") and not session_type:
|
363
|
+
final_session_type = prompt_session_type_selection()
|
364
|
+
else:
|
365
|
+
# Agents that don't require session management always use in-memory sessions
|
366
|
+
final_session_type = "in_memory"
|
367
|
+
if session_type and session_type != "in_memory":
|
368
|
+
console.print(
|
369
|
+
"Warning: Session type options are only available for agents that require session management. "
|
370
|
+
"Using in-memory sessions for this agent.",
|
371
|
+
style="yellow",
|
372
|
+
)
|
373
|
+
|
374
|
+
if debug and final_session_type:
|
375
|
+
logging.debug(f"Selected session type: {final_session_type}")
|
376
|
+
|
235
377
|
# Region confirmation (if not explicitly passed)
|
236
378
|
if (
|
237
379
|
not auto_approve
|
@@ -270,7 +412,10 @@ def create(
|
|
270
412
|
)
|
271
413
|
|
272
414
|
# Process template
|
273
|
-
|
415
|
+
if not template_source_path:
|
416
|
+
template_path = get_template_path(final_agent, debug=debug)
|
417
|
+
# template_path is already set above for remote templates
|
418
|
+
|
274
419
|
if debug:
|
275
420
|
logging.debug(f"Template path: {template_path}")
|
276
421
|
logging.debug(f"Processing template for project: {project_name}")
|
@@ -282,19 +427,24 @@ def create(
|
|
282
427
|
if debug:
|
283
428
|
logging.debug(f"Output directory: {destination_dir}")
|
284
429
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
430
|
+
try:
|
431
|
+
# Process template (handles both local and remote templates)
|
432
|
+
process_template(
|
433
|
+
final_agent,
|
434
|
+
template_path,
|
435
|
+
project_name,
|
436
|
+
deployment_target=final_deployment,
|
437
|
+
include_data_ingestion=include_data_ingestion,
|
438
|
+
datastore=datastore,
|
439
|
+
session_type=final_session_type,
|
440
|
+
output_dir=destination_dir,
|
441
|
+
remote_template_path=template_source_path,
|
442
|
+
remote_config=config if template_source_path else None,
|
443
|
+
)
|
444
|
+
finally:
|
445
|
+
# Replace region in all files if a different region was specified
|
446
|
+
if region != "us-central1":
|
447
|
+
replace_region_in_files(project_path, region, debug=debug)
|
298
448
|
|
299
449
|
project_path = destination_dir / project_name
|
300
450
|
cd_path = project_path if output_dir else project_name
|