|
27 | 27 | """ |
28 | 28 | from __future__ import annotations |
29 | 29 |
|
| 30 | +# truststore must be injected BEFORE any HTTPS-using import (vertexai, |
| 31 | +# google-auth, requests, etc.) so all SSL goes through the Windows trust |
| 32 | +# store. Required on NTU's network where TLS inspection injects a |
| 33 | +# corporate root CA that's not in certifi's bundle. |
| 34 | +try: |
| 35 | + import truststore # type: ignore |
| 36 | + truststore.inject_into_ssl() |
| 37 | +except ImportError: |
| 38 | + # truststore is optional — required only when running against a |
| 39 | + # network that does TLS inspection (e.g., NTU). On other networks |
| 40 | + # certifi handles validation fine. |
| 41 | + pass |
| 42 | + |
30 | 43 | import argparse |
31 | 44 | import importlib |
32 | 45 | import os |
|
43 | 56 | from vertexai.preview.reasoning_engines.templates.a2a import create_agent_card |
44 | 57 |
|
45 | 58 | PROJECT = "gcp-cits-ccat-poc-d4d2" |
| 59 | +APPSPOT_SA = f"{PROJECT}@appspot.gserviceaccount.com" |
| 60 | + |
| 61 | +# Env vars auto-forwarded into the deployed engine's runtime container if |
| 62 | +# present in the deploy shell. Lifted from main()'s body to a module |
| 63 | +# constant so tests can import + assert against it (W9.2 §6.3.5). |
| 64 | +AUTO_FORWARD_ENV_VARS = ( |
| 65 | + # gahmen-mcp toolset (level_4_agent's data_fetcher_agent reads at import). |
| 66 | + "SMITHERY_API_KEY", |
| 67 | + "SMITHERY_GAHMEN_URL", |
| 68 | + # Per-Level A2A peer routing (orchestrator + level_4 consume these). |
| 69 | + # All Levels live in us-central1 post-W9.2 (was asia-southeast1). |
| 70 | + "LEVEL_1_A2A_ENGINE_ID", "LEVEL_1_A2A_REGION", |
| 71 | + "LEVEL_2_A2A_ENGINE_ID", "LEVEL_2_A2A_REGION", |
| 72 | + "LEVEL_2B_A2A_ENGINE_ID", "LEVEL_2B_A2A_REGION", |
| 73 | + "LEVEL_3_A2A_ENGINE_ID", "LEVEL_3_A2A_REGION", |
| 74 | + "LEVEL_4_A2A_ENGINE_ID", "LEVEL_4_A2A_REGION", |
| 75 | + # Generic project / region overrides (orchestrator's remote_tools reads |
| 76 | + # LEVEL_REGION as the cross-Level default). |
| 77 | + "LEVEL_PROJECT_NUMBER", |
| 78 | + "LEVEL_REGION", |
| 79 | +) |
46 | 80 |
|
47 | 81 |
|
48 | 82 | def _executor_builder(root_agent): |
@@ -71,7 +105,19 @@ def main() -> None: |
71 | 105 | parser = argparse.ArgumentParser() |
72 | 106 | parser.add_argument("module", help="Agent package, e.g. level_1_agent") |
73 | 107 | parser.add_argument("--display", required=True, help='Display name, e.g. "Level 1 (A2A)"') |
74 | | - parser.add_argument("--region", default="asia-southeast1") |
| 108 | + # W9.2 default: us-central1 (Pro 2.5 lives here; was asia-southeast1). |
| 109 | + parser.add_argument("--region", default="us-central1") |
| 110 | + parser.add_argument( |
| 111 | + "--service_account", |
| 112 | + default=APPSPOT_SA, |
| 113 | + help=( |
| 114 | + "Runtime SA for the deployed engine. Default: appspot SA " |
| 115 | + "(the only enabled SA on this project with roles/editor). " |
| 116 | + "Without this, Vertex assigns the default Reasoning Engine " |
| 117 | + "Service Agent — which lacks aiplatform.user, so any " |
| 118 | + "engine→engine agent_engines.get() call 403s. See W9.2 plan §3." |
| 119 | + ), |
| 120 | + ) |
75 | 121 | parser.add_argument( |
76 | 122 | "--description", |
77 | 123 | default="ADK agent exposed via A2A on Vertex Agent Engine.", |
@@ -160,40 +206,27 @@ def main() -> None: |
160 | 206 | "google-adk[a2a]>=2.0.0b1,<3.0.0", |
161 | 207 | ] |
162 | 208 |
|
163 | | - # Auto-forward env vars that the agent might need at runtime. |
164 | | - # SMITHERY_API_KEY — gahmen-mcp toolset gate (level_4_agent's |
165 | | - # data_fetcher_agent reads it at import time). |
166 | | - # SMITHERY_GAHMEN_URL — override for the Smithery server URL. |
167 | | - # LEVEL_1_A2A_* — Level 1 peer-A2A target for level_4_agent's |
168 | | - # consult_level_1 tool. The defaults baked |
169 | | - # into remote_tools.py work for the canonical |
170 | | - # asia-southeast1 Phase 7 deploy; override |
171 | | - # via these env vars if Level 1 has been |
172 | | - # redeployed to a new ID/region. |
173 | | - # If the deploy shell has any of these set, bake them into the |
174 | | - # deployed engine's container. Anything not set falls back to the |
175 | | - # in-code defaults (or the agent runs without that capability). |
| 209 | + # Auto-forward env vars that the agent might need at runtime. Source of |
| 210 | + # truth is AUTO_FORWARD_ENV_VARS at module top — single place to add new |
| 211 | + # ones. Anything not set in the deploy shell falls back to the in-code |
| 212 | + # defaults (or the agent runs without that capability). |
176 | 213 | env_vars: dict[str, str] = {} |
177 | | - for name in ( |
178 | | - "SMITHERY_API_KEY", |
179 | | - "SMITHERY_GAHMEN_URL", |
180 | | - "LEVEL_1_A2A_ENGINE_ID", |
181 | | - "LEVEL_1_A2A_REGION", |
182 | | - "LEVEL_1_A2A_PROJECT_NUMBER", |
183 | | - ): |
| 214 | + for name in AUTO_FORWARD_ENV_VARS: |
184 | 215 | value = os.environ.get(name) |
185 | 216 | if value: |
186 | 217 | env_vars[name] = value |
187 | 218 | if env_vars: |
188 | 219 | print(f"Forwarding {len(env_vars)} env var(s) to engine: {sorted(env_vars)}") |
189 | 220 |
|
190 | 221 | print(f"Deploying {args.module} to {args.region} as {args.display!r} ...") |
| 222 | + print(f"Runtime SA: {args.service_account}") |
191 | 223 | remote = agent_engines.create( |
192 | 224 | agent_engine=a2a_app, |
193 | 225 | requirements=requirements, |
194 | 226 | extra_packages=[args.module], # uploads e.g. ./level_1_agent |
195 | 227 | display_name=args.display, |
196 | 228 | env_vars=env_vars or None, |
| 229 | + service_account=args.service_account, |
197 | 230 | ) |
198 | 231 | print(f"\n✅ Deployed: {remote.resource_name}") |
199 | 232 | print( |
|
0 commit comments