agent-starter-pack 0.15.7__py3-none-any.whl → 0.17.0__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.
- {agents → agent_starter_pack/agents}/adk_base/.template/templateconfig.yaml +1 -1
- {agents/live_api → agent_starter_pack/agents/adk_live}/.template/templateconfig.yaml +5 -7
- agent_starter_pack/agents/adk_live/README.md +32 -0
- agent_starter_pack/agents/adk_live/app/agent.py +48 -0
- agent_starter_pack/agents/adk_live/tests/unit/test_dummy.py +38 -0
- {agents → agent_starter_pack/agents}/agentic_rag/.template/templateconfig.yaml +1 -1
- agent_starter_pack/agents/crewai_coding_crew/app/agent.py +47 -0
- agent_starter_pack/agents/langgraph_base_react/app/agent.py +34 -0
- {src → agent_starter_pack}/base_template/GEMINI.md +1 -1
- {src → agent_starter_pack}/base_template/Makefile +130 -61
- {src → agent_starter_pack}/base_template/README.md +6 -6
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/apis.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/log_sinks.tf +31 -25
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/providers.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/variables.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/github.tf +14 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/locals.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/log_sinks.tf +37 -28
- {src → agent_starter_pack}/base_template/deployment/terraform/providers.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/variables.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} +4 -2
- {src → agent_starter_pack}/base_template/pyproject.toml +22 -21
- {src → agent_starter_pack}/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +5 -5
- {src → agent_starter_pack}/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +3 -3
- {src → agent_starter_pack}/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +74 -11
- {src → agent_starter_pack}/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +6 -6
- {src → agent_starter_pack}/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/pr_checks.yaml +4 -4
- {src → agent_starter_pack}/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +95 -13
- {src → agent_starter_pack}/base_template/{{cookiecutter.agent_directory}}/utils/tracing.py +1 -1
- {src → agent_starter_pack}/base_template/{{cookiecutter.agent_directory}}/utils/typing.py +4 -4
- {src → agent_starter_pack}/cli/commands/setup_cicd.py +1 -1
- {src → agent_starter_pack}/cli/main.py +2 -2
- {src → agent_starter_pack}/cli/utils/gcp.py +1 -1
- {src → agent_starter_pack}/cli/utils/remote_template.py +12 -9
- {src → agent_starter_pack}/cli/utils/template.py +19 -15
- agent_starter_pack/deployment_targets/agent_engine/deployment/terraform/{% if not cookiecutter.is_adk_live %}service.tf{% else %}unused_service.tf{% endif %} +82 -0
- agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +387 -0
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +84 -0
- agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +255 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +40 -14
- {src → agent_starter_pack}/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/utils/deployment.py +13 -4
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/utils/{% if cookiecutter.is_adk_live %}expose_app.py{% else %}unused_expose_app.py{% endif %} +520 -0
- {src → agent_starter_pack}/deployment_targets/cloud_run/Dockerfile +3 -3
- {src → agent_starter_pack}/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +4 -4
- {src → agent_starter_pack}/deployment_targets/cloud_run/deployment/terraform/service.tf +7 -7
- {src → agent_starter_pack}/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +207 -5
- {src → agent_starter_pack}/deployment_targets/cloud_run/tests/load_test/README.md +82 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +249 -0
- {src → agent_starter_pack}/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/server.py +190 -146
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package-lock.json +39 -1007
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package.json +1 -9
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.tsx +1 -1
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/Logger.tsx +8 -3
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/logger.scss +26 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/side-panel/SidePanel.tsx +11 -5
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/side-panel/side-panel.scss +146 -115
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/TranscriptionPreview.tsx +106 -0
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/transcription-preview.scss +150 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-live-api.ts +8 -2
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/multimodal-live-types.ts +38 -2
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-recorder.ts +1 -1
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-streamer.ts +1 -1
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/multimodal-live-client.ts +204 -23
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/utils.ts +27 -5
- {src → agent_starter_pack}/frontends/streamlit/frontend/utils/local_chat_history.py +2 -0
- {src → agent_starter_pack}/resources/docs/adk-cheatsheet.md +5 -5
- agent_starter_pack/resources/idx/.idx/dev.nix +64 -0
- agent_starter_pack/resources/idx/idx-template.json +6 -0
- {src → agent_starter_pack}/resources/idx/idx-template.nix +2 -3
- {src → agent_starter_pack}/resources/locks/uv-adk_base-agent_engine.lock +1079 -954
- {src → agent_starter_pack}/resources/locks/uv-adk_base-cloud_run.lock +1441 -1309
- agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +4229 -0
- agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +4822 -0
- {src → agent_starter_pack}/resources/locks/uv-agentic_rag-agent_engine.lock +1107 -997
- {src → agent_starter_pack}/resources/locks/uv-agentic_rag-cloud_run.lock +1485 -1368
- {src → agent_starter_pack}/resources/locks/uv-crewai_coding_crew-agent_engine.lock +1294 -1297
- {src → agent_starter_pack}/resources/locks/uv-crewai_coding_crew-cloud_run.lock +2028 -1807
- {src → agent_starter_pack}/resources/locks/uv-langgraph_base_react-agent_engine.lock +1176 -1197
- {src → agent_starter_pack}/resources/locks/uv-langgraph_base_react-cloud_run.lock +1947 -1679
- {src → agent_starter_pack}/utils/generate_locks.py +12 -7
- {src → agent_starter_pack}/utils/lock_utils.py +2 -2
- {src → agent_starter_pack}/utils/watch_and_rebuild.py +1 -1
- {agent_starter_pack-0.15.7.dist-info → agent_starter_pack-0.17.0.dist-info}/METADATA +17 -18
- agent_starter_pack-0.17.0.dist-info/RECORD +179 -0
- agent_starter_pack-0.17.0.dist-info/entry_points.txt +2 -0
- llm.txt +1 -1
- agent_starter_pack-0.15.7.dist-info/RECORD +0 -176
- agent_starter_pack-0.15.7.dist-info/entry_points.txt +0 -2
- agents/crewai_coding_crew/app/agent.py +0 -86
- agents/langgraph_base_react/app/agent.py +0 -73
- agents/live_api/README.md +0 -37
- agents/live_api/app/agent.py +0 -72
- agents/live_api/tests/integration/test_server_e2e.py +0 -260
- agents/live_api/tests/load_test/load_test.py +0 -40
- agents/live_api/tests/unit/test_server.py +0 -144
- src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +0 -186
- src/deployment_targets/agent_engine/tests/load_test/README.md +0 -37
- src/deployment_targets/agent_engine/tests/load_test/load_test.py +0 -126
- src/deployment_targets/cloud_run/tests/load_test/load_test.py +0 -122
- src/resources/idx/.idx/dev.nix +0 -50
- src/resources/idx/idx-template.json +0 -21
- src/resources/locks/uv-live_api-cloud_run.lock +0 -6118
- {agents → agent_starter_pack/agents}/README.md +0 -0
- {agents → agent_starter_pack/agents}/adk_base/README.md +0 -0
- {agents → agent_starter_pack/agents}/adk_base/app/__init__.py +0 -0
- {agents → agent_starter_pack/agents}/adk_base/app/agent.py +0 -0
- {agents → agent_starter_pack/agents}/adk_base/notebooks/adk_app_testing.ipynb +0 -0
- {agents → agent_starter_pack/agents}/adk_base/notebooks/evaluating_adk_agent.ipynb +0 -0
- {agents → agent_starter_pack/agents}/adk_base/tests/integration/test_agent.py +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/README.md +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/__init__.py +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/agent.py +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/retrievers.py +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/templates.py +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/notebooks/adk_app_testing.ipynb +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/notebooks/evaluating_adk_agent.ipynb +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/tests/integration/test_agent.py +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/.template/templateconfig.yaml +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/README.md +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/app/crew/config/agents.yaml +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/app/crew/config/tasks.yaml +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/app/crew/crew.py +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/notebooks/evaluating_langgraph_agent.ipynb +0 -0
- {agents → agent_starter_pack/agents}/crewai_coding_crew/tests/integration/test_agent.py +0 -0
- {agents → agent_starter_pack/agents}/langgraph_base_react/.template/templateconfig.yaml +0 -0
- {agents → agent_starter_pack/agents}/langgraph_base_react/README.md +0 -0
- {agents → agent_starter_pack/agents}/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb +0 -0
- {agents → agent_starter_pack/agents}/langgraph_base_react/tests/integration/test_agent.py +0 -0
- {src → agent_starter_pack}/base_template/.gitignore +0 -0
- {src → agent_starter_pack}/base_template/deployment/README.md +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/apis.tf +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/iam.tf +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/storage.tf +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/vars/env.tfvars +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/iam.tf +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/service_accounts.tf +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/storage.tf +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/vars/env.tfvars +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +0 -0
- {src → agent_starter_pack}/base_template/tests/unit/test_dummy.py +0 -0
- {src → agent_starter_pack}/base_template/{{cookiecutter.agent_directory}}/utils/gcs.py +0 -0
- {src → agent_starter_pack}/cli/commands/create.py +0 -0
- {src → agent_starter_pack}/cli/commands/enhance.py +0 -0
- {src → agent_starter_pack}/cli/commands/list.py +0 -0
- {src → agent_starter_pack}/cli/utils/__init__.py +0 -0
- {src → agent_starter_pack}/cli/utils/cicd.py +0 -0
- {src → agent_starter_pack}/cli/utils/datastores.py +0 -0
- {src → agent_starter_pack}/cli/utils/logging.py +0 -0
- {src → agent_starter_pack}/cli/utils/version.py +0 -0
- {src → agent_starter_pack}/data_ingestion/README.md +0 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/ingest_data.py +0 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/process_data.py +0 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/pipeline.py +0 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/submit_pipeline.py +0 -0
- {src → agent_starter_pack}/data_ingestion/pyproject.toml +0 -0
- {src → agent_starter_pack}/data_ingestion/uv.lock +0 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/deployment_metadata.json +0 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/tests/load_test/.results/.placeholder +0 -0
- {src → agent_starter_pack}/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/favicon.ico +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/index.html +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/robots.txt +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.scss +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.test.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/AudioPulse.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/audio-pulse.scss +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/mock-logs.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/contexts/LiveAPIContext.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-media-stream-mux.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-screen-capture.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-webcam.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.css +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.tsx +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/react-app-env.d.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/reportWebVitals.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/setupTests.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audioworklet-registry.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/store-logger.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/audio-processing.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/vol-meter.ts +0 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/tsconfig.json +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/side_bar.py +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/streamlit_app.py +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/style/app_markdown.py +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/utils/chat_utils.py +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/utils/message_editing.py +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/utils/stream_handler.py +0 -0
- {src → agent_starter_pack}/frontends/streamlit/frontend/utils/title_summary.py +0 -0
- {src → agent_starter_pack}/resources/containers/data_processing/Dockerfile +0 -0
- {src → agent_starter_pack}/resources/containers/e2e-tests/Dockerfile +0 -0
- {agent_starter_pack-0.15.7.dist-info → agent_starter_pack-0.17.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.15.7.dist-info → agent_starter_pack-0.17.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,255 @@
|
|
|
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
|
+
{%- if cookiecutter.agent_name == "adk_live" %}
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import time
|
|
19
|
+
|
|
20
|
+
from locust import User, between, task
|
|
21
|
+
from websockets.exceptions import WebSocketException
|
|
22
|
+
from websockets.sync.client import connect
|
|
23
|
+
|
|
24
|
+
logging.basicConfig(level=logging.INFO)
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class WebSocketUser(User):
|
|
29
|
+
"""Simulates a user making websocket requests to the remote agent engine."""
|
|
30
|
+
|
|
31
|
+
wait_time = between(1, 3) # Wait 1-3 seconds between tasks
|
|
32
|
+
abstract = True
|
|
33
|
+
|
|
34
|
+
def __init__(self, *args: object, **kwargs: object) -> None:
|
|
35
|
+
super().__init__(*args, **kwargs)
|
|
36
|
+
if self.host.startswith("https://"):
|
|
37
|
+
self.ws_url = self.host.replace("https://", "wss://", 1) + "/ws"
|
|
38
|
+
elif self.host.startswith("http://"):
|
|
39
|
+
self.ws_url = self.host.replace("http://", "ws://", 1) + "/ws"
|
|
40
|
+
else:
|
|
41
|
+
self.ws_url = self.host + "/ws"
|
|
42
|
+
|
|
43
|
+
@task
|
|
44
|
+
def websocket_audio_conversation(self) -> None:
|
|
45
|
+
"""Test a full websocket conversation with audio input."""
|
|
46
|
+
start_time = time.time()
|
|
47
|
+
response_count = 0
|
|
48
|
+
exception = None
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
response_count = self._websocket_interaction()
|
|
52
|
+
|
|
53
|
+
# Mark as failure if we got no valid responses
|
|
54
|
+
if response_count == 0:
|
|
55
|
+
exception = Exception("No responses received from agent")
|
|
56
|
+
|
|
57
|
+
except WebSocketException as e:
|
|
58
|
+
exception = e
|
|
59
|
+
logger.error(f"WebSocket error: {e}")
|
|
60
|
+
except Exception as e:
|
|
61
|
+
exception = e
|
|
62
|
+
logger.error(f"Unexpected error: {e}")
|
|
63
|
+
finally:
|
|
64
|
+
total_time = int((time.time() - start_time) * 1000)
|
|
65
|
+
|
|
66
|
+
# Report the request metrics to Locust
|
|
67
|
+
self.environment.events.request.fire(
|
|
68
|
+
request_type="WS",
|
|
69
|
+
name="websocket_conversation",
|
|
70
|
+
response_time=total_time,
|
|
71
|
+
response_length=response_count * 100, # Approximate response size
|
|
72
|
+
response=None,
|
|
73
|
+
context={},
|
|
74
|
+
exception=exception,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def _websocket_interaction(self) -> int:
|
|
78
|
+
"""Handle the websocket interaction and return response count."""
|
|
79
|
+
response_count = 0
|
|
80
|
+
|
|
81
|
+
with connect(self.ws_url, open_timeout=10, close_timeout=20) as websocket:
|
|
82
|
+
# Wait for setupComplete
|
|
83
|
+
setup_response = websocket.recv(timeout=10.0)
|
|
84
|
+
setup_data = json.loads(setup_response)
|
|
85
|
+
assert "setupComplete" in setup_data, (
|
|
86
|
+
f"Expected setupComplete, got {setup_data}"
|
|
87
|
+
)
|
|
88
|
+
logger.info("Received setupComplete")
|
|
89
|
+
|
|
90
|
+
# Send dummy audio chunk with user_id
|
|
91
|
+
dummy_audio = bytes([0] * 1024)
|
|
92
|
+
audio_msg = {
|
|
93
|
+
"user_id": "load-test-user",
|
|
94
|
+
"realtimeInput": {
|
|
95
|
+
"mediaChunks": [
|
|
96
|
+
{
|
|
97
|
+
"mimeType": "audio/pcm;rate=16000",
|
|
98
|
+
"data": dummy_audio.hex(),
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
websocket.send(json.dumps(audio_msg))
|
|
104
|
+
logger.info("Sent audio chunk")
|
|
105
|
+
|
|
106
|
+
# Send text message to complete the turn
|
|
107
|
+
text_msg = {
|
|
108
|
+
"content": {
|
|
109
|
+
"role": "user",
|
|
110
|
+
"parts": [{"text": "Hello!"}],
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
websocket.send(json.dumps(text_msg))
|
|
114
|
+
logger.info("Sent text completion")
|
|
115
|
+
|
|
116
|
+
# Collect responses until turn_complete or timeout
|
|
117
|
+
for _ in range(20): # Max 20 responses
|
|
118
|
+
try:
|
|
119
|
+
response = websocket.recv(timeout=10.0)
|
|
120
|
+
response_data = json.loads(response)
|
|
121
|
+
response_count += 1
|
|
122
|
+
logger.debug(f"Received response: {response_data}")
|
|
123
|
+
|
|
124
|
+
if isinstance(response_data, dict) and response_data.get(
|
|
125
|
+
"turn_complete"
|
|
126
|
+
):
|
|
127
|
+
logger.info(f"Turn complete after {response_count} responses")
|
|
128
|
+
break
|
|
129
|
+
except TimeoutError:
|
|
130
|
+
logger.info(f"Timeout after {response_count} responses")
|
|
131
|
+
break
|
|
132
|
+
|
|
133
|
+
return response_count
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class RemoteAgentUser(WebSocketUser):
|
|
137
|
+
"""User for testing remote agent engine deployment."""
|
|
138
|
+
|
|
139
|
+
# Set the host via command line: locust -f load_test.py --host=https://your-deployed-service.run.app
|
|
140
|
+
host = "http://localhost:8000" # Default for local testing
|
|
141
|
+
{%- else %}
|
|
142
|
+
|
|
143
|
+
import json
|
|
144
|
+
import logging
|
|
145
|
+
import os
|
|
146
|
+
import time
|
|
147
|
+
|
|
148
|
+
from locust import HttpUser, between, task
|
|
149
|
+
|
|
150
|
+
# Configure logging
|
|
151
|
+
logging.basicConfig(
|
|
152
|
+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
153
|
+
)
|
|
154
|
+
logger = logging.getLogger(__name__)
|
|
155
|
+
|
|
156
|
+
# Initialize Vertex AI and load agent config
|
|
157
|
+
with open("deployment_metadata.json") as f:
|
|
158
|
+
remote_agent_engine_id = json.load(f)["remote_agent_engine_id"]
|
|
159
|
+
|
|
160
|
+
parts = remote_agent_engine_id.split("/")
|
|
161
|
+
project_id = parts[1]
|
|
162
|
+
location = parts[3]
|
|
163
|
+
engine_id = parts[5]
|
|
164
|
+
|
|
165
|
+
# Convert remote agent engine ID to streaming URL.
|
|
166
|
+
base_url = f"https://{location}-aiplatform.googleapis.com"
|
|
167
|
+
url_path = f"/v1/projects/{project_id}/locations/{location}/reasoningEngines/{engine_id}:streamQuery"
|
|
168
|
+
|
|
169
|
+
logger.info("Using remote agent engine ID: %s", remote_agent_engine_id)
|
|
170
|
+
logger.info("Using base URL: %s", base_url)
|
|
171
|
+
logger.info("Using URL path: %s", url_path)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class ChatStreamUser(HttpUser):
|
|
175
|
+
"""Simulates a user interacting with the chat stream API."""
|
|
176
|
+
|
|
177
|
+
wait_time = between(1, 3) # Wait 1-3 seconds between tasks
|
|
178
|
+
host = base_url # Set the base host URL for Locust
|
|
179
|
+
|
|
180
|
+
@task
|
|
181
|
+
def chat_stream(self) -> None:
|
|
182
|
+
"""Simulates a chat stream interaction."""
|
|
183
|
+
headers = {"Content-Type": "application/json"}
|
|
184
|
+
headers["Authorization"] = f"Bearer {os.environ['_AUTH_TOKEN']}"
|
|
185
|
+
{% if cookiecutter.is_adk %}
|
|
186
|
+
data = {
|
|
187
|
+
"class_method": "async_stream_query",
|
|
188
|
+
"input": {
|
|
189
|
+
"user_id": "test",
|
|
190
|
+
"message": "What's the weather in San Francisco?",
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
{% else %}
|
|
194
|
+
data = {
|
|
195
|
+
"input": {
|
|
196
|
+
"input": {
|
|
197
|
+
"messages": [
|
|
198
|
+
{"type": "human", "content": "Hello, AI!"},
|
|
199
|
+
{"type": "ai", "content": "Hello!"},
|
|
200
|
+
{"type": "human", "content": "How are you?"},
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
"config": {
|
|
204
|
+
"metadata": {"user_id": "test-user", "session_id": "test-session"}
|
|
205
|
+
},
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
{% endif %}
|
|
209
|
+
start_time = time.time()
|
|
210
|
+
with self.client.post(
|
|
211
|
+
url_path,
|
|
212
|
+
headers=headers,
|
|
213
|
+
json=data,
|
|
214
|
+
catch_response=True,
|
|
215
|
+
{%- if cookiecutter.is_adk %}
|
|
216
|
+
name="/streamQuery async_stream_query",
|
|
217
|
+
{%- else %}
|
|
218
|
+
name="/stream_messages first message",
|
|
219
|
+
{%- endif %}
|
|
220
|
+
stream=True,
|
|
221
|
+
params={"alt": "sse"},
|
|
222
|
+
) as response:
|
|
223
|
+
if response.status_code == 200:
|
|
224
|
+
events = []
|
|
225
|
+
for line in response.iter_lines():
|
|
226
|
+
if line:
|
|
227
|
+
line_str = line.decode("utf-8")
|
|
228
|
+
events.append(line_str)
|
|
229
|
+
|
|
230
|
+
if "429 Too Many Requests" in line_str:
|
|
231
|
+
self.environment.events.request.fire(
|
|
232
|
+
request_type="POST",
|
|
233
|
+
name=f"{url_path} rate_limited 429s",
|
|
234
|
+
response_time=0,
|
|
235
|
+
response_length=len(line),
|
|
236
|
+
response=response,
|
|
237
|
+
context={},
|
|
238
|
+
)
|
|
239
|
+
end_time = time.time()
|
|
240
|
+
total_time = end_time - start_time
|
|
241
|
+
self.environment.events.request.fire(
|
|
242
|
+
request_type="POST",
|
|
243
|
+
{%- if cookiecutter.is_adk %}
|
|
244
|
+
name="/streamQuery end",
|
|
245
|
+
{%- else %}
|
|
246
|
+
name="/stream_messages end",
|
|
247
|
+
{%- endif %}
|
|
248
|
+
response_time=total_time * 1000, # Convert to milliseconds
|
|
249
|
+
response_length=len(events),
|
|
250
|
+
response=response,
|
|
251
|
+
context={},
|
|
252
|
+
)
|
|
253
|
+
else:
|
|
254
|
+
response.failure(f"Unexpected status code: {response.status_code}")
|
|
255
|
+
{%- endif %}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
# mypy: disable-error-code="attr-defined,arg-type"
|
|
16
|
-
{%- if
|
|
16
|
+
{%- if cookiecutter.is_adk %}
|
|
17
17
|
import logging
|
|
18
18
|
import os
|
|
19
19
|
from typing import Any
|
|
@@ -25,8 +25,12 @@ from google.adk.artifacts import GcsArtifactService
|
|
|
25
25
|
from google.cloud import logging as google_cloud_logging
|
|
26
26
|
from opentelemetry import trace
|
|
27
27
|
from opentelemetry.sdk.trace import TracerProvider, export
|
|
28
|
-
from vertexai._genai.types import AgentEngine, AgentEngineConfig
|
|
28
|
+
from vertexai._genai.types import AgentEngine, AgentEngineConfig{%- if cookiecutter.is_adk_live %}, AgentServerMode{%- endif %}
|
|
29
|
+
{%- if cookiecutter.is_adk_live %}
|
|
30
|
+
from vertexai.preview.reasoning_engines import AdkApp
|
|
31
|
+
{%- else %}
|
|
29
32
|
from vertexai.agent_engines.templates.adk import AdkApp
|
|
33
|
+
{%- endif %}
|
|
30
34
|
|
|
31
35
|
from {{cookiecutter.agent_directory}}.agent import root_agent
|
|
32
36
|
from {{cookiecutter.agent_directory}}.utils.deployment import (
|
|
@@ -235,6 +239,16 @@ class AgentEngineApp:
|
|
|
235
239
|
default=None,
|
|
236
240
|
help="Service account email to use for the agent engine",
|
|
237
241
|
)
|
|
242
|
+
@click.option(
|
|
243
|
+
"--staging-bucket-uri",
|
|
244
|
+
default=None,
|
|
245
|
+
help="GCS bucket URI for staging files (defaults to gs://{project}-agent-engine)",
|
|
246
|
+
)
|
|
247
|
+
@click.option(
|
|
248
|
+
"--artifacts-bucket-name",
|
|
249
|
+
default=None,
|
|
250
|
+
help="GCS bucket name for artifacts (defaults to gs://{project}-agent-engine)",
|
|
251
|
+
)
|
|
238
252
|
def deploy_agent_engine_app(
|
|
239
253
|
project: str | None,
|
|
240
254
|
location: str,
|
|
@@ -243,13 +257,31 @@ def deploy_agent_engine_app(
|
|
|
243
257
|
extra_packages: tuple[str, ...],
|
|
244
258
|
set_env_vars: str | None,
|
|
245
259
|
service_account: str | None,
|
|
260
|
+
staging_bucket_uri: str | None,
|
|
261
|
+
artifacts_bucket_name: str | None,
|
|
246
262
|
) -> AgentEngine:
|
|
247
263
|
"""Deploy the agent engine app to Vertex AI."""
|
|
264
|
+
|
|
265
|
+
logging.basicConfig(level=logging.INFO)
|
|
266
|
+
|
|
248
267
|
# Parse environment variables if provided
|
|
249
268
|
env_vars = parse_env_vars(set_env_vars)
|
|
250
269
|
|
|
251
270
|
if not project:
|
|
252
271
|
_, project = google.auth.default()
|
|
272
|
+
if not staging_bucket_uri:
|
|
273
|
+
staging_bucket_uri = f"gs://{project}-agent-engine"
|
|
274
|
+
if not artifacts_bucket_name:
|
|
275
|
+
artifacts_bucket_name = f"gs://{project}-agent-engine"
|
|
276
|
+
|
|
277
|
+
{%- if "adk" in cookiecutter.tags %}
|
|
278
|
+
create_bucket_if_not_exists(
|
|
279
|
+
bucket_name=artifacts_bucket_name, project=project, location=location
|
|
280
|
+
)
|
|
281
|
+
{%- endif %}
|
|
282
|
+
create_bucket_if_not_exists(
|
|
283
|
+
bucket_name=staging_bucket_uri, project=project, location=location
|
|
284
|
+
)
|
|
253
285
|
|
|
254
286
|
print("""
|
|
255
287
|
╔═══════════════════════════════════════════════════════════╗
|
|
@@ -259,18 +291,7 @@ def deploy_agent_engine_app(
|
|
|
259
291
|
╚═══════════════════════════════════════════════════════════╝
|
|
260
292
|
""")
|
|
261
293
|
|
|
262
|
-
logging.basicConfig(level=logging.INFO)
|
|
263
294
|
extra_packages_list = list(extra_packages)
|
|
264
|
-
staging_bucket_uri = f"gs://{project}-agent-engine"
|
|
265
|
-
{%- if "adk" in cookiecutter.tags %}
|
|
266
|
-
artifacts_bucket_name = f"{project}-{{cookiecutter.project_name}}-logs"
|
|
267
|
-
create_bucket_if_not_exists(
|
|
268
|
-
bucket_name=artifacts_bucket_name, project=project, location=location
|
|
269
|
-
)
|
|
270
|
-
{%- endif %}
|
|
271
|
-
create_bucket_if_not_exists(
|
|
272
|
-
bucket_name=staging_bucket_uri, project=project, location=location
|
|
273
|
-
)
|
|
274
295
|
|
|
275
296
|
# Initialize vertexai client
|
|
276
297
|
client = vertexai.Client(
|
|
@@ -282,7 +303,7 @@ def deploy_agent_engine_app(
|
|
|
282
303
|
# Read requirements
|
|
283
304
|
with open(requirements_file) as f:
|
|
284
305
|
requirements = f.read().strip().split("\n")
|
|
285
|
-
{% if
|
|
306
|
+
{% if cookiecutter.is_adk %}
|
|
286
307
|
agent_engine = AgentEngineApp(
|
|
287
308
|
agent=root_agent,
|
|
288
309
|
artifact_service_builder=lambda: GcsArtifactService(
|
|
@@ -314,6 +335,11 @@ def deploy_agent_engine_app(
|
|
|
314
335
|
requirements=requirements,
|
|
315
336
|
staging_bucket=staging_bucket_uri,
|
|
316
337
|
labels=labels,
|
|
338
|
+
gcs_dir_name=agent_name,
|
|
339
|
+
{%- if cookiecutter.is_adk_live %}
|
|
340
|
+
agent_server_mode=AgentServerMode.EXPERIMENTAL, # Enable bidi streaming
|
|
341
|
+
resource_limits={"cpu": "4", "memory": "8Gi"},
|
|
342
|
+
{%- endif %}
|
|
317
343
|
)
|
|
318
344
|
|
|
319
345
|
agent_config = {
|
|
@@ -75,11 +75,20 @@ def print_deployment_success(
|
|
|
75
75
|
agent_engine_id = remote_agent.api_resource.name.split("/")[-1]
|
|
76
76
|
console_url = f"https://console.cloud.google.com/vertex-ai/agents/locations/{location}/agent-engines/{agent_engine_id}?project={project}"
|
|
77
77
|
|
|
78
|
-
{%- if
|
|
78
|
+
{%- if cookiecutter.is_adk %}
|
|
79
|
+
{%- if cookiecutter.is_adk_live %}
|
|
80
|
+
print("\n✅ Deployment successful! Run your agent with: `make playground-remote`")
|
|
81
|
+
{%- else %}
|
|
79
82
|
print(
|
|
80
|
-
|
|
81
|
-
f"\n📊 View in console: {console_url}\n"
|
|
83
|
+
"\n✅ Deployment successful! Test your agent: notebooks/adk_app_testing.ipynb"
|
|
82
84
|
)
|
|
85
|
+
{%- endif %}
|
|
86
|
+
service_account = remote_agent.api_resource.spec.service_account
|
|
87
|
+
print(f"Service Account: {service_account}")
|
|
88
|
+
print(f"\n📊 View in console: {console_url}\n")
|
|
83
89
|
{%- else %}
|
|
84
|
-
print(
|
|
90
|
+
print("\n✅ Deployment successful!")
|
|
91
|
+
service_account = remote_agent.api_resource.spec.service_account
|
|
92
|
+
print(f"Service Account: {service_account}")
|
|
93
|
+
print(f"\n📊 View in console: {console_url}\n")
|
|
85
94
|
{%- endif %}
|