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,91 @@
|
|
|
1
|
+
# {{cookiecutter.project_name}}
|
|
2
|
+
|
|
3
|
+
{{cookiecutter.agent_description}}
|
|
4
|
+
|
|
5
|
+
Template generated with `googleCloudPlatform/agent-starter-pack`
|
|
6
|
+
|
|
7
|
+
## Project Structure
|
|
8
|
+
|
|
9
|
+
This project is organized as follows:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
{{cookiecutter.project_name}}/
|
|
13
|
+
├── app/ # Core application code
|
|
14
|
+
│ ├── agent.py # Main agent logic
|
|
15
|
+
│ ├── agent_engine_app.py # Agent Engine application logic
|
|
16
|
+
│ └── utils/ # Utility functions and helpers
|
|
17
|
+
├── deployment/ # Infrastructure and deployment scripts
|
|
18
|
+
├── notebooks/ # Jupyter notebooks for prototyping and evaluation
|
|
19
|
+
├── tests/ # Unit, integration, and load tests
|
|
20
|
+
├── Makefile # Makefile for common commands
|
|
21
|
+
└── pyproject.toml # Project dependencies and configuration
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Installation
|
|
26
|
+
|
|
27
|
+
Install required packages using uv:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv sync --extra jupyter --extra streamlit --frozen
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Setup
|
|
34
|
+
|
|
35
|
+
If not done during the initialization, set your default Google Cloud project and Location:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
export PROJECT_ID="YOUR_PROJECT_ID"
|
|
39
|
+
export LOCATION="us-central1"
|
|
40
|
+
gcloud config set project $PROJECT_ID
|
|
41
|
+
gcloud auth application-default login
|
|
42
|
+
gcloud auth application-default set-quota-project $PROJECT_ID
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Commands
|
|
46
|
+
|
|
47
|
+
| Command | Description |
|
|
48
|
+
| -------------------- | ------------------------------------------------------------------------------------------- |
|
|
49
|
+
{%- if cookiecutter.deployment_target == 'cloud_run' %}
|
|
50
|
+
| `make playground` | Launch local development environment with backend and frontend |
|
|
51
|
+
| `make backend` | Start backend server only |
|
|
52
|
+
| `make ui` | Launch Streamlit frontend without local backend |
|
|
53
|
+
{%- elif cookiecutter.deployment_target == 'agent_engine' %}
|
|
54
|
+
| `make playground` | Launch Streamlit interface for testing agent locally and remotely |
|
|
55
|
+
| `make backend` | Deploy agent to Agent Engine service |
|
|
56
|
+
{%- endif %}
|
|
57
|
+
| `make test` | Run unit and integration tests |
|
|
58
|
+
| `uv run jupyter lab` | Launch Jupyter notebook |
|
|
59
|
+
|
|
60
|
+
For full command options and usage, refer to the [Makefile](Makefile).
|
|
61
|
+
|
|
62
|
+
## Usage
|
|
63
|
+
1. **Prototype:** Build your Generative AI Agent using the intro notebooks in `notebooks/` for guidance. Use Vertex AI Evaluation to assess performance.
|
|
64
|
+
2. **Integrate:** Import your chain into the app by editing `app/agent.py`.
|
|
65
|
+
3. **Test:** Explore your chain's functionality using the Streamlit playground with `make playground`. The playground offers features like chat history, user feedback, and various input types, and automatically reloads your agent on code changes.
|
|
66
|
+
4. **Deploy:** Configure and trigger the CI/CD pipelines, editing tests if needed. See the [deployment section](#deployment) for details.
|
|
67
|
+
5. **Monitor:** Track performance and gather insights using Cloud Logging, Tracing, and the Looker Studio dashboard to iterate on your application.
|
|
68
|
+
|
|
69
|
+
## Deployment
|
|
70
|
+
|
|
71
|
+
### Dev Environment
|
|
72
|
+
|
|
73
|
+
You can test deployment towards a Dev Environment using the following command:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
gcloud config set project <your-dev-project-id>
|
|
77
|
+
make backend
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The repository includes a Terraform configuration for the setup of the Dev Google Cloud project.
|
|
81
|
+
See [deployment/README.md](deployment/README.md) for instructions.
|
|
82
|
+
|
|
83
|
+
### Production Deployment
|
|
84
|
+
|
|
85
|
+
The repository includes a Terraform configuration for the setup of a production Google Cloud project. Refer to [deployment/README.md](deployment/README.md) for detailed instructions on how to deploy the infrastructure and application.
|
|
86
|
+
|
|
87
|
+
## Monitoring and Observability
|
|
88
|
+
|
|
89
|
+
>> You can use [this Looker Studio dashboard](https://lookerstudio.google.com/c/reporting/fa742264-4b4b-4c56-81e6-a667dd0f853f/page/tEnnC) template for visualizing events being logged in BigQuery. See the "Setup Instructions" tab to getting started.
|
|
90
|
+
|
|
91
|
+
The application uses OpenTelemetry for comprehensive observability with all events being sent to Google Cloud Trace and Logging for monitoring and to BigQuery for long term storage.
|
|
@@ -0,0 +1,143 @@
|
|
|
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 json
|
|
16
|
+
import logging
|
|
17
|
+
from collections.abc import Sequence
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from google.cloud import logging as google_cloud_logging
|
|
21
|
+
from google.cloud import storage
|
|
22
|
+
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
|
|
23
|
+
from opentelemetry.sdk.trace import ReadableSpan
|
|
24
|
+
from opentelemetry.sdk.trace.export import SpanExportResult
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CloudTraceLoggingSpanExporter(CloudTraceSpanExporter):
|
|
28
|
+
"""
|
|
29
|
+
An extended version of CloudTraceSpanExporter that logs span data to Google Cloud Logging
|
|
30
|
+
and handles large attribute values by storing them in Google Cloud Storage.
|
|
31
|
+
|
|
32
|
+
This class helps bypass the 256 character limit of Cloud Trace for attribute values
|
|
33
|
+
by leveraging Cloud Logging (which has a 256KB limit) and Cloud Storage for larger payloads.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
logging_client: google_cloud_logging.Client | None = None,
|
|
39
|
+
storage_client: storage.Client | None = None,
|
|
40
|
+
bucket_name: str | None = None,
|
|
41
|
+
debug: bool = False,
|
|
42
|
+
**kwargs: Any,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""
|
|
45
|
+
Initialize the exporter with Google Cloud clients and configuration.
|
|
46
|
+
|
|
47
|
+
:param logging_client: Google Cloud Logging client
|
|
48
|
+
:param storage_client: Google Cloud Storage client
|
|
49
|
+
:param bucket_name: Name of the GCS bucket to store large payloads
|
|
50
|
+
:param debug: Enable debug mode for additional logging
|
|
51
|
+
:param kwargs: Additional arguments to pass to the parent class
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(**kwargs)
|
|
54
|
+
self.debug = debug
|
|
55
|
+
self.logging_client = logging_client or google_cloud_logging.Client(
|
|
56
|
+
project=self.project_id
|
|
57
|
+
)
|
|
58
|
+
self.logger = self.logging_client.logger(__name__)
|
|
59
|
+
self.storage_client = storage_client or storage.Client(project=self.project_id)
|
|
60
|
+
self.bucket_name = bucket_name or f"{self.project_id}-logs-data"
|
|
61
|
+
self.bucket = self.storage_client.bucket(self.bucket_name)
|
|
62
|
+
|
|
63
|
+
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
|
|
64
|
+
"""
|
|
65
|
+
Export the spans to Google Cloud Logging and Cloud Trace.
|
|
66
|
+
|
|
67
|
+
:param spans: A sequence of spans to export
|
|
68
|
+
:return: The result of the export operation
|
|
69
|
+
"""
|
|
70
|
+
for span in spans:
|
|
71
|
+
span_context = span.get_span_context()
|
|
72
|
+
trace_id = format(span_context.trace_id, "x")
|
|
73
|
+
span_id = format(span_context.span_id, "x")
|
|
74
|
+
span_dict = json.loads(span.to_json())
|
|
75
|
+
|
|
76
|
+
span_dict["trace"] = f"projects/{self.project_id}/traces/{trace_id}"
|
|
77
|
+
span_dict["span_id"] = span_id
|
|
78
|
+
|
|
79
|
+
span_dict = self._process_large_attributes(
|
|
80
|
+
span_dict=span_dict, span_id=span_id
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if self.debug:
|
|
84
|
+
print(span_dict)
|
|
85
|
+
|
|
86
|
+
# Log the span data to Google Cloud Logging
|
|
87
|
+
self.logger.log_struct(span_dict, severity="INFO")
|
|
88
|
+
|
|
89
|
+
# Export spans to Google Cloud Trace using the parent class method
|
|
90
|
+
return super().export(spans)
|
|
91
|
+
|
|
92
|
+
def store_in_gcs(self, content: str, span_id: str) -> str:
|
|
93
|
+
"""
|
|
94
|
+
Initiate storing large content in Google Cloud Storage/
|
|
95
|
+
|
|
96
|
+
:param content: The content to store
|
|
97
|
+
:param span_id: The ID of the span
|
|
98
|
+
:return: The GCS URI of the stored content
|
|
99
|
+
"""
|
|
100
|
+
if not self.storage_client.bucket(self.bucket_name).exists():
|
|
101
|
+
logging.warning(
|
|
102
|
+
f"Bucket {self.bucket_name} not found. "
|
|
103
|
+
"Unable to store span attributes in GCS."
|
|
104
|
+
)
|
|
105
|
+
return "GCS bucket not found"
|
|
106
|
+
|
|
107
|
+
blob_name = f"spans/{span_id}.json"
|
|
108
|
+
blob = self.bucket.blob(blob_name)
|
|
109
|
+
|
|
110
|
+
blob.upload_from_string(content, "application/json")
|
|
111
|
+
return f"gs://{self.bucket_name}/{blob_name}"
|
|
112
|
+
|
|
113
|
+
def _process_large_attributes(self, span_dict: dict, span_id: str) -> dict:
|
|
114
|
+
"""
|
|
115
|
+
Process large attribute values by storing them in GCS if they exceed the size
|
|
116
|
+
limit of Google Cloud Logging.
|
|
117
|
+
|
|
118
|
+
:param span_dict: The span data dictionary
|
|
119
|
+
:param trace_id: The trace ID
|
|
120
|
+
:param span_id: The span ID
|
|
121
|
+
:return: The updated span dictionary
|
|
122
|
+
"""
|
|
123
|
+
attributes = span_dict["attributes"]
|
|
124
|
+
if len(json.dumps(attributes).encode()) > 255 * 1024: # 250 KB
|
|
125
|
+
# Separate large payload from other attributes
|
|
126
|
+
attributes_payload = dict(attributes.items())
|
|
127
|
+
attributes_retain = dict(attributes.items())
|
|
128
|
+
|
|
129
|
+
# Store large payload in GCS
|
|
130
|
+
gcs_uri = self.store_in_gcs(json.dumps(attributes_payload), span_id)
|
|
131
|
+
attributes_retain["uri_payload"] = gcs_uri
|
|
132
|
+
attributes_retain["url_payload"] = (
|
|
133
|
+
f"https://storage.mtls.cloud.google.com/"
|
|
134
|
+
f"{self.bucket_name}/spans/{span_id}.json"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
span_dict["attributes"] = attributes_retain
|
|
138
|
+
logging.info(
|
|
139
|
+
"Length of payload span above 250 KB, storing attributes in GCS "
|
|
140
|
+
"to avoid large log entry errors"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return span_dict
|
|
@@ -0,0 +1,115 @@
|
|
|
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 json
|
|
16
|
+
import uuid
|
|
17
|
+
from typing import (
|
|
18
|
+
Annotated,
|
|
19
|
+
Any,
|
|
20
|
+
Literal,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from langchain_core.load.serializable import Serializable
|
|
24
|
+
from langchain_core.messages import (
|
|
25
|
+
AIMessage,
|
|
26
|
+
HumanMessage,
|
|
27
|
+
ToolMessage,
|
|
28
|
+
)
|
|
29
|
+
from langchain_core.runnables import RunnableConfig
|
|
30
|
+
from pydantic import (
|
|
31
|
+
BaseModel,
|
|
32
|
+
Field,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class InputChat(BaseModel):
|
|
37
|
+
"""Represents the input for a chat session."""
|
|
38
|
+
|
|
39
|
+
messages: list[
|
|
40
|
+
Annotated[HumanMessage | AIMessage | ToolMessage, Field(discriminator="type")]
|
|
41
|
+
] = Field(
|
|
42
|
+
..., description="The chat messages representing the current conversation."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
{% if cookiecutter.deployment_target == 'cloud_run' %}
|
|
46
|
+
class Request(BaseModel):
|
|
47
|
+
"""Represents the input for a chat request with optional configuration.
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
input: The chat input containing messages and other chat-related data
|
|
51
|
+
config: Optional configuration for the runnable, including tags, callbacks, etc.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
input: InputChat
|
|
55
|
+
config: RunnableConfig | None = None
|
|
56
|
+
|
|
57
|
+
{% endif %}
|
|
58
|
+
class Feedback(BaseModel):
|
|
59
|
+
"""Represents feedback for a conversation."""
|
|
60
|
+
|
|
61
|
+
score: int | float
|
|
62
|
+
text: str | None = ""
|
|
63
|
+
run_id: str
|
|
64
|
+
log_type: Literal["feedback"] = "feedback"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def ensure_valid_config(config: RunnableConfig | None) -> RunnableConfig:
|
|
68
|
+
"""Ensures a valid RunnableConfig by setting defaults for missing fields."""
|
|
69
|
+
if config is None:
|
|
70
|
+
config = RunnableConfig()
|
|
71
|
+
if config.get("run_id") is None:
|
|
72
|
+
config["run_id"] = uuid.uuid4()
|
|
73
|
+
if config.get("metadata") is None:
|
|
74
|
+
config["metadata"] = {}
|
|
75
|
+
return config
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def default_serialization(obj: Any) -> Any:
|
|
79
|
+
"""
|
|
80
|
+
Default serialization for LangChain objects.
|
|
81
|
+
Converts BaseModel instances to JSON strings.
|
|
82
|
+
"""
|
|
83
|
+
if isinstance(obj, Serializable):
|
|
84
|
+
return obj.to_json()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def dumps(obj: Any) -> str:
|
|
88
|
+
"""
|
|
89
|
+
Serialize an object to a JSON string.
|
|
90
|
+
|
|
91
|
+
For LangChain objects (BaseModel instances), it converts them to
|
|
92
|
+
dictionaries before serialization.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
obj: The object to serialize
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
JSON string representation of the object
|
|
99
|
+
"""
|
|
100
|
+
return json.dumps(obj, default=default_serialization)
|
|
101
|
+
{% if cookiecutter.deployment_target == 'agent_engine' %}
|
|
102
|
+
|
|
103
|
+
def dumpd(obj: Any) -> Any:
|
|
104
|
+
"""
|
|
105
|
+
Convert an object to a JSON-serializable dict.
|
|
106
|
+
Uses default_serialization for handling BaseModel instances.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
obj: The object to convert
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Dict/list representation of the object that can be JSON serialized
|
|
113
|
+
"""
|
|
114
|
+
return json.loads(dumps(obj))
|
|
115
|
+
{% endif %}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Deployment README.md
|
|
2
|
+
|
|
3
|
+
This folder contains the infrastructure-as-code and CI/CD pipeline configurations for deploying a conversational Generative AI application on Google Cloud.
|
|
4
|
+
|
|
5
|
+
The application leverages [**Terraform**](http://terraform.io) to define and provision the underlying infrastructure, while [**Cloud Build**](https://cloud.google.com/build/) orchestrates the continuous integration and continuous deployment (CI/CD) pipeline.
|
|
6
|
+
|
|
7
|
+
## Deployment Workflow
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
**Description:**
|
|
12
|
+
|
|
13
|
+
1. CI Pipeline (`deployment/ci/pr_checks.yaml`):
|
|
14
|
+
|
|
15
|
+
- Triggered on pull request creation/update
|
|
16
|
+
- Runs unit and integration tests
|
|
17
|
+
|
|
18
|
+
2. CD Pipeline (`deployment/cd/staging.yaml`):
|
|
19
|
+
|
|
20
|
+
- Triggered on merge to `main` branch
|
|
21
|
+
- Builds and pushes application to Artifact Registry
|
|
22
|
+
- Deploys to staging environment
|
|
23
|
+
- Performs load testing
|
|
24
|
+
|
|
25
|
+
3. Production Deployment (`deployment/cd/deploy-to-prod.yaml`):
|
|
26
|
+
- Triggered after successful staging deployment
|
|
27
|
+
- Requires manual approval
|
|
28
|
+
- Deploys to production environment
|
|
29
|
+
|
|
30
|
+
## Setup
|
|
31
|
+
|
|
32
|
+
**Prerequisites:**
|
|
33
|
+
|
|
34
|
+
1. A set of Google Cloud projects:
|
|
35
|
+
- Staging project
|
|
36
|
+
- Production project
|
|
37
|
+
- CI/CD project (can be the same as staging or production)
|
|
38
|
+
2. Terraform installed on your local machine
|
|
39
|
+
3. Enable required APIs in the CI/CD project. This will be required for the Terraform deployment:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
gcloud config set project $YOUR_CI_CD_PROJECT_ID
|
|
43
|
+
gcloud services enable serviceusage.googleapis.com cloudresourcemanager.googleapis.com cloudbuild.googleapis.com secretmanager.googleapis.com
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Step-by-Step Guide
|
|
47
|
+
|
|
48
|
+
1. **Create a Git Repository using your favorite Git provider (GitHub, GitLab, Bitbucket, etc.)**
|
|
49
|
+
|
|
50
|
+
2. **Connect Your Repository to Cloud Build**
|
|
51
|
+
For detailed instructions, visit: [Cloud Build Repository Setup](https://cloud.google.com/build/docs/repositories#whats_next).<br>
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
3. **Configure Terraform Variables**
|
|
56
|
+
|
|
57
|
+
- Edit [`deployment/terraform/vars/env.tfvars`](../terraform/vars/env.tfvars) with your Google Cloud settings.
|
|
58
|
+
|
|
59
|
+
| Variable | Description | Required |
|
|
60
|
+
| ---------------------- | --------------------------------------------------------------- | :------: |
|
|
61
|
+
| prod_project_id | **Production** Google Cloud Project ID for resource deployment. | Yes |
|
|
62
|
+
| staging_project_id | **Staging** Google Cloud Project ID for resource deployment. | Yes |
|
|
63
|
+
| cicd_runner_project_id | Google Cloud Project ID where CI/CD pipelines will execute. | Yes |
|
|
64
|
+
| region | Google Cloud region for resource deployment. | Yes |
|
|
65
|
+
| host_connection_name | Name of the host connection you created in Cloud Build | Yes |
|
|
66
|
+
| repository_name | Name of the repository you added to Cloud Build | Yes |
|
|
67
|
+
|
|
68
|
+
Other optional variables include: telemetry and feedback BigQuery dataset IDs, log filters, sink names, service account names, bucket name suffixes, artifact registry repository name, and various role assignments.
|
|
69
|
+
|
|
70
|
+
4. **Deploy Infrastructure with Terraform**
|
|
71
|
+
|
|
72
|
+
- Open a terminal and navigate to the Terraform directory:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cd deployment/terraform
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
- Initialize Terraform:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
terraform init
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- Apply the Terraform configuration:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
terraform apply --var-file vars/env.tfvars
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- Type 'yes' when prompted to confirm
|
|
91
|
+
|
|
92
|
+
After completing these steps, your infrastructure will be set up and ready for deployment!
|
|
93
|
+
|
|
94
|
+
## Dev Deployment
|
|
95
|
+
|
|
96
|
+
For End-to-end testing of the application, including tracing and feedback sinking to BigQuery, without the need to trigger a CI/CD pipeline.
|
|
97
|
+
|
|
98
|
+
First, enable required Google Cloud APIs:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
gcloud config set project <your-dev-project-id>
|
|
102
|
+
gcloud services enable serviceusage.googleapis.com cloudresourcemanager.googleapis.com
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
After you edited the relative [`env.tfvars` file](../terraform/dev/vars/env.tfvars), follow the following instructions:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
cd deployment/terraform/dev
|
|
109
|
+
terraform init
|
|
110
|
+
terraform apply --var-file vars/env.tfvars
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Then deploy the application using the following command (from the root of the repository):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
make backend
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### End-to-end Demo video
|
|
120
|
+
|
|
121
|
+
<a href="https://storage.googleapis.com/github-repo/generative-ai/sample-apps/e2e-gen-ai-app-starter-pack/template_deployment_demo.mp4">
|
|
122
|
+
<img src="https://storage.googleapis.com/github-repo/generative-ai/sample-apps/e2e-gen-ai-app-starter-pack/preview_video.png" alt="Watch the video" width="300"/>
|
|
123
|
+
</a>
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
steps:
|
|
16
|
+
{%- if cookiecutter.data_ingestion %}
|
|
17
|
+
- name: "python:3.11"
|
|
18
|
+
id: deploy-data-ingestion-pipeline-prod
|
|
19
|
+
entrypoint: bash
|
|
20
|
+
args:
|
|
21
|
+
- -c
|
|
22
|
+
- |
|
|
23
|
+
cd data_ingestion && pip install uv --user && uv sync --frozen && \
|
|
24
|
+
uv run python data_ingestion_pipeline/submit_pipeline.py
|
|
25
|
+
env:
|
|
26
|
+
- "PIPELINE_ROOT=${_PIPELINE_GCS_ROOT}"
|
|
27
|
+
- "REGION=${_REGION}"
|
|
28
|
+
- "DATA_STORE_REGION=${_DATA_STORE_REGION}"
|
|
29
|
+
- "DATA_STORE_ID=${_DATA_STORE_ID}"
|
|
30
|
+
- "PROJECT_ID=${_PROD_PROJECT_ID}"
|
|
31
|
+
- "SERVICE_ACCOUNT=${_PIPELINE_SA_EMAIL}"
|
|
32
|
+
- "PIPELINE_NAME=${_PIPELINE_NAME}"
|
|
33
|
+
- "CRON_SCHEDULE=${_PIPELINE_CRON_SCHEDULE}"
|
|
34
|
+
- "DISABLE_CACHING=TRUE"
|
|
35
|
+
- 'PATH=/usr/local/bin:/usr/bin:~/.local/bin'
|
|
36
|
+
{%- endif %}
|
|
37
|
+
{%- if cookiecutter.deployment_target == 'cloud_run' %}
|
|
38
|
+
|
|
39
|
+
- name: "gcr.io/cloud-builders/gcloud"
|
|
40
|
+
id: trigger-deployment
|
|
41
|
+
entrypoint: gcloud
|
|
42
|
+
args:
|
|
43
|
+
- "run"
|
|
44
|
+
- "deploy"
|
|
45
|
+
- "{{cookiecutter.project_name}}"
|
|
46
|
+
- "--image"
|
|
47
|
+
- "$_REGION-docker.pkg.dev/$PROJECT_ID/$_ARTIFACT_REGISTRY_REPO_NAME/$_CONTAINER_NAME"
|
|
48
|
+
- "--region"
|
|
49
|
+
- "$_REGION"
|
|
50
|
+
- "--project"
|
|
51
|
+
- $_PROD_PROJECT_ID
|
|
52
|
+
- "--min-instances"
|
|
53
|
+
- "1"
|
|
54
|
+
- "--no-cpu-throttling"
|
|
55
|
+
- "--cpu"
|
|
56
|
+
- "4"
|
|
57
|
+
- "--memory"
|
|
58
|
+
- "4Gi"
|
|
59
|
+
- "--concurrency"
|
|
60
|
+
- "40"
|
|
61
|
+
- "--service-account"
|
|
62
|
+
- "${_CLOUD_RUN_APP_SA_NAME}@${_PROD_PROJECT_ID}.iam.gserviceaccount.com"
|
|
63
|
+
- "--set-env-vars"
|
|
64
|
+
- "COMMIT_SHA=${COMMIT_SHA}{%- if cookiecutter.data_ingestion %},DATA_STORE_ID=${_DATA_STORE_ID},DATA_STORE_REGION=${_DATA_STORE_REGION}{%- endif %}"
|
|
65
|
+
{%- elif cookiecutter.deployment_target == 'agent_engine' %}
|
|
66
|
+
- name: "python:3.11"
|
|
67
|
+
id: install-dependencies
|
|
68
|
+
entrypoint: /bin/bash
|
|
69
|
+
args:
|
|
70
|
+
- "-c"
|
|
71
|
+
- |
|
|
72
|
+
pip install uv --user && uv sync --frozen
|
|
73
|
+
env:
|
|
74
|
+
- 'PATH=/usr/local/bin:/usr/bin:~/.local/bin'
|
|
75
|
+
|
|
76
|
+
- name: "python:3.11"
|
|
77
|
+
id: trigger-deployment
|
|
78
|
+
entrypoint: /bin/bash
|
|
79
|
+
args:
|
|
80
|
+
- "-c"
|
|
81
|
+
- |
|
|
82
|
+
uv export --no-hashes --no-sources --no-header --no-emit-project --frozen > .requirements.txt
|
|
83
|
+
uv run app/agent_engine_app.py \
|
|
84
|
+
--project ${_PROD_PROJECT_ID} \
|
|
85
|
+
--location ${_REGION} \
|
|
86
|
+
--set-env-vars COMMIT_SHA=${COMMIT_SHA}{%- if cookiecutter.data_ingestion %},DATA_STORE_ID=${_DATA_STORE_ID},DATA_STORE_REGION=${_DATA_STORE_REGION}{%- endif %}
|
|
87
|
+
env:
|
|
88
|
+
- 'PATH=/usr/local/bin:/usr/bin:~/.local/bin'
|
|
89
|
+
{%- endif %}
|
|
90
|
+
|
|
91
|
+
substitutions:
|
|
92
|
+
_PROD_PROJECT_ID: YOUR_PROD_PROJECT_ID
|
|
93
|
+
_REGION: us-central1
|
|
94
|
+
|
|
95
|
+
logsBucket: gs://${PROJECT_ID}-logs-data/build-logs
|
|
96
|
+
options:
|
|
97
|
+
substitutionOption: ALLOW_LOOSE
|
|
98
|
+
defaultLogsBucketBehavior: REGIONAL_USER_OWNED_BUCKET
|