agent-starter-pack 0.18.2__py3-none-any.whl → 0.21.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/agents/{langgraph_base_react → adk_a2a_base}/.template/templateconfig.yaml +5 -12
- agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
- agent_starter_pack/{frontends/streamlit/frontend/style/app_markdown.py → agents/adk_a2a_base/app/__init__.py} +3 -23
- agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
- agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
- agent_starter_pack/agents/{crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → adk_a2a_base/notebooks/evaluating_adk_agent.ipynb} +163 -199
- agent_starter_pack/agents/adk_a2a_base/tests/integration/test_agent.py +58 -0
- agent_starter_pack/agents/adk_base/app/__init__.py +2 -2
- agent_starter_pack/agents/adk_base/app/agent.py +3 -0
- agent_starter_pack/agents/adk_base/notebooks/adk_app_testing.ipynb +13 -28
- agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
- agent_starter_pack/agents/adk_live/app/agent.py +3 -0
- agent_starter_pack/agents/agentic_rag/app/__init__.py +2 -2
- agent_starter_pack/agents/agentic_rag/app/agent.py +3 -0
- agent_starter_pack/agents/agentic_rag/notebooks/adk_app_testing.ipynb +13 -28
- agent_starter_pack/agents/{crewai_coding_crew → langgraph_base}/.template/templateconfig.yaml +12 -9
- agent_starter_pack/agents/langgraph_base/README.md +30 -0
- agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
- agent_starter_pack/agents/{langgraph_base_react → langgraph_base}/app/agent.py +4 -4
- agent_starter_pack/agents/{langgraph_base_react → langgraph_base}/tests/integration/test_agent.py +1 -1
- agent_starter_pack/base_template/.gitignore +4 -2
- agent_starter_pack/base_template/Makefile +110 -16
- agent_starter_pack/base_template/README.md +97 -12
- agent_starter_pack/base_template/deployment/terraform/dev/apis.tf +4 -6
- agent_starter_pack/base_template/deployment/terraform/dev/providers.tf +5 -1
- agent_starter_pack/base_template/deployment/terraform/dev/variables.tf +5 -3
- agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
- agent_starter_pack/base_template/deployment/terraform/github.tf +16 -9
- agent_starter_pack/base_template/deployment/terraform/locals.tf +7 -7
- agent_starter_pack/base_template/deployment/terraform/providers.tf +5 -1
- agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
- agent_starter_pack/base_template/deployment/terraform/storage.tf +0 -9
- agent_starter_pack/base_template/deployment/terraform/variables.tf +15 -19
- agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} +20 -22
- agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
- agent_starter_pack/base_template/pyproject.toml +5 -17
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +19 -4
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +36 -11
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +24 -5
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +44 -9
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/{utils → app_utils}/typing.py +4 -6
- agent_starter_pack/{agents/crewai_coding_crew/app/crew/config/agents.yaml → base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/__init__.py } +9 -23
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/part_converter.py +138 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/__init__.py +13 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/a2a_agent_executor.py +265 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/task_result_aggregator.py +152 -0
- agent_starter_pack/cli/commands/create.py +40 -4
- agent_starter_pack/cli/commands/enhance.py +1 -1
- agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
- agent_starter_pack/cli/main.py +2 -0
- agent_starter_pack/cli/utils/cicd.py +20 -4
- agent_starter_pack/cli/utils/template.py +257 -25
- agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +113 -16
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +2 -2
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +178 -9
- agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +193 -307
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/{utils → app_utils}/{% if cookiecutter.is_adk_live %}expose_app.py{% else %}unused_expose_app.py{% endif %} +13 -14
- agent_starter_pack/deployment_targets/cloud_run/Dockerfile +4 -1
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +85 -86
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +139 -107
- agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +228 -12
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +4 -4
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +92 -12
- agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/{server.py → fast_api_app.py} +194 -121
- agent_starter_pack/frontends/adk_live_react/frontend/package-lock.json +18 -18
- agent_starter_pack/frontends/adk_live_react/frontend/src/multimodal-live-types.ts +5 -3
- agent_starter_pack/resources/docs/adk-cheatsheet.md +198 -41
- agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
- agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
- agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +1443 -709
- agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +1058 -874
- agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +1443 -709
- agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +1058 -874
- agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +1568 -749
- agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +1123 -929
- agent_starter_pack/resources/locks/{uv-langgraph_base_react-agent_engine.lock → uv-langgraph_base-agent_engine.lock} +1714 -1689
- agent_starter_pack/resources/locks/{uv-langgraph_base_react-cloud_run.lock → uv-langgraph_base-cloud_run.lock} +1285 -2374
- agent_starter_pack/utils/watch_and_rebuild.py +1 -1
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/METADATA +3 -6
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/RECORD +89 -93
- agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
- llm.txt +4 -5
- agent_starter_pack/agents/crewai_coding_crew/README.md +0 -34
- agent_starter_pack/agents/crewai_coding_crew/app/agent.py +0 -47
- agent_starter_pack/agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
- agent_starter_pack/agents/crewai_coding_crew/app/crew/crew.py +0 -71
- agent_starter_pack/agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
- agent_starter_pack/agents/langgraph_base_react/README.md +0 -9
- agent_starter_pack/agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb +0 -1574
- agent_starter_pack/base_template/deployment/terraform/dev/log_sinks.tf +0 -69
- agent_starter_pack/base_template/deployment/terraform/log_sinks.tf +0 -79
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/utils/tracing.py +0 -155
- agent_starter_pack/cli/utils/register_gemini_enterprise.py +0 -406
- agent_starter_pack/deployment_targets/agent_engine/deployment/terraform/{% if not cookiecutter.is_adk_live %}service.tf{% else %}unused_service.tf{% endif %} +0 -82
- agent_starter_pack/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/utils/deployment.py +0 -99
- agent_starter_pack/frontends/streamlit/frontend/side_bar.py +0 -214
- agent_starter_pack/frontends/streamlit/frontend/streamlit_app.py +0 -265
- agent_starter_pack/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
- agent_starter_pack/frontends/streamlit/frontend/utils/local_chat_history.py +0 -127
- agent_starter_pack/frontends/streamlit/frontend/utils/message_editing.py +0 -59
- agent_starter_pack/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
- agent_starter_pack/frontends/streamlit/frontend/utils/stream_handler.py +0 -310
- agent_starter_pack/frontends/streamlit/frontend/utils/title_summary.py +0 -94
- agent_starter_pack/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6650
- agent_starter_pack/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -7825
- agent_starter_pack-0.18.2.dist-info/entry_points.txt +0 -3
- /agent_starter_pack/agents/{crewai_coding_crew → langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +0 -0
- /agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/{utils → app_utils}/gcs.py +0 -0
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.18.2.dist-info → agent_starter_pack-0.21.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Copyright 2025 Google LLC
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
|
|
16
|
-
"""Utility to register an Agent Engine to Gemini Enterprise."""
|
|
17
|
-
|
|
18
|
-
import argparse
|
|
19
|
-
import json
|
|
20
|
-
import os
|
|
21
|
-
import sys
|
|
22
|
-
from pathlib import Path
|
|
23
|
-
|
|
24
|
-
import requests
|
|
25
|
-
import vertexai
|
|
26
|
-
from google.auth import default
|
|
27
|
-
from google.auth.transport.requests import Request as GoogleAuthRequest
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def get_agent_engine_id(
|
|
31
|
-
agent_engine_id: str | None, metadata_file: str = "deployment_metadata.json"
|
|
32
|
-
) -> str:
|
|
33
|
-
"""Get the agent engine ID from parameter or deployment metadata.
|
|
34
|
-
|
|
35
|
-
Args:
|
|
36
|
-
agent_engine_id: Optional agent engine resource name
|
|
37
|
-
metadata_file: Path to deployment metadata JSON file
|
|
38
|
-
|
|
39
|
-
Returns:
|
|
40
|
-
The agent engine resource name
|
|
41
|
-
|
|
42
|
-
Raises:
|
|
43
|
-
ValueError: If agent_engine_id is not provided and metadata file doesn't exist
|
|
44
|
-
"""
|
|
45
|
-
if agent_engine_id:
|
|
46
|
-
return agent_engine_id
|
|
47
|
-
|
|
48
|
-
# Try to read from deployment_metadata.json
|
|
49
|
-
metadata_path = Path(metadata_file)
|
|
50
|
-
if not metadata_path.exists():
|
|
51
|
-
raise ValueError(
|
|
52
|
-
f"No agent engine ID provided and {metadata_file} not found. "
|
|
53
|
-
"Please provide --agent-engine-id or deploy your agent first."
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
with open(metadata_path) as f:
|
|
57
|
-
metadata = json.load(f)
|
|
58
|
-
return metadata["remote_agent_engine_id"]
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def get_access_token() -> str:
|
|
62
|
-
"""Get Google Cloud access token.
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
Access token string
|
|
66
|
-
|
|
67
|
-
Raises:
|
|
68
|
-
SystemExit: If authentication fails
|
|
69
|
-
"""
|
|
70
|
-
try:
|
|
71
|
-
credentials, _ = default()
|
|
72
|
-
auth_req = GoogleAuthRequest()
|
|
73
|
-
credentials.refresh(auth_req)
|
|
74
|
-
return credentials.token
|
|
75
|
-
except Exception as e:
|
|
76
|
-
print(f"Error getting access token: {e}", file=sys.stderr)
|
|
77
|
-
print(
|
|
78
|
-
"Please ensure you are authenticated with 'gcloud auth application-default login'",
|
|
79
|
-
file=sys.stderr,
|
|
80
|
-
)
|
|
81
|
-
raise RuntimeError("Failed to get access token") from e
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def get_agent_engine_metadata(agent_engine_id: str) -> tuple[str | None, str | None]:
|
|
85
|
-
"""Fetch display_name and description from deployed Agent Engine.
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
agent_engine_id: Agent Engine resource name
|
|
89
|
-
|
|
90
|
-
Returns:
|
|
91
|
-
Tuple of (display_name, description) - either can be None if not found
|
|
92
|
-
"""
|
|
93
|
-
parts = agent_engine_id.split("/")
|
|
94
|
-
if len(parts) < 6:
|
|
95
|
-
return None, None
|
|
96
|
-
|
|
97
|
-
project_id = parts[1]
|
|
98
|
-
location = parts[3]
|
|
99
|
-
|
|
100
|
-
try:
|
|
101
|
-
client = vertexai.Client(project=project_id, location=location)
|
|
102
|
-
agent_engine = client.agent_engines.get(name=agent_engine_id)
|
|
103
|
-
|
|
104
|
-
display_name = getattr(agent_engine.api_resource, "display_name", None)
|
|
105
|
-
description = getattr(agent_engine.api_resource, "description", None)
|
|
106
|
-
|
|
107
|
-
return display_name, description
|
|
108
|
-
except Exception as e:
|
|
109
|
-
print(
|
|
110
|
-
f"Warning: Could not fetch metadata from Agent Engine: {e}", file=sys.stderr
|
|
111
|
-
)
|
|
112
|
-
return None, None
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def register_agent(
|
|
116
|
-
agent_engine_id: str,
|
|
117
|
-
gemini_enterprise_app_id: str,
|
|
118
|
-
display_name: str,
|
|
119
|
-
description: str,
|
|
120
|
-
tool_description: str,
|
|
121
|
-
project_id: str | None = None,
|
|
122
|
-
authorization_id: str | None = None,
|
|
123
|
-
) -> dict:
|
|
124
|
-
"""Register an agent engine to Gemini Enterprise.
|
|
125
|
-
|
|
126
|
-
This function attempts to create a new agent registration. If the agent is already
|
|
127
|
-
registered (same reasoning engine), it will automatically update the existing
|
|
128
|
-
registration instead.
|
|
129
|
-
|
|
130
|
-
Args:
|
|
131
|
-
agent_engine_id: Agent engine resource name (e.g., projects/.../reasoningEngines/...)
|
|
132
|
-
gemini_enterprise_app_id: Full Gemini Enterprise app resource name
|
|
133
|
-
(e.g., projects/{project_number}/locations/{location}/collections/{collection}/engines/{engine_id})
|
|
134
|
-
display_name: Display name for the agent in Gemini Enterprise
|
|
135
|
-
description: Description of the agent
|
|
136
|
-
tool_description: Description of what the tool does
|
|
137
|
-
project_id: Optional GCP project ID for billing (extracted from agent_engine_id if not provided)
|
|
138
|
-
authorization_id: Optional OAuth authorization ID
|
|
139
|
-
(e.g., projects/{project_number}/locations/global/authorizations/{auth_id})
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
API response as dictionary
|
|
143
|
-
|
|
144
|
-
Raises:
|
|
145
|
-
requests.HTTPError: If the API request fails
|
|
146
|
-
ValueError: If gemini_enterprise_app_id format is invalid
|
|
147
|
-
"""
|
|
148
|
-
# Parse Gemini Enterprise app resource name
|
|
149
|
-
# Format: projects/{project_number}/locations/{location}/collections/{collection}/engines/{engine_id}
|
|
150
|
-
parts = gemini_enterprise_app_id.split("/")
|
|
151
|
-
if (
|
|
152
|
-
len(parts) != 8
|
|
153
|
-
or parts[0] != "projects"
|
|
154
|
-
or parts[2] != "locations"
|
|
155
|
-
or parts[4] != "collections"
|
|
156
|
-
or parts[6] != "engines"
|
|
157
|
-
):
|
|
158
|
-
raise ValueError(
|
|
159
|
-
f"Invalid GEMINI_ENTERPRISE_APP_ID format. Expected: "
|
|
160
|
-
f"projects/{{project_number}}/locations/{{location}}/collections/{{collection}}/engines/{{engine_id}}, "
|
|
161
|
-
f"got: {gemini_enterprise_app_id}"
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
project_number = parts[1]
|
|
165
|
-
as_location = parts[3]
|
|
166
|
-
collection = parts[5]
|
|
167
|
-
engine_id = parts[7]
|
|
168
|
-
|
|
169
|
-
# Use project from agent engine if not explicitly provided (for billing header)
|
|
170
|
-
if not project_id:
|
|
171
|
-
# Extract from agent_engine_id: projects/{project}/locations/{location}/reasoningEngines/{id}
|
|
172
|
-
agent_parts = agent_engine_id.split("/")
|
|
173
|
-
if len(agent_parts) > 1 and agent_parts[0] == "projects":
|
|
174
|
-
project_id = agent_parts[1]
|
|
175
|
-
else:
|
|
176
|
-
# Fallback to the project number from the Gemini Enterprise App ID.
|
|
177
|
-
project_id = project_number
|
|
178
|
-
|
|
179
|
-
# Get access token
|
|
180
|
-
access_token = get_access_token()
|
|
181
|
-
|
|
182
|
-
# Build API endpoint
|
|
183
|
-
url = (
|
|
184
|
-
f"https://discoveryengine.googleapis.com/v1alpha/projects/{project_number}/"
|
|
185
|
-
f"locations/{as_location}/collections/{collection}/engines/{engine_id}/"
|
|
186
|
-
"assistants/default_assistant/agents"
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
# Request headers
|
|
190
|
-
headers = {
|
|
191
|
-
"Authorization": f"Bearer {access_token}",
|
|
192
|
-
"Content-Type": "application/json",
|
|
193
|
-
"x-goog-user-project": project_id,
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
# Request body
|
|
197
|
-
adk_agent_definition: dict = {
|
|
198
|
-
"tool_settings": {"tool_description": tool_description},
|
|
199
|
-
"provisioned_reasoning_engine": {"reasoningEngine": agent_engine_id},
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
# Add OAuth authorization if provided
|
|
203
|
-
if authorization_id:
|
|
204
|
-
adk_agent_definition["authorizations"] = [authorization_id]
|
|
205
|
-
|
|
206
|
-
payload = {
|
|
207
|
-
"displayName": display_name,
|
|
208
|
-
"description": description,
|
|
209
|
-
"icon": {
|
|
210
|
-
"uri": "https://fonts.gstatic.com/s/i/short-term/release/googlesymbols/smart_toy/default/24px.svg"
|
|
211
|
-
},
|
|
212
|
-
"adk_agent_definition": adk_agent_definition,
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
print("Registering agent to Gemini Enterprise...")
|
|
216
|
-
print(f" Agent Engine: {agent_engine_id}")
|
|
217
|
-
print(f" Gemini Enterprise App: {gemini_enterprise_app_id}")
|
|
218
|
-
print(f" Display Name: {display_name}")
|
|
219
|
-
print(f" API Endpoint: {url}")
|
|
220
|
-
|
|
221
|
-
try:
|
|
222
|
-
# Try to create a new registration first
|
|
223
|
-
response = requests.post(url, headers=headers, json=payload, timeout=30)
|
|
224
|
-
response.raise_for_status()
|
|
225
|
-
|
|
226
|
-
result = response.json()
|
|
227
|
-
print("\n✅ Successfully registered agent to Gemini Enterprise!")
|
|
228
|
-
print(f" Agent Name: {result.get('name', 'N/A')}")
|
|
229
|
-
return result
|
|
230
|
-
|
|
231
|
-
except requests.exceptions.HTTPError as http_err:
|
|
232
|
-
# Check if the error is because the agent already exists
|
|
233
|
-
if response.status_code in (400, 409):
|
|
234
|
-
try:
|
|
235
|
-
error_data = response.json()
|
|
236
|
-
error_message = error_data.get("error", {}).get("message", "")
|
|
237
|
-
|
|
238
|
-
# Check if error indicates the agent already exists
|
|
239
|
-
if (
|
|
240
|
-
"already exists" in error_message.lower()
|
|
241
|
-
or "duplicate" in error_message.lower()
|
|
242
|
-
):
|
|
243
|
-
print(
|
|
244
|
-
"\n⚠️ Agent already registered. Updating existing registration..."
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
# For update, we need to use the specific agent resource name
|
|
248
|
-
# The agent name should be in the error or we can construct it
|
|
249
|
-
# Format: {url}/{agent_id} but we need to find existing agent first
|
|
250
|
-
|
|
251
|
-
# List existing agents to find the one for this reasoning engine
|
|
252
|
-
list_response = requests.get(url, headers=headers, timeout=30)
|
|
253
|
-
list_response.raise_for_status()
|
|
254
|
-
agents_list = list_response.json().get("agents", [])
|
|
255
|
-
|
|
256
|
-
# Find the agent that matches our reasoning engine
|
|
257
|
-
existing_agent = None
|
|
258
|
-
for agent in agents_list:
|
|
259
|
-
re_name = (
|
|
260
|
-
agent.get("adk_agent_definition", {})
|
|
261
|
-
.get("provisioned_reasoning_engine", {})
|
|
262
|
-
.get("reasoningEngine", "")
|
|
263
|
-
)
|
|
264
|
-
if re_name == agent_engine_id:
|
|
265
|
-
existing_agent = agent
|
|
266
|
-
break
|
|
267
|
-
|
|
268
|
-
if existing_agent:
|
|
269
|
-
agent_name = existing_agent.get("name")
|
|
270
|
-
update_url = f"https://discoveryengine.googleapis.com/v1alpha/{agent_name}"
|
|
271
|
-
|
|
272
|
-
print(f" Updating agent: {agent_name}")
|
|
273
|
-
|
|
274
|
-
# PATCH request to update
|
|
275
|
-
update_response = requests.patch(
|
|
276
|
-
update_url, headers=headers, json=payload, timeout=30
|
|
277
|
-
)
|
|
278
|
-
update_response.raise_for_status()
|
|
279
|
-
|
|
280
|
-
result = update_response.json()
|
|
281
|
-
print(
|
|
282
|
-
"\n✅ Successfully updated agent registration in Gemini Enterprise!"
|
|
283
|
-
)
|
|
284
|
-
print(f" Agent Name: {result.get('name', 'N/A')}")
|
|
285
|
-
return result
|
|
286
|
-
else:
|
|
287
|
-
print(
|
|
288
|
-
"\n❌ Could not find existing agent to update",
|
|
289
|
-
file=sys.stderr,
|
|
290
|
-
)
|
|
291
|
-
raise
|
|
292
|
-
except (ValueError, KeyError):
|
|
293
|
-
# Failed to parse error response, raise original error
|
|
294
|
-
pass
|
|
295
|
-
|
|
296
|
-
# If not an "already exists" error, or update failed, raise the original error
|
|
297
|
-
print(f"\n❌ HTTP error occurred: {http_err}", file=sys.stderr)
|
|
298
|
-
print(f" Response: {response.text}", file=sys.stderr)
|
|
299
|
-
raise
|
|
300
|
-
except requests.exceptions.RequestException as req_err:
|
|
301
|
-
print(f"\n❌ Request error occurred: {req_err}", file=sys.stderr)
|
|
302
|
-
raise
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def main() -> None:
|
|
306
|
-
"""Main entry point for CLI."""
|
|
307
|
-
parser = argparse.ArgumentParser(
|
|
308
|
-
description="Register an Agent Engine to Gemini Enterprise"
|
|
309
|
-
)
|
|
310
|
-
parser.add_argument(
|
|
311
|
-
"--agent-engine-id",
|
|
312
|
-
help="Agent Engine resource name (e.g., projects/.../reasoningEngines/...). "
|
|
313
|
-
"If not provided, reads from deployment_metadata.json",
|
|
314
|
-
)
|
|
315
|
-
parser.add_argument(
|
|
316
|
-
"--metadata-file",
|
|
317
|
-
default="deployment_metadata.json",
|
|
318
|
-
help="Path to deployment metadata file (default: deployment_metadata.json)",
|
|
319
|
-
)
|
|
320
|
-
parser.add_argument(
|
|
321
|
-
"--gemini-enterprise-app-id",
|
|
322
|
-
help="Gemini Enterprise app full resource name "
|
|
323
|
-
"(e.g., projects/{project_number}/locations/{location}/collections/{collection}/engines/{engine_id}). "
|
|
324
|
-
"Can also be set via GEMINI_ENTERPRISE_APP_ID env var",
|
|
325
|
-
)
|
|
326
|
-
parser.add_argument(
|
|
327
|
-
"--display-name",
|
|
328
|
-
help="Display name for the agent. Can also be set via GEMINI_DISPLAY_NAME env var",
|
|
329
|
-
)
|
|
330
|
-
parser.add_argument(
|
|
331
|
-
"--description",
|
|
332
|
-
help="Description of the agent. Can also be set via GEMINI_DESCRIPTION env var",
|
|
333
|
-
)
|
|
334
|
-
parser.add_argument(
|
|
335
|
-
"--tool-description",
|
|
336
|
-
help="Description of what the tool does. Can also be set via GEMINI_TOOL_DESCRIPTION env var",
|
|
337
|
-
)
|
|
338
|
-
parser.add_argument(
|
|
339
|
-
"--project-id",
|
|
340
|
-
help="GCP project ID (extracted from agent-engine-id if not provided). "
|
|
341
|
-
"Can also be set via GOOGLE_CLOUD_PROJECT env var",
|
|
342
|
-
)
|
|
343
|
-
parser.add_argument(
|
|
344
|
-
"--authorization-id",
|
|
345
|
-
help="OAuth authorization resource name "
|
|
346
|
-
"(e.g., projects/{project_number}/locations/global/authorizations/{auth_id}). "
|
|
347
|
-
"Can also be set via GEMINI_AUTHORIZATION_ID env var",
|
|
348
|
-
)
|
|
349
|
-
|
|
350
|
-
args = parser.parse_args()
|
|
351
|
-
|
|
352
|
-
# Get agent engine ID
|
|
353
|
-
try:
|
|
354
|
-
agent_engine_id = get_agent_engine_id(args.agent_engine_id, args.metadata_file)
|
|
355
|
-
except ValueError as e:
|
|
356
|
-
print(f"Error: {e}", file=sys.stderr)
|
|
357
|
-
sys.exit(1)
|
|
358
|
-
|
|
359
|
-
# Auto-detect display_name and description from Agent Engine
|
|
360
|
-
auto_display_name, auto_description = get_agent_engine_metadata(agent_engine_id)
|
|
361
|
-
|
|
362
|
-
gemini_enterprise_app_id = args.gemini_enterprise_app_id or os.getenv(
|
|
363
|
-
"GEMINI_ENTERPRISE_APP_ID"
|
|
364
|
-
)
|
|
365
|
-
if not gemini_enterprise_app_id:
|
|
366
|
-
print(
|
|
367
|
-
"Error: --gemini-enterprise-app-id or GEMINI_ENTERPRISE_APP_ID env var required",
|
|
368
|
-
file=sys.stderr,
|
|
369
|
-
)
|
|
370
|
-
sys.exit(1)
|
|
371
|
-
|
|
372
|
-
display_name = (
|
|
373
|
-
args.display_name
|
|
374
|
-
or os.getenv("GEMINI_DISPLAY_NAME")
|
|
375
|
-
or auto_display_name
|
|
376
|
-
or "My Agent"
|
|
377
|
-
)
|
|
378
|
-
description = (
|
|
379
|
-
args.description
|
|
380
|
-
or os.getenv("GEMINI_DESCRIPTION")
|
|
381
|
-
or auto_description
|
|
382
|
-
or "AI Agent"
|
|
383
|
-
)
|
|
384
|
-
tool_description = (
|
|
385
|
-
args.tool_description or os.getenv("GEMINI_TOOL_DESCRIPTION") or description
|
|
386
|
-
)
|
|
387
|
-
project_id = args.project_id or os.getenv("GOOGLE_CLOUD_PROJECT")
|
|
388
|
-
authorization_id = args.authorization_id or os.getenv("GEMINI_AUTHORIZATION_ID")
|
|
389
|
-
|
|
390
|
-
try:
|
|
391
|
-
register_agent(
|
|
392
|
-
agent_engine_id=agent_engine_id,
|
|
393
|
-
gemini_enterprise_app_id=gemini_enterprise_app_id,
|
|
394
|
-
display_name=display_name,
|
|
395
|
-
description=description,
|
|
396
|
-
tool_description=tool_description,
|
|
397
|
-
project_id=project_id,
|
|
398
|
-
authorization_id=authorization_id,
|
|
399
|
-
)
|
|
400
|
-
except Exception as e:
|
|
401
|
-
print(f"Error during registration: {e}", file=sys.stderr)
|
|
402
|
-
sys.exit(1)
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
if __name__ == "__main__":
|
|
406
|
-
main()
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Copyright 2025 Google LLC
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
# Get project information to access the project number
|
|
16
|
-
data "google_project" "project" {
|
|
17
|
-
for_each = local.deploy_project_ids
|
|
18
|
-
|
|
19
|
-
project_id = local.deploy_project_ids[each.key]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
resource "google_vertex_ai_reasoning_engine" "app_staging" {
|
|
23
|
-
display_name = var.project_name
|
|
24
|
-
description = "Agent deployed via Terraform"
|
|
25
|
-
region = var.region
|
|
26
|
-
project = var.staging_project_id
|
|
27
|
-
|
|
28
|
-
spec {
|
|
29
|
-
service_account = google_service_account.app_sa["staging"].email
|
|
30
|
-
|
|
31
|
-
package_spec {
|
|
32
|
-
# IMPORTANT: This Python version must match the version used in CI/CD pipelines
|
|
33
|
-
# for pickling compatibility. Mismatched versions will cause deserialization errors.
|
|
34
|
-
python_version = "3.12"
|
|
35
|
-
pickle_object_gcs_uri = "gs://agent-starter-pack/dummy/agent_engine.pkl"
|
|
36
|
-
dependency_files_gcs_uri = "gs://agent-starter-pack/dummy/dependencies.tar.gz"
|
|
37
|
-
requirements_gcs_uri = "gs://agent-starter-pack/dummy/requirements.txt"
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
# This lifecycle block prevents Terraform from overwriting the spec when it's
|
|
42
|
-
# updated by Agent Engine deployments outside of Terraform (e.g., via CI/CD pipelines)
|
|
43
|
-
lifecycle {
|
|
44
|
-
ignore_changes = [
|
|
45
|
-
spec,
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
# Make dependencies conditional to avoid errors.
|
|
50
|
-
depends_on = [google_project_service.deploy_project_services]
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
resource "google_vertex_ai_reasoning_engine" "app_prod" {
|
|
54
|
-
display_name = var.project_name
|
|
55
|
-
description = "Agent deployed via Terraform"
|
|
56
|
-
region = var.region
|
|
57
|
-
project = var.prod_project_id
|
|
58
|
-
|
|
59
|
-
spec {
|
|
60
|
-
service_account = google_service_account.app_sa["prod"].email
|
|
61
|
-
|
|
62
|
-
package_spec {
|
|
63
|
-
# IMPORTANT: This Python version must match the version used in CI/CD pipelines
|
|
64
|
-
# for pickling compatibility. Mismatched versions will cause deserialization errors.
|
|
65
|
-
python_version = "3.12"
|
|
66
|
-
pickle_object_gcs_uri = "gs://agent-starter-pack/dummy/agent_engine.pkl"
|
|
67
|
-
dependency_files_gcs_uri = "gs://agent-starter-pack/dummy/dependencies.tar.gz"
|
|
68
|
-
requirements_gcs_uri = "gs://agent-starter-pack/dummy/requirements.txt"
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
# This lifecycle block prevents Terraform from overwriting the spec when it's
|
|
73
|
-
# updated by Agent Engine deployments outside of Terraform (e.g., via CI/CD pipelines)
|
|
74
|
-
lifecycle {
|
|
75
|
-
ignore_changes = [
|
|
76
|
-
spec,
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
# Make dependencies conditional to avoid errors.
|
|
81
|
-
depends_on = [google_project_service.deploy_project_services]
|
|
82
|
-
}
|