|
22 | 22 | import click |
23 | 23 |
|
24 | 24 | from ..apps.app import validate_app_name |
| 25 | +from .utils import gcp_utils |
25 | 26 |
|
26 | 27 | _INIT_PY_TEMPLATE = """\ |
27 | 28 | from . import agent |
|
61 | 62 | https://google.github.io/adk-docs/agents/models |
62 | 63 | """ |
63 | 64 |
|
| 65 | +_EXPRESS_TOS_MSG = """ |
| 66 | +Google Cloud Express Mode Terms of Service: https://cloud.google.com/terms/google-cloud-express |
| 67 | +By continuing, you agree to the Terms of Service for Vertex AI Express Mode. |
| 68 | +Would you like to proceed? (yes/no) |
| 69 | +""" |
| 70 | + |
| 71 | +_NOT_ELIGIBLE_MSG = """ |
| 72 | +You are not eligible for Express Mode. |
| 73 | +Please follow these instructions to set up a full Google Cloud project: |
| 74 | +https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-cloud-vertex-ai |
| 75 | +""" |
| 76 | + |
64 | 77 | _SUCCESS_MSG_CODE = """ |
65 | 78 | Agent created in {agent_folder}: |
66 | 79 | - .env |
67 | 80 | - __init__.py |
68 | 81 | - agent.py |
| 82 | +
|
| 83 | +⚠️ WARNING: Secrets (like GOOGLE_API_KEY) are stored in .env. |
| 84 | +Please ensure .env is added to your .gitignore to avoid committing secrets to version control. |
69 | 85 | """ |
70 | 86 |
|
71 | 87 | _SUCCESS_MSG_CONFIG = """ |
72 | 88 | Agent created in {agent_folder}: |
73 | 89 | - .env |
74 | 90 | - __init__.py |
75 | 91 | - root_agent.yaml |
| 92 | +
|
| 93 | +⚠️ WARNING: Secrets (like GOOGLE_API_KEY) are stored in .env. |
| 94 | +Please ensure .env is added to your .gitignore to avoid committing secrets to version control. |
76 | 95 | """ |
77 | 96 |
|
78 | 97 |
|
@@ -187,10 +206,10 @@ def _generate_files( |
187 | 206 |
|
188 | 207 | with open(dotenv_file_path, "w", encoding="utf-8") as f: |
189 | 208 | lines = [] |
190 | | - if google_api_key: |
191 | | - lines.append("GOOGLE_GENAI_USE_VERTEXAI=0") |
192 | | - elif google_cloud_project and google_cloud_region: |
| 209 | + if google_cloud_project and google_cloud_region: |
193 | 210 | lines.append("GOOGLE_GENAI_USE_VERTEXAI=1") |
| 211 | + elif google_api_key: |
| 212 | + lines.append("GOOGLE_GENAI_USE_VERTEXAI=0") |
194 | 213 | if google_api_key: |
195 | 214 | lines.append(f"GOOGLE_API_KEY={google_api_key}") |
196 | 215 | if google_cloud_project: |
@@ -247,18 +266,110 @@ def _prompt_to_choose_backend( |
247 | 266 | A tuple of (google_api_key, google_cloud_project, google_cloud_region). |
248 | 267 | """ |
249 | 268 | backend_choice = click.prompt( |
250 | | - "1. Google AI\n2. Vertex AI\nChoose a backend", |
251 | | - type=click.Choice(["1", "2"]), |
| 269 | + "1. Google AI\n2. Vertex AI\n3. Login with Google\nChoose a backend", |
| 270 | + type=click.Choice(["1", "2", "3"]), |
252 | 271 | ) |
253 | 272 | if backend_choice == "1": |
254 | 273 | google_api_key = _prompt_for_google_api_key(google_api_key) |
255 | 274 | elif backend_choice == "2": |
256 | 275 | click.secho(_GOOGLE_CLOUD_SETUP_MSG, fg="green") |
257 | 276 | google_cloud_project = _prompt_for_google_cloud(google_cloud_project) |
258 | 277 | google_cloud_region = _prompt_for_google_cloud_region(google_cloud_region) |
| 278 | + elif backend_choice == "3": |
| 279 | + google_api_key, google_cloud_project, google_cloud_region = ( |
| 280 | + _handle_login_with_google() |
| 281 | + ) |
259 | 282 | return google_api_key, google_cloud_project, google_cloud_region |
260 | 283 |
|
261 | 284 |
|
| 285 | +def _handle_login_with_google() -> ( |
| 286 | + Tuple[Optional[str], Optional[str], Optional[str]] |
| 287 | +): |
| 288 | + """Handles the "Login with Google" flow.""" |
| 289 | + if not gcp_utils.check_adc(): |
| 290 | + click.secho( |
| 291 | + "No Application Default Credentials found. " |
| 292 | + "Opening browser for login...", |
| 293 | + fg="yellow", |
| 294 | + ) |
| 295 | + try: |
| 296 | + gcp_utils.login_adc() |
| 297 | + except RuntimeError as e: |
| 298 | + click.secho(str(e), fg="red") |
| 299 | + raise click.Abort() |
| 300 | + |
| 301 | + # Check for existing Express project |
| 302 | + express_project = gcp_utils.retrieve_express_project() |
| 303 | + if express_project: |
| 304 | + api_key = express_project.get("api_key") |
| 305 | + project_id = express_project.get("project_id") |
| 306 | + region = express_project.get("region", "us-central1") |
| 307 | + if project_id: |
| 308 | + click.secho(f"Using existing Express project: {project_id}", fg="green") |
| 309 | + return api_key, project_id, region |
| 310 | + |
| 311 | + # Check for existing full GCP projects |
| 312 | + projects = gcp_utils.list_gcp_projects(limit=20) |
| 313 | + if projects: |
| 314 | + click.secho("Recently created Google Cloud projects found:", fg="green") |
| 315 | + click.echo("0. Enter project ID manually") |
| 316 | + for i, (p_id, p_name) in enumerate(projects, 1): |
| 317 | + click.echo(f"{i}. {p_name} ({p_id})") |
| 318 | + |
| 319 | + project_index = click.prompt( |
| 320 | + "Select a project", |
| 321 | + type=click.IntRange(0, len(projects)), |
| 322 | + ) |
| 323 | + if project_index == 0: |
| 324 | + selected_project_id = _prompt_for_google_cloud(None) |
| 325 | + else: |
| 326 | + selected_project_id = projects[project_index - 1][0] |
| 327 | + region = _prompt_for_google_cloud_region(None) |
| 328 | + return None, selected_project_id, region |
| 329 | + else: |
| 330 | + if click.confirm( |
| 331 | + "No projects found automatically. Would you like to enter one" |
| 332 | + " manually?", |
| 333 | + default=False, |
| 334 | + ): |
| 335 | + selected_project_id = _prompt_for_google_cloud(None) |
| 336 | + region = _prompt_for_google_cloud_region(None) |
| 337 | + return None, selected_project_id, region |
| 338 | + |
| 339 | + # Check Express eligibility |
| 340 | + if gcp_utils.check_express_eligibility(): |
| 341 | + click.secho(_EXPRESS_TOS_MSG, fg="yellow") |
| 342 | + if click.confirm("Do you accept the Terms of Service?", default=False): |
| 343 | + selected_region = click.prompt( |
| 344 | + """\ |
| 345 | +Choose a region for Express Mode: |
| 346 | +1. us-central1 |
| 347 | +2. europe-west1 |
| 348 | +3. asia-southeast1 |
| 349 | +Choose region""", |
| 350 | + type=click.Choice(["1", "2", "3"]), |
| 351 | + default="1", |
| 352 | + ) |
| 353 | + region_map = { |
| 354 | + "1": "us-central1", |
| 355 | + "2": "europe-west1", |
| 356 | + "3": "asia-southeast1", |
| 357 | + } |
| 358 | + region = region_map[selected_region] |
| 359 | + express_info = gcp_utils.sign_up_express(location=region) |
| 360 | + api_key = express_info.get("api_key") |
| 361 | + project_id = express_info.get("project_id") |
| 362 | + region = express_info.get("region", region) |
| 363 | + click.secho( |
| 364 | + f"Express Mode project created: {project_id}", |
| 365 | + fg="green", |
| 366 | + ) |
| 367 | + return api_key, project_id, region |
| 368 | + |
| 369 | + click.secho(_NOT_ELIGIBLE_MSG, fg="red") |
| 370 | + raise click.Abort() |
| 371 | + |
| 372 | + |
262 | 373 | def _prompt_to_choose_type() -> str: |
263 | 374 | """Prompts user to choose type of agent to create.""" |
264 | 375 | type_choice = click.prompt( |
|
0 commit comments