agent-starter-pack 0.0.1b0__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.
Potentially problematic release.
This version of agent-starter-pack might be problematic. Click here for more details.
- agent_starter_pack-0.0.1b0.dist-info/METADATA +143 -0
- agent_starter_pack-0.0.1b0.dist-info/RECORD +162 -0
- agent_starter_pack-0.0.1b0.dist-info/WHEEL +4 -0
- agent_starter_pack-0.0.1b0.dist-info/entry_points.txt +2 -0
- agent_starter_pack-0.0.1b0.dist-info/licenses/LICENSE +201 -0
- agents/agentic_rag_vertexai_search/README.md +22 -0
- agents/agentic_rag_vertexai_search/app/agent.py +145 -0
- agents/agentic_rag_vertexai_search/app/retrievers.py +79 -0
- agents/agentic_rag_vertexai_search/app/templates.py +53 -0
- agents/agentic_rag_vertexai_search/notebooks/evaluating_langgraph_agent.ipynb +1561 -0
- agents/agentic_rag_vertexai_search/template/.templateconfig.yaml +14 -0
- agents/agentic_rag_vertexai_search/tests/integration/test_agent.py +57 -0
- agents/crewai_coding_crew/README.md +34 -0
- agents/crewai_coding_crew/app/agent.py +86 -0
- agents/crewai_coding_crew/app/crew/config/agents.yaml +39 -0
- agents/crewai_coding_crew/app/crew/config/tasks.yaml +37 -0
- agents/crewai_coding_crew/app/crew/crew.py +71 -0
- agents/crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb +1571 -0
- agents/crewai_coding_crew/notebooks/evaluating_langgraph_agent.ipynb +1561 -0
- agents/crewai_coding_crew/template/.templateconfig.yaml +12 -0
- agents/crewai_coding_crew/tests/integration/test_agent.py +47 -0
- agents/langgraph_base_react/README.md +9 -0
- agents/langgraph_base_react/app/agent.py +73 -0
- agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb +1561 -0
- agents/langgraph_base_react/template/.templateconfig.yaml +13 -0
- agents/langgraph_base_react/tests/integration/test_agent.py +48 -0
- agents/multimodal_live_api/README.md +50 -0
- agents/multimodal_live_api/app/agent.py +86 -0
- agents/multimodal_live_api/app/server.py +193 -0
- agents/multimodal_live_api/app/templates.py +51 -0
- agents/multimodal_live_api/app/vector_store.py +55 -0
- agents/multimodal_live_api/template/.templateconfig.yaml +15 -0
- agents/multimodal_live_api/tests/integration/test_server_e2e.py +254 -0
- agents/multimodal_live_api/tests/load_test/load_test.py +40 -0
- agents/multimodal_live_api/tests/unit/test_server.py +143 -0
- src/base_template/.gitignore +197 -0
- src/base_template/Makefile +37 -0
- src/base_template/README.md +91 -0
- src/base_template/app/utils/tracing.py +143 -0
- src/base_template/app/utils/typing.py +115 -0
- src/base_template/deployment/README.md +123 -0
- src/base_template/deployment/cd/deploy-to-prod.yaml +98 -0
- src/base_template/deployment/cd/staging.yaml +215 -0
- src/base_template/deployment/ci/pr_checks.yaml +51 -0
- src/base_template/deployment/terraform/apis.tf +34 -0
- src/base_template/deployment/terraform/build_triggers.tf +122 -0
- src/base_template/deployment/terraform/dev/apis.tf +42 -0
- src/base_template/deployment/terraform/dev/iam.tf +90 -0
- src/base_template/deployment/terraform/dev/log_sinks.tf +66 -0
- src/base_template/deployment/terraform/dev/providers.tf +29 -0
- src/base_template/deployment/terraform/dev/storage.tf +76 -0
- src/base_template/deployment/terraform/dev/variables.tf +126 -0
- src/base_template/deployment/terraform/dev/vars/env.tfvars +21 -0
- src/base_template/deployment/terraform/iam.tf +130 -0
- src/base_template/deployment/terraform/locals.tf +50 -0
- src/base_template/deployment/terraform/log_sinks.tf +72 -0
- src/base_template/deployment/terraform/providers.tf +35 -0
- src/base_template/deployment/terraform/service_accounts.tf +42 -0
- src/base_template/deployment/terraform/storage.tf +100 -0
- src/base_template/deployment/terraform/variables.tf +202 -0
- src/base_template/deployment/terraform/vars/env.tfvars +43 -0
- src/base_template/pyproject.toml +113 -0
- src/base_template/tests/unit/test_utils/test_tracing_exporter.py +140 -0
- src/cli/commands/create.py +534 -0
- src/cli/commands/setup_cicd.py +730 -0
- src/cli/main.py +35 -0
- src/cli/utils/__init__.py +35 -0
- src/cli/utils/cicd.py +662 -0
- src/cli/utils/gcp.py +120 -0
- src/cli/utils/logging.py +51 -0
- src/cli/utils/template.py +644 -0
- src/data_ingestion/README.md +79 -0
- src/data_ingestion/data_ingestion_pipeline/components/ingest_data.py +175 -0
- src/data_ingestion/data_ingestion_pipeline/components/process_data.py +321 -0
- src/data_ingestion/data_ingestion_pipeline/pipeline.py +58 -0
- src/data_ingestion/data_ingestion_pipeline/submit_pipeline.py +184 -0
- src/data_ingestion/pyproject.toml +17 -0
- src/data_ingestion/uv.lock +999 -0
- src/deployment_targets/agent_engine/app/agent_engine_app.py +238 -0
- src/deployment_targets/agent_engine/app/utils/gcs.py +42 -0
- src/deployment_targets/agent_engine/deployment_metadata.json +4 -0
- src/deployment_targets/agent_engine/notebooks/intro_reasoning_engine.ipynb +869 -0
- src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +120 -0
- src/deployment_targets/agent_engine/tests/load_test/.results/.placeholder +0 -0
- src/deployment_targets/agent_engine/tests/load_test/.results/report.html +264 -0
- src/deployment_targets/agent_engine/tests/load_test/.results/results_exceptions.csv +1 -0
- src/deployment_targets/agent_engine/tests/load_test/.results/results_failures.csv +1 -0
- src/deployment_targets/agent_engine/tests/load_test/.results/results_stats.csv +3 -0
- src/deployment_targets/agent_engine/tests/load_test/.results/results_stats_history.csv +22 -0
- src/deployment_targets/agent_engine/tests/load_test/README.md +42 -0
- src/deployment_targets/agent_engine/tests/load_test/load_test.py +100 -0
- src/deployment_targets/agent_engine/tests/unit/test_dummy.py +22 -0
- src/deployment_targets/cloud_run/Dockerfile +29 -0
- src/deployment_targets/cloud_run/app/server.py +128 -0
- src/deployment_targets/cloud_run/deployment/terraform/artifact_registry.tf +22 -0
- src/deployment_targets/cloud_run/deployment/terraform/dev/service_accounts.tf +20 -0
- src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +192 -0
- src/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +0 -0
- src/deployment_targets/cloud_run/tests/load_test/README.md +79 -0
- src/deployment_targets/cloud_run/tests/load_test/load_test.py +85 -0
- src/deployment_targets/cloud_run/tests/unit/test_server.py +142 -0
- src/deployment_targets/cloud_run/uv.lock +6952 -0
- src/frontends/live_api_react/frontend/package-lock.json +19405 -0
- src/frontends/live_api_react/frontend/package.json +56 -0
- src/frontends/live_api_react/frontend/public/favicon.ico +0 -0
- src/frontends/live_api_react/frontend/public/index.html +62 -0
- src/frontends/live_api_react/frontend/public/robots.txt +3 -0
- src/frontends/live_api_react/frontend/src/App.scss +189 -0
- src/frontends/live_api_react/frontend/src/App.test.tsx +25 -0
- src/frontends/live_api_react/frontend/src/App.tsx +205 -0
- src/frontends/live_api_react/frontend/src/components/audio-pulse/AudioPulse.tsx +64 -0
- src/frontends/live_api_react/frontend/src/components/audio-pulse/audio-pulse.scss +68 -0
- src/frontends/live_api_react/frontend/src/components/control-tray/ControlTray.tsx +217 -0
- src/frontends/live_api_react/frontend/src/components/control-tray/control-tray.scss +201 -0
- src/frontends/live_api_react/frontend/src/components/logger/Logger.tsx +241 -0
- src/frontends/live_api_react/frontend/src/components/logger/logger.scss +133 -0
- src/frontends/live_api_react/frontend/src/components/logger/mock-logs.ts +151 -0
- src/frontends/live_api_react/frontend/src/components/side-panel/SidePanel.tsx +161 -0
- src/frontends/live_api_react/frontend/src/components/side-panel/side-panel.scss +285 -0
- src/frontends/live_api_react/frontend/src/contexts/LiveAPIContext.tsx +48 -0
- src/frontends/live_api_react/frontend/src/hooks/use-live-api.ts +115 -0
- src/frontends/live_api_react/frontend/src/hooks/use-media-stream-mux.ts +23 -0
- src/frontends/live_api_react/frontend/src/hooks/use-screen-capture.ts +72 -0
- src/frontends/live_api_react/frontend/src/hooks/use-webcam.ts +69 -0
- src/frontends/live_api_react/frontend/src/index.css +28 -0
- src/frontends/live_api_react/frontend/src/index.tsx +35 -0
- src/frontends/live_api_react/frontend/src/multimodal-live-types.ts +242 -0
- src/frontends/live_api_react/frontend/src/react-app-env.d.ts +17 -0
- src/frontends/live_api_react/frontend/src/reportWebVitals.ts +31 -0
- src/frontends/live_api_react/frontend/src/setupTests.ts +21 -0
- src/frontends/live_api_react/frontend/src/utils/audio-recorder.ts +111 -0
- src/frontends/live_api_react/frontend/src/utils/audio-streamer.ts +270 -0
- src/frontends/live_api_react/frontend/src/utils/audioworklet-registry.ts +43 -0
- src/frontends/live_api_react/frontend/src/utils/multimodal-live-client.ts +329 -0
- src/frontends/live_api_react/frontend/src/utils/store-logger.ts +64 -0
- src/frontends/live_api_react/frontend/src/utils/utils.ts +86 -0
- src/frontends/live_api_react/frontend/src/utils/worklets/audio-processing.ts +73 -0
- src/frontends/live_api_react/frontend/src/utils/worklets/vol-meter.ts +65 -0
- src/frontends/live_api_react/frontend/tsconfig.json +25 -0
- src/frontends/streamlit/frontend/side_bar.py +213 -0
- src/frontends/streamlit/frontend/streamlit_app.py +263 -0
- src/frontends/streamlit/frontend/style/app_markdown.py +37 -0
- src/frontends/streamlit/frontend/utils/chat_utils.py +67 -0
- src/frontends/streamlit/frontend/utils/local_chat_history.py +125 -0
- src/frontends/streamlit/frontend/utils/message_editing.py +59 -0
- src/frontends/streamlit/frontend/utils/multimodal_utils.py +217 -0
- src/frontends/streamlit/frontend/utils/stream_handler.py +282 -0
- src/frontends/streamlit/frontend/utils/title_summary.py +77 -0
- src/resources/containers/data_processing/Dockerfile +25 -0
- src/resources/locks/uv-agentic_rag_vertexai_search-agent_engine.lock +4684 -0
- src/resources/locks/uv-agentic_rag_vertexai_search-cloud_run.lock +5799 -0
- src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +5509 -0
- src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +6688 -0
- src/resources/locks/uv-langgraph_base_react-agent_engine.lock +4595 -0
- src/resources/locks/uv-langgraph_base_react-cloud_run.lock +5710 -0
- src/resources/locks/uv-multimodal_live_api-cloud_run.lock +5665 -0
- src/resources/setup_cicd/cicd_variables.tf +36 -0
- src/resources/setup_cicd/github.tf +85 -0
- src/resources/setup_cicd/providers.tf +39 -0
- src/utils/generate_locks.py +135 -0
- src/utils/lock_utils.py +82 -0
- src/utils/watch_and_rebuild.py +190 -0
|
@@ -0,0 +1,534 @@
|
|
|
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
|
+
import logging
|
|
16
|
+
import pathlib
|
|
17
|
+
import subprocess
|
|
18
|
+
|
|
19
|
+
import click
|
|
20
|
+
from click.core import ParameterSource
|
|
21
|
+
from rich.console import Console
|
|
22
|
+
from rich.prompt import IntPrompt, Prompt
|
|
23
|
+
|
|
24
|
+
from ..utils.gcp import verify_credentials, verify_vertex_connection
|
|
25
|
+
from ..utils.logging import handle_cli_error
|
|
26
|
+
from ..utils.template import (
|
|
27
|
+
get_available_agents,
|
|
28
|
+
get_template_path,
|
|
29
|
+
process_template,
|
|
30
|
+
prompt_data_ingestion,
|
|
31
|
+
prompt_deployment_target,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
console = Console()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@click.command()
|
|
38
|
+
@click.pass_context
|
|
39
|
+
@click.argument("project_name")
|
|
40
|
+
@click.option("--agent", "-a", help="agent name or number to use")
|
|
41
|
+
@click.option(
|
|
42
|
+
"--deployment-target",
|
|
43
|
+
"-d",
|
|
44
|
+
type=click.Choice(["agent_engine", "cloud_run"]),
|
|
45
|
+
help="Deployment target name",
|
|
46
|
+
)
|
|
47
|
+
@click.option(
|
|
48
|
+
"--include-data-ingestion", "-i", is_flag=True, help="Include data pipeline"
|
|
49
|
+
)
|
|
50
|
+
@click.option("--gcp-account", help="GCP service account email")
|
|
51
|
+
@click.option("--gcp-project", help="GCP project ID")
|
|
52
|
+
@click.option("--debug", is_flag=True, help="Enable debug logging")
|
|
53
|
+
@click.option(
|
|
54
|
+
"--output-dir",
|
|
55
|
+
"-o",
|
|
56
|
+
type=click.Path(),
|
|
57
|
+
help="Output directory for the project (default: current directory)",
|
|
58
|
+
)
|
|
59
|
+
@click.option(
|
|
60
|
+
"--auto-approve", is_flag=True, help="Skip credential confirmation prompts"
|
|
61
|
+
)
|
|
62
|
+
@click.option(
|
|
63
|
+
"--region",
|
|
64
|
+
help="GCP region for deployment (default: us-central1)",
|
|
65
|
+
default="us-central1",
|
|
66
|
+
)
|
|
67
|
+
@click.option(
|
|
68
|
+
"--skip-checks",
|
|
69
|
+
is_flag=True,
|
|
70
|
+
help="Skip verification checks for uv, GCP and Vertex AI",
|
|
71
|
+
default=False,
|
|
72
|
+
)
|
|
73
|
+
@handle_cli_error
|
|
74
|
+
def create(
|
|
75
|
+
ctx: click.Context,
|
|
76
|
+
project_name: str,
|
|
77
|
+
agent: str | None,
|
|
78
|
+
deployment_target: str | None,
|
|
79
|
+
include_data_ingestion: bool,
|
|
80
|
+
gcp_account: str | None,
|
|
81
|
+
gcp_project: str | None,
|
|
82
|
+
debug: bool,
|
|
83
|
+
output_dir: str | None,
|
|
84
|
+
auto_approve: bool,
|
|
85
|
+
region: str,
|
|
86
|
+
skip_checks: bool,
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Create GCP-based AI agent projects from templates."""
|
|
89
|
+
try:
|
|
90
|
+
# Display welcome banner
|
|
91
|
+
console.print("\n=== GCP Agent Starter Pack :rocket:===", style="bold blue")
|
|
92
|
+
console.print("Welcome to the Agent Starter Pack!")
|
|
93
|
+
console.print(
|
|
94
|
+
"This tool will help you create an end-to-end production-ready AI agent in GCP!\n"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Setup debug logging if enabled
|
|
98
|
+
if debug:
|
|
99
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
100
|
+
console.print("> Debug mode enabled")
|
|
101
|
+
logging.debug("Starting CLI in debug mode")
|
|
102
|
+
|
|
103
|
+
# Convert output_dir to Path if provided, otherwise use current directory
|
|
104
|
+
destination_dir = pathlib.Path(output_dir) if output_dir else pathlib.Path.cwd()
|
|
105
|
+
destination_dir = destination_dir.resolve() # Convert to absolute path
|
|
106
|
+
|
|
107
|
+
# Check if project would exist in output directory
|
|
108
|
+
project_path = destination_dir / project_name
|
|
109
|
+
if project_path.exists():
|
|
110
|
+
console.print(
|
|
111
|
+
f"Error: Project directory '{project_path}' already exists",
|
|
112
|
+
style="bold red",
|
|
113
|
+
)
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
# Agent selection
|
|
117
|
+
selected_agent = None
|
|
118
|
+
if agent:
|
|
119
|
+
agents = get_available_agents()
|
|
120
|
+
# First check if it's a valid agent name
|
|
121
|
+
if any(p["name"] == agent for p in agents.values()):
|
|
122
|
+
selected_agent = agent
|
|
123
|
+
else:
|
|
124
|
+
# Try numeric agent selection if input is a number
|
|
125
|
+
try:
|
|
126
|
+
agent_num = int(agent)
|
|
127
|
+
if agent_num in agents:
|
|
128
|
+
selected_agent = agents[agent_num]["name"]
|
|
129
|
+
else:
|
|
130
|
+
raise ValueError(f"Invalid agent number: {agent_num}")
|
|
131
|
+
except ValueError as err:
|
|
132
|
+
raise ValueError(f"Invalid agent name or number: {agent}") from err
|
|
133
|
+
|
|
134
|
+
final_agent = (
|
|
135
|
+
selected_agent
|
|
136
|
+
if selected_agent
|
|
137
|
+
else display_agent_selection(deployment_target)
|
|
138
|
+
)
|
|
139
|
+
if debug:
|
|
140
|
+
logging.debug(f"Selected agent: {agent}")
|
|
141
|
+
|
|
142
|
+
# Deployment target selection
|
|
143
|
+
final_deployment = (
|
|
144
|
+
deployment_target
|
|
145
|
+
if deployment_target
|
|
146
|
+
else prompt_deployment_target(final_agent)
|
|
147
|
+
)
|
|
148
|
+
if debug:
|
|
149
|
+
logging.debug(f"Selected deployment target: {final_deployment}")
|
|
150
|
+
|
|
151
|
+
# Data pipeline selection
|
|
152
|
+
include_data_ingestion = include_data_ingestion or prompt_data_ingestion(final_agent)
|
|
153
|
+
if debug:
|
|
154
|
+
logging.debug(f"Include data pipeline: {include_data_ingestion}")
|
|
155
|
+
# Region confirmation (if not explicitly passed)
|
|
156
|
+
if not auto_approve and ctx.get_parameter_source("region") != ParameterSource.COMMANDLINE:
|
|
157
|
+
region = prompt_region_confirmation(region)
|
|
158
|
+
if debug:
|
|
159
|
+
logging.debug(f"Selected region: {region}")
|
|
160
|
+
|
|
161
|
+
# GCP Setup
|
|
162
|
+
with console.status("[bold blue]Setting up GCP environment...", spinner="dots"):
|
|
163
|
+
if debug:
|
|
164
|
+
logging.debug("Setting up GCP...")
|
|
165
|
+
|
|
166
|
+
# Handle GCP credentials
|
|
167
|
+
if gcp_account and gcp_project:
|
|
168
|
+
try:
|
|
169
|
+
subprocess.run(
|
|
170
|
+
["gcloud", "config", "set", "account", gcp_account], check=True
|
|
171
|
+
)
|
|
172
|
+
subprocess.run(
|
|
173
|
+
["gcloud", "config", "set", "project", gcp_project], check=True
|
|
174
|
+
)
|
|
175
|
+
subprocess.run(
|
|
176
|
+
[
|
|
177
|
+
"gcloud",
|
|
178
|
+
"auth",
|
|
179
|
+
"application-default",
|
|
180
|
+
"set-quota-project",
|
|
181
|
+
gcp_project,
|
|
182
|
+
],
|
|
183
|
+
check=True,
|
|
184
|
+
)
|
|
185
|
+
except subprocess.CalledProcessError as e:
|
|
186
|
+
console.print(f"Error setting GCP credentials: {e!s}", style="bold red")
|
|
187
|
+
raise
|
|
188
|
+
|
|
189
|
+
if not skip_checks:
|
|
190
|
+
# Verify GCP credentials
|
|
191
|
+
if debug:
|
|
192
|
+
logging.debug("Verifying GCP credentials...")
|
|
193
|
+
creds_info = verify_credentials()
|
|
194
|
+
|
|
195
|
+
if not auto_approve:
|
|
196
|
+
change_creds = (
|
|
197
|
+
Prompt.ask(
|
|
198
|
+
f"\n> You are logged in with account '{creds_info['account']}' "
|
|
199
|
+
f"and using project '{creds_info['project']}'. "
|
|
200
|
+
"Do you wish to change this?",
|
|
201
|
+
choices=["y", "n"],
|
|
202
|
+
default="n",
|
|
203
|
+
).lower()
|
|
204
|
+
== "y"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if change_creds:
|
|
208
|
+
handle_credential_change()
|
|
209
|
+
else:
|
|
210
|
+
console.print(
|
|
211
|
+
f"\n> Using account '{creds_info['account']}' "
|
|
212
|
+
f"with project '{creds_info['project']}'"
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Check for uv installation
|
|
216
|
+
console.print("> Checking for uv installation...")
|
|
217
|
+
check_and_install_uv()
|
|
218
|
+
else:
|
|
219
|
+
if debug:
|
|
220
|
+
logging.debug("Skipping verification checks due to --skip-checks flag")
|
|
221
|
+
console.print("> Skipping verification checks", style="yellow")
|
|
222
|
+
# Set a default creds_info when skipping checks
|
|
223
|
+
creds_info = {"project": gcp_project} if gcp_project else {"project": "unknown"}
|
|
224
|
+
|
|
225
|
+
console.print("> Testing GCP and Vertex AI Connection...")
|
|
226
|
+
try:
|
|
227
|
+
verify_vertex_connection(
|
|
228
|
+
project_id=creds_info["project"],
|
|
229
|
+
location=region,
|
|
230
|
+
)
|
|
231
|
+
console.print(
|
|
232
|
+
f"> ✓ Successfully verified connection to Vertex AI in project {creds_info['project']}"
|
|
233
|
+
)
|
|
234
|
+
except Exception as e:
|
|
235
|
+
console.print(
|
|
236
|
+
f"> ✗ Failed to connect to Vertex AI: {e!s}", style="bold red"
|
|
237
|
+
)
|
|
238
|
+
raise
|
|
239
|
+
|
|
240
|
+
# Process template
|
|
241
|
+
template_path = get_template_path(final_agent, debug=debug)
|
|
242
|
+
if debug:
|
|
243
|
+
logging.debug(f"Template path: {template_path}")
|
|
244
|
+
logging.debug(f"Processing template for project: {project_name}")
|
|
245
|
+
|
|
246
|
+
# Create output directory if it doesn't exist
|
|
247
|
+
if not destination_dir.exists():
|
|
248
|
+
destination_dir.mkdir(parents=True)
|
|
249
|
+
|
|
250
|
+
if debug:
|
|
251
|
+
logging.debug(f"Output directory: {destination_dir}")
|
|
252
|
+
|
|
253
|
+
process_template(
|
|
254
|
+
final_agent,
|
|
255
|
+
template_path,
|
|
256
|
+
project_name,
|
|
257
|
+
deployment_target=final_deployment,
|
|
258
|
+
include_data_ingestion=include_data_ingestion,
|
|
259
|
+
output_dir=destination_dir,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
project_path = destination_dir / project_name
|
|
263
|
+
console.print("\n> 👍 Done. Execute the following command to get started:")
|
|
264
|
+
if output_dir:
|
|
265
|
+
# If output_dir was specified, use the absolute path
|
|
266
|
+
console.print(f"cd {project_path} && make install && make playground")
|
|
267
|
+
else:
|
|
268
|
+
# If no output_dir specified, just use project name
|
|
269
|
+
console.print(f"cd {project_name} && make install && make playground")
|
|
270
|
+
|
|
271
|
+
# Replace region in all files if a different region was specified
|
|
272
|
+
if region != "us-central1":
|
|
273
|
+
replace_region_in_files(project_path, region, debug=debug)
|
|
274
|
+
except Exception:
|
|
275
|
+
if debug:
|
|
276
|
+
logging.exception(
|
|
277
|
+
"An error occurred:"
|
|
278
|
+
) # This will print the full stack trace
|
|
279
|
+
raise
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def prompt_region_confirmation(default_region: str = "us-central1") -> str:
|
|
283
|
+
"""Prompt user to confirm or change the default region."""
|
|
284
|
+
console.print(f"\n> Default GCP region is '{default_region}'")
|
|
285
|
+
new_region = Prompt.ask(
|
|
286
|
+
"Enter desired GCP region (leave blank for default)",
|
|
287
|
+
default="",
|
|
288
|
+
show_default=False,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
return new_region if new_region else default_region
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def display_agent_selection(deployment_target: str | None = None) -> str:
|
|
295
|
+
"""Display available agents and prompt for selection."""
|
|
296
|
+
agents = get_available_agents(deployment_target=deployment_target)
|
|
297
|
+
|
|
298
|
+
if not agents:
|
|
299
|
+
if deployment_target:
|
|
300
|
+
raise click.ClickException(
|
|
301
|
+
f"No agents available for deployment target '{deployment_target}'"
|
|
302
|
+
)
|
|
303
|
+
raise click.ClickException("No valid agents found")
|
|
304
|
+
|
|
305
|
+
console.print("\n> Please select a agent to get started:")
|
|
306
|
+
for num, agent in agents.items():
|
|
307
|
+
console.print(
|
|
308
|
+
f"{num}. [bold]{agent['name']}[/] - [dim]{agent['description']}[/]"
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
choice = IntPrompt.ask(
|
|
312
|
+
"\nEnter the number of your template choice", default=1, show_default=True
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
if choice not in agents:
|
|
316
|
+
raise ValueError(f"Invalid agent selection: {choice}")
|
|
317
|
+
|
|
318
|
+
return agents[choice]["name"]
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def handle_credential_change() -> None:
|
|
322
|
+
"""Handle the process of changing GCP credentials."""
|
|
323
|
+
try:
|
|
324
|
+
console.print("\n> Initiating new login...")
|
|
325
|
+
subprocess.run(["gcloud", "auth", "login", "--update-adc"], check=True)
|
|
326
|
+
console.print("> Login successful. Verifying new credentials...")
|
|
327
|
+
|
|
328
|
+
# Re-verify credentials after login
|
|
329
|
+
new_creds_info = verify_credentials()
|
|
330
|
+
|
|
331
|
+
# Prompt for project change
|
|
332
|
+
change_project = (
|
|
333
|
+
Prompt.ask(
|
|
334
|
+
f"\n> You are now logged in with account '{new_creds_info['account']}'. "
|
|
335
|
+
f"Current project is '{new_creds_info['project']}'. "
|
|
336
|
+
"Do you wish to change the project?",
|
|
337
|
+
choices=["y", "n"],
|
|
338
|
+
default="n",
|
|
339
|
+
).lower()
|
|
340
|
+
== "y"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
if change_project:
|
|
344
|
+
handle_project_change()
|
|
345
|
+
|
|
346
|
+
except subprocess.CalledProcessError as e:
|
|
347
|
+
console.print(
|
|
348
|
+
"\n> Error during login process. Please try again.", style="bold red"
|
|
349
|
+
)
|
|
350
|
+
logging.debug(f"Login error: {e!s}")
|
|
351
|
+
raise
|
|
352
|
+
except Exception as e:
|
|
353
|
+
console.print(f"\n> Unexpected error: {e!s}", style="bold red")
|
|
354
|
+
logging.debug(f"Unexpected error during login: {e!s}")
|
|
355
|
+
raise
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def handle_project_change() -> None:
|
|
359
|
+
"""Handle the process of changing GCP project."""
|
|
360
|
+
try:
|
|
361
|
+
# Prompt for new project ID
|
|
362
|
+
new_project = Prompt.ask("\n> Enter the new project ID")
|
|
363
|
+
|
|
364
|
+
console.print(f"\n> Setting project to {new_project}...")
|
|
365
|
+
subprocess.run(["gcloud", "config", "set", "project", new_project], check=True)
|
|
366
|
+
|
|
367
|
+
console.print("> Setting application default quota project...")
|
|
368
|
+
subprocess.run(
|
|
369
|
+
["gcloud", "auth", "application-default", "set-quota-project", new_project],
|
|
370
|
+
check=True,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
console.print(f"> Successfully switched to project: {new_project}")
|
|
374
|
+
|
|
375
|
+
# Re-verify credentials one final time
|
|
376
|
+
final_creds_info = verify_credentials()
|
|
377
|
+
console.print(
|
|
378
|
+
f"\n> Now using account '{final_creds_info['account']}' "
|
|
379
|
+
f"with project '{final_creds_info['project']}'"
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
except subprocess.CalledProcessError as e:
|
|
383
|
+
console.print(
|
|
384
|
+
"\n> Error while changing project. Please verify the project ID and try again.",
|
|
385
|
+
style="bold red",
|
|
386
|
+
)
|
|
387
|
+
logging.debug(f"Project change error: {e!s}")
|
|
388
|
+
raise
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def replace_region_in_files(
|
|
392
|
+
project_path: pathlib.Path, new_region: str, debug: bool = False
|
|
393
|
+
) -> None:
|
|
394
|
+
"""Replace all instances of 'us-central1' with the specified region in project files.
|
|
395
|
+
Also handles vertex_ai_search region mapping.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
project_path: Path to the project directory
|
|
399
|
+
new_region: The new region to use
|
|
400
|
+
debug: Whether to enable debug logging
|
|
401
|
+
"""
|
|
402
|
+
if debug:
|
|
403
|
+
logging.debug(
|
|
404
|
+
f"Replacing region 'us-central1' with '{new_region}' in {project_path}"
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
# Define allowed file extensions
|
|
408
|
+
allowed_extensions = {".md", ".py", ".tfvars", ".yaml", ".tf", ".yml"}
|
|
409
|
+
|
|
410
|
+
# Skip directories that shouldn't be modified
|
|
411
|
+
skip_dirs = {".git", "__pycache__", "venv", ".venv", "node_modules"}
|
|
412
|
+
|
|
413
|
+
# Determine data_store_region region value
|
|
414
|
+
if new_region.startswith("us"):
|
|
415
|
+
data_store_region = "us"
|
|
416
|
+
elif new_region.startswith("europe"):
|
|
417
|
+
data_store_region = "eu"
|
|
418
|
+
else:
|
|
419
|
+
data_store_region = "global"
|
|
420
|
+
|
|
421
|
+
for file_path in project_path.rglob("*"):
|
|
422
|
+
# Skip directories and files with unwanted extensions
|
|
423
|
+
if (
|
|
424
|
+
file_path.is_dir()
|
|
425
|
+
or any(skip_dir in file_path.parts for skip_dir in skip_dirs)
|
|
426
|
+
or file_path.suffix not in allowed_extensions
|
|
427
|
+
):
|
|
428
|
+
continue
|
|
429
|
+
|
|
430
|
+
try:
|
|
431
|
+
content = file_path.read_text()
|
|
432
|
+
modified = False
|
|
433
|
+
|
|
434
|
+
# Replace standard region references
|
|
435
|
+
if "us-central1" in content:
|
|
436
|
+
if debug:
|
|
437
|
+
logging.debug(f"Replacing region in {file_path}")
|
|
438
|
+
content = content.replace("us-central1", new_region)
|
|
439
|
+
modified = True
|
|
440
|
+
|
|
441
|
+
# Replace data_store_region region if present (all variants)
|
|
442
|
+
if 'data_store_region = "us"' in content:
|
|
443
|
+
if debug:
|
|
444
|
+
logging.debug(f"Replacing vertex_ai_search region in {file_path}")
|
|
445
|
+
content = content.replace(
|
|
446
|
+
'data_store_region = "us"',
|
|
447
|
+
f'data_store_region = "{data_store_region}"',
|
|
448
|
+
)
|
|
449
|
+
modified = True
|
|
450
|
+
elif 'data_store_region="us"' in content:
|
|
451
|
+
if debug:
|
|
452
|
+
logging.debug(f"Replacing data_store_region in {file_path}")
|
|
453
|
+
content = content.replace(
|
|
454
|
+
'data_store_region="us"', f'data_store_region="{data_store_region}"'
|
|
455
|
+
)
|
|
456
|
+
modified = True
|
|
457
|
+
elif "_DATA_STORE_REGION: us" in content:
|
|
458
|
+
if debug:
|
|
459
|
+
logging.debug(f"Replacing _DATA_STORE_REGION in {file_path}")
|
|
460
|
+
content = content.replace(
|
|
461
|
+
"_DATA_STORE_REGION: us", f"_DATA_STORE_REGION: {data_store_region}"
|
|
462
|
+
)
|
|
463
|
+
modified = True
|
|
464
|
+
|
|
465
|
+
if modified:
|
|
466
|
+
file_path.write_text(content)
|
|
467
|
+
|
|
468
|
+
except UnicodeDecodeError:
|
|
469
|
+
# Skip files that can't be read as text
|
|
470
|
+
continue
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def check_and_install_uv() -> None:
|
|
474
|
+
"""Check if uv is installed and install it if not present."""
|
|
475
|
+
try:
|
|
476
|
+
# Use shell=True for Windows compatibility and add timeout
|
|
477
|
+
process = subprocess.run(
|
|
478
|
+
"uv --version",
|
|
479
|
+
shell=True,
|
|
480
|
+
capture_output=True,
|
|
481
|
+
text=True,
|
|
482
|
+
timeout=10
|
|
483
|
+
)
|
|
484
|
+
if process.returncode == 0:
|
|
485
|
+
logging.debug("uv is already installed")
|
|
486
|
+
return
|
|
487
|
+
else:
|
|
488
|
+
console.print("> uv command failed", style="yellow")
|
|
489
|
+
except subprocess.TimeoutExpired:
|
|
490
|
+
console.print("> uv version check timed out", style="yellow")
|
|
491
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
492
|
+
console.print("> uv is not installed", style="yellow")
|
|
493
|
+
|
|
494
|
+
console.print(
|
|
495
|
+
"\n> uv is required for the template to work. You can install it in several ways:"
|
|
496
|
+
"\n 1. Automatically install uv now"
|
|
497
|
+
"\n 2. Manual installation from: https://docs.astral.sh/uv/getting-started/installation"
|
|
498
|
+
"\n This includes other options e.g PyPI (pip/pipx), Homebrew, Docker.."
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
install_choice = Prompt.ask(
|
|
502
|
+
"\n> Would you like to install uv automatically now?",
|
|
503
|
+
choices=["y", "n"],
|
|
504
|
+
default="y",
|
|
505
|
+
)
|
|
506
|
+
if install_choice.lower() == "y":
|
|
507
|
+
console.print("> Installing uv...", style="yellow")
|
|
508
|
+
try:
|
|
509
|
+
install_command = "curl -LsSf https://astral.sh/uv/install.sh | sh"
|
|
510
|
+
# Add timeout to installation process as well
|
|
511
|
+
subprocess.run(
|
|
512
|
+
install_command,
|
|
513
|
+
shell=True,
|
|
514
|
+
check=True,
|
|
515
|
+
timeout=60 # Give installation more time
|
|
516
|
+
)
|
|
517
|
+
console.print("> uv installed successfully!", style="green")
|
|
518
|
+
except subprocess.TimeoutExpired:
|
|
519
|
+
console.print("> uv installation timed out", style="bold red")
|
|
520
|
+
raise
|
|
521
|
+
except subprocess.CalledProcessError as e:
|
|
522
|
+
console.print("> Failed to install uv", style="bold red")
|
|
523
|
+
logging.debug(f"uv installation error: {e!s}")
|
|
524
|
+
console.print(
|
|
525
|
+
"> Please install uv manually using one of the methods listed above",
|
|
526
|
+
style="yellow",
|
|
527
|
+
)
|
|
528
|
+
raise
|
|
529
|
+
else:
|
|
530
|
+
console.print(
|
|
531
|
+
"> Please install uv manually using one of the methods listed above and try again",
|
|
532
|
+
style="yellow",
|
|
533
|
+
)
|
|
534
|
+
raise click.Abort() from None
|