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,36 @@
|
|
|
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
|
+
variable "repository_owner" {
|
|
16
|
+
description = "Owner of the GitHub repository"
|
|
17
|
+
type = string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
variable "github_app_installation_id" {
|
|
21
|
+
description = "GitHub App Installation ID"
|
|
22
|
+
type = string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
variable "github_pat_secret_id" {
|
|
26
|
+
description = "GitHub PAT secret id in Cloud Secret Manager"
|
|
27
|
+
type = string
|
|
28
|
+
default = "github-pat"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
variable "connection_exists" {
|
|
32
|
+
description = "Flag indicating if a Cloud Build connection already exists"
|
|
33
|
+
type = bool
|
|
34
|
+
default = false
|
|
35
|
+
}
|
|
36
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
provider "github" {
|
|
16
|
+
token = data.google_secret_manager_secret_version.github_token.secret_data
|
|
17
|
+
owner = var.repository_owner
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
data "google_secret_manager_secret_version" "github_token" {
|
|
21
|
+
project = var.cicd_runner_project_id
|
|
22
|
+
secret = var.github_pat_secret_id
|
|
23
|
+
version = "latest"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Create the GitHub connection
|
|
27
|
+
resource "google_cloudbuildv2_connection" "github_connection" {
|
|
28
|
+
count = var.connection_exists ? 0 : 1
|
|
29
|
+
project = var.cicd_runner_project_id
|
|
30
|
+
location = var.region
|
|
31
|
+
name = var.host_connection_name
|
|
32
|
+
|
|
33
|
+
github_config {
|
|
34
|
+
app_installation_id = var.github_app_installation_id
|
|
35
|
+
authorizer_credential {
|
|
36
|
+
oauth_token_secret_version = "projects/${var.cicd_runner_project_id}/secrets/${var.github_pat_secret_id}/versions/latest"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
depends_on = [resource.google_project_service.cicd_services, resource.google_project_service.shared_services]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
locals {
|
|
43
|
+
connection_name = var.host_connection_name
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Try to get existing repo
|
|
48
|
+
data "github_repository" "existing_repo" {
|
|
49
|
+
full_name = "${var.repository_owner}/${var.repository_name}"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Only create GitHub repo if it doesn't already exist
|
|
53
|
+
resource "github_repository" "repo" {
|
|
54
|
+
count = data.github_repository.existing_repo.repo_id == null ? 1 : 0
|
|
55
|
+
name = var.repository_name
|
|
56
|
+
description = "Repository created by Terraform"
|
|
57
|
+
visibility = "private"
|
|
58
|
+
|
|
59
|
+
has_issues = true
|
|
60
|
+
has_wiki = false
|
|
61
|
+
has_projects = false
|
|
62
|
+
has_downloads = false
|
|
63
|
+
|
|
64
|
+
allow_merge_commit = true
|
|
65
|
+
allow_squash_merge = true
|
|
66
|
+
allow_rebase_merge = true
|
|
67
|
+
|
|
68
|
+
auto_init = false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
resource "google_cloudbuildv2_repository" "repo" {
|
|
73
|
+
project = var.cicd_runner_project_id
|
|
74
|
+
location = var.region
|
|
75
|
+
name = var.repository_name
|
|
76
|
+
|
|
77
|
+
parent_connection = "projects/${var.cicd_runner_project_id}/locations/${var.region}/connections/${local.connection_name}"
|
|
78
|
+
remote_uri = "https://github.com/${var.repository_owner}/${var.repository_name}.git"
|
|
79
|
+
depends_on = [
|
|
80
|
+
resource.google_project_service.cicd_services,
|
|
81
|
+
resource.google_project_service.shared_services,
|
|
82
|
+
data.github_repository.existing_repo,
|
|
83
|
+
github_repository.repo
|
|
84
|
+
]
|
|
85
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
terraform {
|
|
16
|
+
required_version = ">= 1.0.0"
|
|
17
|
+
required_providers {
|
|
18
|
+
google = {
|
|
19
|
+
source = "hashicorp/google"
|
|
20
|
+
version = "< 7.0.0"
|
|
21
|
+
}
|
|
22
|
+
github = {
|
|
23
|
+
source = "integrations/github"
|
|
24
|
+
version = "~> 6.5.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
provider "google" {
|
|
30
|
+
alias = "staging_billing_override"
|
|
31
|
+
billing_project = var.staging_project_id
|
|
32
|
+
user_project_override = true
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
provider "google" {
|
|
36
|
+
alias = "prod_billing_override"
|
|
37
|
+
billing_project = var.prod_project_id
|
|
38
|
+
user_project_override = true
|
|
39
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
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 script to generate lock files for all agent and deployment target combinations."""
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
import pathlib
|
|
20
|
+
import shutil
|
|
21
|
+
import subprocess
|
|
22
|
+
import tempfile
|
|
23
|
+
|
|
24
|
+
import click
|
|
25
|
+
from jinja2 import Template
|
|
26
|
+
from lock_utils import get_agent_configs, get_lock_filename
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def ensure_lock_dir() -> pathlib.Path:
|
|
30
|
+
"""Ensure the locks directory exists and is empty.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Path to the locks directory
|
|
34
|
+
"""
|
|
35
|
+
lock_dir = pathlib.Path("src/resources/locks")
|
|
36
|
+
|
|
37
|
+
# Remove if exists
|
|
38
|
+
if lock_dir.exists():
|
|
39
|
+
shutil.rmtree(lock_dir)
|
|
40
|
+
|
|
41
|
+
# Create fresh directory
|
|
42
|
+
lock_dir.mkdir(parents=True)
|
|
43
|
+
|
|
44
|
+
return lock_dir
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def generate_pyproject(
|
|
48
|
+
template_path: pathlib.Path, deployment_target: str, extra_dependencies: list[str]
|
|
49
|
+
) -> str:
|
|
50
|
+
"""Generate pyproject.toml content from template.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
template_path: Path to the pyproject.toml template
|
|
54
|
+
deployment_target: Target deployment platform
|
|
55
|
+
extra_dependencies: List of additional dependencies from .templateconfig.yaml
|
|
56
|
+
"""
|
|
57
|
+
with open(template_path, encoding="utf-8") as f:
|
|
58
|
+
template = Template(f.read(), trim_blocks=True, lstrip_blocks=True)
|
|
59
|
+
|
|
60
|
+
# Convert list to proper format for template
|
|
61
|
+
context = {
|
|
62
|
+
"cookiecutter": {
|
|
63
|
+
"project_name": "locked-template",
|
|
64
|
+
"deployment_target": deployment_target,
|
|
65
|
+
# Ensure extra_dependencies is a list
|
|
66
|
+
"extra_dependencies": list(extra_dependencies)
|
|
67
|
+
if extra_dependencies
|
|
68
|
+
else [],
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Add debug logging
|
|
73
|
+
logging.debug(f"Template context: {context}")
|
|
74
|
+
result = template.render(context)
|
|
75
|
+
logging.debug(f"Generated pyproject.toml:\n{result}")
|
|
76
|
+
|
|
77
|
+
return result
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def generate_lock_file(pyproject_content: str, output_path: pathlib.Path) -> None:
|
|
81
|
+
"""Generate uv.lock file from pyproject content."""
|
|
82
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
83
|
+
tmp_dir = pathlib.Path(tmpdir)
|
|
84
|
+
|
|
85
|
+
# Write temporary pyproject.toml
|
|
86
|
+
with open(tmp_dir / "pyproject.toml", "w", encoding="utf-8") as f:
|
|
87
|
+
f.write(pyproject_content)
|
|
88
|
+
|
|
89
|
+
# Run uv pip compile to generate lock file
|
|
90
|
+
subprocess.run(["uv", "lock"], cwd=tmp_dir, check=True)
|
|
91
|
+
# Replace locked-template with {{cookiecutter.project_name}} in generated lock file
|
|
92
|
+
lock_file_path = tmp_dir / "uv.lock"
|
|
93
|
+
with open(lock_file_path, "r+", encoding="utf-8") as f:
|
|
94
|
+
lock_content = f.read()
|
|
95
|
+
f.seek(0)
|
|
96
|
+
f.write(
|
|
97
|
+
lock_content.replace("locked-template", "{{cookiecutter.project_name}}")
|
|
98
|
+
)
|
|
99
|
+
f.truncate()
|
|
100
|
+
|
|
101
|
+
# Copy the generated lock file to output location
|
|
102
|
+
shutil.copy2(lock_file_path, output_path)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@click.command()
|
|
106
|
+
@click.option(
|
|
107
|
+
"--template",
|
|
108
|
+
type=click.Path(exists=True, path_type=pathlib.Path),
|
|
109
|
+
default="src/base_template/pyproject.toml",
|
|
110
|
+
help="Path to template pyproject.toml",
|
|
111
|
+
)
|
|
112
|
+
def main(template: pathlib.Path) -> None:
|
|
113
|
+
"""Generate lock files for all agent and deployment target combinations."""
|
|
114
|
+
lock_dir = ensure_lock_dir()
|
|
115
|
+
agent_configs = get_agent_configs()
|
|
116
|
+
|
|
117
|
+
for agent_name, config in agent_configs.items():
|
|
118
|
+
for target in config.targets:
|
|
119
|
+
print(f"Generating lock file for {agent_name} with {target}...")
|
|
120
|
+
|
|
121
|
+
# Generate pyproject content
|
|
122
|
+
content = generate_pyproject(
|
|
123
|
+
template,
|
|
124
|
+
deployment_target=target,
|
|
125
|
+
extra_dependencies=config.dependencies,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Generate lock file
|
|
129
|
+
output_path = lock_dir / get_lock_filename(agent_name, target)
|
|
130
|
+
generate_lock_file(content, output_path)
|
|
131
|
+
print(f"Generated {output_path}")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
if __name__ == "__main__":
|
|
135
|
+
main()
|
src/utils/lock_utils.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
"""Utilities for managing Poetry lock files and dependencies."""
|
|
16
|
+
|
|
17
|
+
import pathlib
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import NamedTuple
|
|
20
|
+
|
|
21
|
+
import yaml
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AgentConfig(NamedTuple):
|
|
25
|
+
"""Configuration for an agent template."""
|
|
26
|
+
|
|
27
|
+
targets: set[str]
|
|
28
|
+
dependencies: list[str]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_agent_configs(
|
|
32
|
+
agents_dir: pathlib.Path = pathlib.Path("agents"),
|
|
33
|
+
) -> dict[str, AgentConfig]:
|
|
34
|
+
"""Get all agents and their supported deployment targets.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
agents_dir: Path to the agents directory
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Dictionary mapping agent names to their configuration
|
|
41
|
+
"""
|
|
42
|
+
agent_configs = {}
|
|
43
|
+
|
|
44
|
+
for agent_dir in agents_dir.iterdir():
|
|
45
|
+
if not agent_dir.is_dir():
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
config_file = agent_dir / "template" / ".templateconfig.yaml"
|
|
49
|
+
if not config_file.exists():
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
with open(config_file, encoding="utf-8") as f:
|
|
53
|
+
config = yaml.safe_load(f)
|
|
54
|
+
|
|
55
|
+
agent_name = agent_dir.name
|
|
56
|
+
settings = config.get("settings", {})
|
|
57
|
+
|
|
58
|
+
agent_configs[agent_name] = AgentConfig(
|
|
59
|
+
targets=set(settings.get("deployment_targets", [])),
|
|
60
|
+
dependencies=settings.get("extra_dependencies", []),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return agent_configs
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_lock_filename(agent_name: str, deployment_target: str) -> str:
|
|
67
|
+
"""Generate the lock filename for a given agent and deployment target.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
agent_name: Name of the agent
|
|
71
|
+
deployment_target: Target deployment platform
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Formatted lock filename
|
|
75
|
+
"""
|
|
76
|
+
return f"uv-{agent_name}-{deployment_target}.lock"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_lock_path(agent_name: str, deployment_target: str) -> Path:
|
|
80
|
+
"""Get the path to the appropriate lock file."""
|
|
81
|
+
lock_filename = get_lock_filename(agent_name, deployment_target)
|
|
82
|
+
return Path("src/resources/locks") / lock_filename
|
|
@@ -0,0 +1,190 @@
|
|
|
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 shutil
|
|
18
|
+
import subprocess
|
|
19
|
+
import time
|
|
20
|
+
|
|
21
|
+
import click
|
|
22
|
+
from rich.console import Console
|
|
23
|
+
from watchdog.events import FileSystemEventHandler
|
|
24
|
+
from watchdog.observers import Observer
|
|
25
|
+
|
|
26
|
+
console = Console()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TemplateHandler(FileSystemEventHandler):
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
agent_name: str,
|
|
33
|
+
project_name: str,
|
|
34
|
+
deployment_target: str,
|
|
35
|
+
output_dir: str | None,
|
|
36
|
+
region: str,
|
|
37
|
+
):
|
|
38
|
+
self.agent_name = agent_name
|
|
39
|
+
self.project_name = project_name
|
|
40
|
+
self.deployment_target = deployment_target
|
|
41
|
+
self.output_dir = output_dir
|
|
42
|
+
self.region = region
|
|
43
|
+
self.last_rebuild = 0
|
|
44
|
+
self.rebuild_cooldown = 1 # Seconds to wait between rebuilds
|
|
45
|
+
|
|
46
|
+
def on_modified(self, event):
|
|
47
|
+
if event.is_directory:
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
# Implement cooldown to prevent multiple rapid rebuilds
|
|
51
|
+
current_time = time.time()
|
|
52
|
+
if current_time - self.last_rebuild < self.rebuild_cooldown:
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
self.last_rebuild = current_time
|
|
56
|
+
|
|
57
|
+
console.print(f"Detected change in {event.src_path}")
|
|
58
|
+
self.rebuild_template()
|
|
59
|
+
|
|
60
|
+
def rebuild_template(self):
|
|
61
|
+
try:
|
|
62
|
+
# Clean output directory
|
|
63
|
+
project_path = (
|
|
64
|
+
pathlib.Path(self.output_dir) / self.project_name
|
|
65
|
+
if self.output_dir
|
|
66
|
+
else pathlib.Path(self.project_name)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Check if the project directory exists and remove it
|
|
70
|
+
if project_path.exists():
|
|
71
|
+
console.print(
|
|
72
|
+
f"Removing existing directory: {project_path}", style="yellow"
|
|
73
|
+
)
|
|
74
|
+
shutil.rmtree(project_path)
|
|
75
|
+
|
|
76
|
+
# Rebuild using the CLI tool with agent and deployment target
|
|
77
|
+
cmd = [
|
|
78
|
+
"uv",
|
|
79
|
+
"run",
|
|
80
|
+
"-m",
|
|
81
|
+
"src.cli.main",
|
|
82
|
+
"create",
|
|
83
|
+
str(self.project_name),
|
|
84
|
+
"--agent",
|
|
85
|
+
self.agent_name,
|
|
86
|
+
"--deployment-target",
|
|
87
|
+
self.deployment_target,
|
|
88
|
+
"--output-dir",
|
|
89
|
+
str(self.output_dir) if self.output_dir else ".",
|
|
90
|
+
"--auto-approve",
|
|
91
|
+
"--region",
|
|
92
|
+
self.region,
|
|
93
|
+
]
|
|
94
|
+
console.print(f"Executing: {' '.join(cmd)}", style="bold blue")
|
|
95
|
+
subprocess.run(cmd, check=True)
|
|
96
|
+
|
|
97
|
+
console.print("✨ Template rebuilt successfully!", style="bold green")
|
|
98
|
+
|
|
99
|
+
except subprocess.CalledProcessError as e:
|
|
100
|
+
console.print(f"Error rebuilding template: {e}", style="bold red")
|
|
101
|
+
except Exception as e:
|
|
102
|
+
console.print(f"Unexpected error: {e}", style="bold red")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@click.command()
|
|
106
|
+
@click.argument("agent")
|
|
107
|
+
@click.argument("project_name")
|
|
108
|
+
@click.option("--deployment-target", "-d", help="Deployment target to use")
|
|
109
|
+
@click.option(
|
|
110
|
+
"--output-dir",
|
|
111
|
+
"-o",
|
|
112
|
+
type=click.Path(),
|
|
113
|
+
default="target",
|
|
114
|
+
help="Output directory for the project",
|
|
115
|
+
)
|
|
116
|
+
@click.option("--debug", is_flag=True, help="Enable debug logging")
|
|
117
|
+
@click.option("--region", default="us-central1", help="GCP region to use")
|
|
118
|
+
def watch(
|
|
119
|
+
agent: str,
|
|
120
|
+
project_name: str,
|
|
121
|
+
deployment_target: str,
|
|
122
|
+
output_dir: str | None,
|
|
123
|
+
debug: bool,
|
|
124
|
+
region: str,
|
|
125
|
+
):
|
|
126
|
+
"""
|
|
127
|
+
Watch a agent's template and automatically rebuild when changes are detected.
|
|
128
|
+
|
|
129
|
+
agent: Name of the agent to watch (e.g., langgraph_base_react)
|
|
130
|
+
PROJECT_NAME: Name of the project to generate
|
|
131
|
+
"""
|
|
132
|
+
if debug:
|
|
133
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
134
|
+
|
|
135
|
+
# Get directories to watch
|
|
136
|
+
root_dir = pathlib.Path(__file__).parent.parent.parent.resolve()
|
|
137
|
+
src_dir = root_dir / "src"
|
|
138
|
+
agents_dir = root_dir / "agents"
|
|
139
|
+
|
|
140
|
+
if not agents_dir.exists():
|
|
141
|
+
raise click.BadParameter(f"agents directory not found: {agents_dir}")
|
|
142
|
+
|
|
143
|
+
if not src_dir.exists():
|
|
144
|
+
raise click.BadParameter(f"Source directory not found: {src_dir}")
|
|
145
|
+
|
|
146
|
+
# Create output directory if it doesn't exist
|
|
147
|
+
if output_dir:
|
|
148
|
+
output_path = pathlib.Path(output_dir)
|
|
149
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
150
|
+
console.print(f"Using output directory: {output_path}")
|
|
151
|
+
|
|
152
|
+
console.print(f"Watching agent: {agent}")
|
|
153
|
+
console.print(f"Deployment target: {deployment_target}")
|
|
154
|
+
console.print(f"Source directory: {src_dir}")
|
|
155
|
+
console.print(f"agents directory: {agents_dir}")
|
|
156
|
+
console.print(f"Project name: {project_name}")
|
|
157
|
+
console.print(f"Region: {region}")
|
|
158
|
+
|
|
159
|
+
event_handler = TemplateHandler(
|
|
160
|
+
agent_name=agent,
|
|
161
|
+
project_name=project_name,
|
|
162
|
+
deployment_target=deployment_target,
|
|
163
|
+
output_dir=output_dir,
|
|
164
|
+
region=region,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
observer = Observer()
|
|
168
|
+
# Watch both src and agents directories
|
|
169
|
+
observer.schedule(event_handler, str(src_dir), recursive=True)
|
|
170
|
+
observer.schedule(event_handler, str(agents_dir), recursive=True)
|
|
171
|
+
observer.start()
|
|
172
|
+
|
|
173
|
+
try:
|
|
174
|
+
# Trigger initial build
|
|
175
|
+
console.print("\n🏗️ Performing initial build...", style="bold blue")
|
|
176
|
+
event_handler.rebuild_template()
|
|
177
|
+
|
|
178
|
+
console.print(
|
|
179
|
+
"\n🔍 Watching for changes (Press Ctrl+C to stop)...", style="bold blue"
|
|
180
|
+
)
|
|
181
|
+
while True:
|
|
182
|
+
time.sleep(1)
|
|
183
|
+
except KeyboardInterrupt:
|
|
184
|
+
console.print("\n⏹️ Stopping watch...", style="bold yellow")
|
|
185
|
+
observer.stop()
|
|
186
|
+
observer.join()
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
if __name__ == "__main__":
|
|
190
|
+
watch()
|