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
|
@@ -1,144 +0,0 @@
|
|
|
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
|
-
import os
|
|
18
|
-
from collections.abc import Generator
|
|
19
|
-
from unittest.mock import AsyncMock, MagicMock, patch
|
|
20
|
-
|
|
21
|
-
import pytest
|
|
22
|
-
from fastapi.testclient import TestClient
|
|
23
|
-
from google.auth.credentials import Credentials
|
|
24
|
-
|
|
25
|
-
# Set up logging
|
|
26
|
-
logging.basicConfig(level=logging.INFO)
|
|
27
|
-
logger = logging.getLogger(__name__)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@pytest.fixture(autouse=True)
|
|
31
|
-
def mock_google_cloud_credentials() -> Generator[None, None, None]:
|
|
32
|
-
"""Mock Google Cloud credentials for testing."""
|
|
33
|
-
with patch.dict(
|
|
34
|
-
os.environ,
|
|
35
|
-
{
|
|
36
|
-
"GOOGLE_APPLICATION_CREDENTIALS": "/path/to/mock/credentials.json",
|
|
37
|
-
"GOOGLE_CLOUD_PROJECT_ID": "mock-project-id",
|
|
38
|
-
},
|
|
39
|
-
):
|
|
40
|
-
yield
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@pytest.fixture(autouse=True)
|
|
44
|
-
def mock_google_auth_default() -> Generator[None, None, None]:
|
|
45
|
-
"""Mock the google.auth.default function for testing."""
|
|
46
|
-
mock_credentials = MagicMock(spec=Credentials)
|
|
47
|
-
mock_project = "mock-project-id"
|
|
48
|
-
|
|
49
|
-
with patch("google.auth.default", return_value=(mock_credentials, mock_project)):
|
|
50
|
-
yield
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@pytest.fixture(autouse=True)
|
|
54
|
-
def mock_dependencies() -> Generator[None, None, None]:
|
|
55
|
-
"""
|
|
56
|
-
Mock Vertex AI dependencies for testing.
|
|
57
|
-
Patches genai client and tool functions.
|
|
58
|
-
"""
|
|
59
|
-
with (
|
|
60
|
-
patch("{{cookiecutter.agent_directory}}.server.genai_client") as mock_genai,
|
|
61
|
-
patch("{{cookiecutter.agent_directory}}.server.tool_functions") as mock_tools,
|
|
62
|
-
):
|
|
63
|
-
mock_genai.aio.live.connect = AsyncMock()
|
|
64
|
-
mock_tools.return_value = {}
|
|
65
|
-
yield
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
@pytest.mark.asyncio
|
|
69
|
-
async def test_websocket_endpoint() -> None:
|
|
70
|
-
"""
|
|
71
|
-
Test the websocket endpoint to ensure it correctly handles
|
|
72
|
-
websocket connections and messages.
|
|
73
|
-
"""
|
|
74
|
-
from {{cookiecutter.agent_directory}}.server import app
|
|
75
|
-
|
|
76
|
-
mock_session = AsyncMock()
|
|
77
|
-
mock_session._ws = AsyncMock()
|
|
78
|
-
# Configure mock to return proper response format and close after one message
|
|
79
|
-
mock_session._ws.recv.side_effect = [
|
|
80
|
-
json.dumps(
|
|
81
|
-
{
|
|
82
|
-
"serverContent": {
|
|
83
|
-
"modelTurn": {
|
|
84
|
-
"role": "model",
|
|
85
|
-
"parts": [{"text": "Hello, how can I help you?"}],
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
).encode(), # Encode as bytes since recv(decode=False) is used
|
|
90
|
-
None, # Add None to trigger StopAsyncIteration after first message
|
|
91
|
-
]
|
|
92
|
-
|
|
93
|
-
with patch("{{cookiecutter.agent_directory}}.server.genai_client") as mock_genai:
|
|
94
|
-
mock_genai.aio.live.connect.return_value.__aenter__.return_value = mock_session
|
|
95
|
-
client = TestClient(app)
|
|
96
|
-
with client.websocket_connect("/ws") as websocket:
|
|
97
|
-
# Test initial connection message
|
|
98
|
-
data = websocket.receive_json()
|
|
99
|
-
assert data["status"] == "Backend is ready for conversation"
|
|
100
|
-
|
|
101
|
-
# Test sending a message
|
|
102
|
-
websocket.send_json(
|
|
103
|
-
{"setup": {"run_id": "test-run", "user_id": "test-user"}}
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
# Test sending audio stream
|
|
107
|
-
dummy_audio = bytes([0] * 1024) # 1KB of silence
|
|
108
|
-
websocket.send_json(
|
|
109
|
-
{
|
|
110
|
-
"realtimeInput": {
|
|
111
|
-
"mediaChunks": [
|
|
112
|
-
{
|
|
113
|
-
"mimeType": "audio/pcm;rate=16000",
|
|
114
|
-
"data": dummy_audio.hex(),
|
|
115
|
-
}
|
|
116
|
-
]
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
# Receive response as bytes
|
|
122
|
-
response = websocket.receive_bytes()
|
|
123
|
-
response_data = json.loads(response.decode())
|
|
124
|
-
assert "serverContent" in response_data
|
|
125
|
-
|
|
126
|
-
# Verify mock interactions
|
|
127
|
-
mock_genai.aio.live.connect.assert_called_once()
|
|
128
|
-
assert mock_session._ws.recv.called
|
|
129
|
-
await mock_session._ws.recv.aclose()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
@pytest.mark.asyncio
|
|
133
|
-
def test_websocket_error_handling() -> None:
|
|
134
|
-
"""Test websocket error handling."""
|
|
135
|
-
from {{cookiecutter.agent_directory}}.server import app
|
|
136
|
-
|
|
137
|
-
with patch("{{cookiecutter.agent_directory}}.server.genai_client") as mock_genai:
|
|
138
|
-
mock_genai.aio.live.connect.side_effect = Exception("Connection failed")
|
|
139
|
-
|
|
140
|
-
client = TestClient(app)
|
|
141
|
-
with pytest.raises(Exception) as exc:
|
|
142
|
-
with client.websocket_connect("/ws"):
|
|
143
|
-
pass
|
|
144
|
-
assert str(exc.value) == "Connection failed"
|
|
@@ -1,186 +0,0 @@
|
|
|
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
|
-
|
|
17
|
-
import pytest
|
|
18
|
-
{%- if "adk" in cookiecutter.tags %}
|
|
19
|
-
from google.adk.events.event import Event
|
|
20
|
-
|
|
21
|
-
from {{cookiecutter.agent_directory}}.agent import root_agent
|
|
22
|
-
from {{cookiecutter.agent_directory}}.agent_engine_app import AgentEngineApp
|
|
23
|
-
{%- else %}
|
|
24
|
-
|
|
25
|
-
from {{cookiecutter.agent_directory}}.agent_engine_app import AgentEngineApp
|
|
26
|
-
{%- endif %}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@pytest.fixture
|
|
30
|
-
def agent_app() -> AgentEngineApp:
|
|
31
|
-
"""Fixture to create and set up AgentEngineApp instance"""
|
|
32
|
-
{%- if "adk" in cookiecutter.tags %}
|
|
33
|
-
app = AgentEngineApp(agent=root_agent)
|
|
34
|
-
{%- else %}
|
|
35
|
-
app = AgentEngineApp()
|
|
36
|
-
{%- endif %}
|
|
37
|
-
app.set_up()
|
|
38
|
-
return app
|
|
39
|
-
|
|
40
|
-
{% if "adk" in cookiecutter.tags %}
|
|
41
|
-
@pytest.mark.asyncio
|
|
42
|
-
async def test_agent_stream_query(agent_app: AgentEngineApp) -> None:
|
|
43
|
-
"""
|
|
44
|
-
Integration test for the agent stream query functionality.
|
|
45
|
-
Tests that the agent returns valid streaming responses.
|
|
46
|
-
"""
|
|
47
|
-
# Create message and events for the async_stream_query
|
|
48
|
-
message = "What's the weather in San Francisco?"
|
|
49
|
-
events = []
|
|
50
|
-
async for event in agent_app.async_stream_query(message=message, user_id="test"):
|
|
51
|
-
events.append(event)
|
|
52
|
-
assert len(events) > 0, "Expected at least one chunk in response"
|
|
53
|
-
|
|
54
|
-
# Check for valid content in the response
|
|
55
|
-
has_text_content = False
|
|
56
|
-
for event in events:
|
|
57
|
-
validated_event = Event.model_validate(event)
|
|
58
|
-
content = validated_event.content
|
|
59
|
-
if (
|
|
60
|
-
content is not None
|
|
61
|
-
and content.parts
|
|
62
|
-
and any(part.text for part in content.parts)
|
|
63
|
-
):
|
|
64
|
-
has_text_content = True
|
|
65
|
-
break
|
|
66
|
-
|
|
67
|
-
assert has_text_content, "Expected at least one event with text content"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def test_agent_feedback(agent_app: AgentEngineApp) -> None:
|
|
71
|
-
"""
|
|
72
|
-
Integration test for the agent feedback functionality.
|
|
73
|
-
Tests that feedback can be registered successfully.
|
|
74
|
-
"""
|
|
75
|
-
feedback_data = {
|
|
76
|
-
"score": 5,
|
|
77
|
-
"text": "Great response!",
|
|
78
|
-
"invocation_id": "test-run-123",
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
# Should not raise any exceptions
|
|
82
|
-
agent_app.register_feedback(feedback_data)
|
|
83
|
-
|
|
84
|
-
# Test invalid feedback
|
|
85
|
-
with pytest.raises(ValueError):
|
|
86
|
-
invalid_feedback = {
|
|
87
|
-
"score": "invalid", # Score must be numeric
|
|
88
|
-
"text": "Bad feedback",
|
|
89
|
-
"invocation_id": "test-run-123",
|
|
90
|
-
}
|
|
91
|
-
agent_app.register_feedback(invalid_feedback)
|
|
92
|
-
|
|
93
|
-
logging.info("All assertions passed for agent feedback test")
|
|
94
|
-
{% else %}
|
|
95
|
-
def test_agent_stream_query(agent_app: AgentEngineApp) -> None:
|
|
96
|
-
"""
|
|
97
|
-
Integration test for the agent stream query functionality.
|
|
98
|
-
Tests that the agent returns valid streaming responses.
|
|
99
|
-
"""
|
|
100
|
-
input_dict = {
|
|
101
|
-
"messages": [
|
|
102
|
-
{"type": "human", "content": "Test message"},
|
|
103
|
-
],
|
|
104
|
-
"user_id": "test-user",
|
|
105
|
-
"session_id": "test-session",
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
events = list(agent_app.stream_query(input=input_dict))
|
|
109
|
-
|
|
110
|
-
assert len(events) > 0, "Expected at least one chunk in response"
|
|
111
|
-
|
|
112
|
-
# Verify each event is a tuple of message and metadata
|
|
113
|
-
for event in events:
|
|
114
|
-
assert isinstance(event, list), "Event should be a list"
|
|
115
|
-
assert len(event) == 2, "Event should contain message and metadata"
|
|
116
|
-
message, _ = event
|
|
117
|
-
|
|
118
|
-
# Verify message structure
|
|
119
|
-
assert isinstance(message, dict), "Message should be a dictionary"
|
|
120
|
-
assert message["type"] == "constructor"
|
|
121
|
-
assert "kwargs" in message, "Constructor message should have kwargs"
|
|
122
|
-
|
|
123
|
-
# Verify at least one message has content
|
|
124
|
-
has_content = False
|
|
125
|
-
for event in events:
|
|
126
|
-
message = event[0]
|
|
127
|
-
if message.get("type") == "constructor" and "content" in message["kwargs"]:
|
|
128
|
-
has_content = True
|
|
129
|
-
break
|
|
130
|
-
assert has_content, "At least one message should have content"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def test_agent_query(agent_app: AgentEngineApp) -> None:
|
|
134
|
-
"""
|
|
135
|
-
Integration test for the agent query functionality.
|
|
136
|
-
Tests that the agent returns valid responses.
|
|
137
|
-
"""
|
|
138
|
-
input_dict = {
|
|
139
|
-
"messages": [
|
|
140
|
-
{"type": "human", "content": "Test message"},
|
|
141
|
-
],
|
|
142
|
-
"user_id": "test-user",
|
|
143
|
-
"session_id": "test-session",
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
response = agent_app.query(input=input_dict)
|
|
147
|
-
|
|
148
|
-
# Basic response validation
|
|
149
|
-
assert isinstance(response, dict), "Response should be a dictionary"
|
|
150
|
-
assert "messages" in response, "Response should contain messages"
|
|
151
|
-
assert len(response["messages"]) > 0, "Response should have at least one message"
|
|
152
|
-
|
|
153
|
-
# Validate last message is AI response with content
|
|
154
|
-
message = response["messages"][-1]
|
|
155
|
-
kwargs = message["kwargs"]
|
|
156
|
-
assert kwargs["type"] == "ai", "Last message should be AI response"
|
|
157
|
-
assert len(kwargs["content"]) > 0, "AI message content should not be empty"
|
|
158
|
-
|
|
159
|
-
logging.info("All assertions passed for agent query test")
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def test_agent_feedback(agent_app: AgentEngineApp) -> None:
|
|
163
|
-
"""
|
|
164
|
-
Integration test for the agent feedback functionality.
|
|
165
|
-
Tests that feedback can be registered successfully.
|
|
166
|
-
"""
|
|
167
|
-
feedback_data = {
|
|
168
|
-
"score": 5,
|
|
169
|
-
"text": "Great response!",
|
|
170
|
-
"run_id": "test-run-123",
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
# Should not raise any exceptions
|
|
174
|
-
agent_app.register_feedback(feedback_data)
|
|
175
|
-
|
|
176
|
-
# Test invalid feedback
|
|
177
|
-
with pytest.raises(ValueError):
|
|
178
|
-
invalid_feedback = {
|
|
179
|
-
"score": "invalid", # Score must be numeric
|
|
180
|
-
"text": "Bad feedback",
|
|
181
|
-
"run_id": "test-run-123",
|
|
182
|
-
}
|
|
183
|
-
agent_app.register_feedback(invalid_feedback)
|
|
184
|
-
|
|
185
|
-
logging.info("All assertions passed for agent feedback test")
|
|
186
|
-
{% endif %}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Robust Load Testing for Generative AI Applications
|
|
2
|
-
|
|
3
|
-
This directory provides a comprehensive load testing framework for your Generative AI application, leveraging the power of [Locust](http://locust.io), a leading open-source load testing tool.
|
|
4
|
-
|
|
5
|
-
## Load Testing
|
|
6
|
-
|
|
7
|
-
Before running load tests, ensure you have deployed the backend remotely.
|
|
8
|
-
|
|
9
|
-
Follow these steps to execute load tests:
|
|
10
|
-
|
|
11
|
-
**1. Deploy the Backend Remotely:**
|
|
12
|
-
```bash
|
|
13
|
-
gcloud config set project <your-dev-project-id>
|
|
14
|
-
make backend
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
**2. Create a Virtual Environment for Locust:**
|
|
18
|
-
It's recommended to use a separate terminal tab and create a virtual environment for Locust to avoid conflicts with your application's Python environment.
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
python3 -m venv .locust_env && source .locust_env/bin/activate && pip install locust==2.31.1
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
**3. Execute the Load Test:**
|
|
25
|
-
Trigger the Locust load test with the following command:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
export _AUTH_TOKEN=$(gcloud auth print-access-token -q)
|
|
29
|
-
locust -f tests/load_test/load_test.py \
|
|
30
|
-
--headless \
|
|
31
|
-
-t 30s -u 5 -r 2 \
|
|
32
|
-
--csv=tests/load_test/.results/results \
|
|
33
|
-
--html=tests/load_test/.results/report.html
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
This command initiates a 30-second load test, simulating 2 users spawning per second, reaching a maximum of 10 concurrent users.
|
|
37
|
-
|
|
@@ -1,126 +0,0 @@
|
|
|
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
|
-
import os
|
|
18
|
-
import time
|
|
19
|
-
|
|
20
|
-
from locust import HttpUser, between, task
|
|
21
|
-
|
|
22
|
-
# Configure logging
|
|
23
|
-
logging.basicConfig(
|
|
24
|
-
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
25
|
-
)
|
|
26
|
-
logger = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
|
-
# Initialize Vertex AI and load agent config
|
|
29
|
-
with open("deployment_metadata.json") as f:
|
|
30
|
-
remote_agent_engine_id = json.load(f)["remote_agent_engine_id"]
|
|
31
|
-
|
|
32
|
-
parts = remote_agent_engine_id.split("/")
|
|
33
|
-
project_id = parts[1]
|
|
34
|
-
location = parts[3]
|
|
35
|
-
engine_id = parts[5]
|
|
36
|
-
|
|
37
|
-
# Convert remote agent engine ID to streaming URL.
|
|
38
|
-
base_url = f"https://{location}-aiplatform.googleapis.com"
|
|
39
|
-
url_path = f"/v1/projects/{project_id}/locations/{location}/reasoningEngines/{engine_id}:streamQuery"
|
|
40
|
-
|
|
41
|
-
logger.info("Using remote agent engine ID: %s", remote_agent_engine_id)
|
|
42
|
-
logger.info("Using base URL: %s", base_url)
|
|
43
|
-
logger.info("Using URL path: %s", url_path)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class ChatStreamUser(HttpUser):
|
|
47
|
-
"""Simulates a user interacting with the chat stream API."""
|
|
48
|
-
|
|
49
|
-
wait_time = between(1, 3) # Wait 1-3 seconds between tasks
|
|
50
|
-
host = base_url # Set the base host URL for Locust
|
|
51
|
-
|
|
52
|
-
@task
|
|
53
|
-
def chat_stream(self) -> None:
|
|
54
|
-
"""Simulates a chat stream interaction."""
|
|
55
|
-
headers = {"Content-Type": "application/json"}
|
|
56
|
-
headers["Authorization"] = f"Bearer {os.environ['_AUTH_TOKEN']}"
|
|
57
|
-
{% if "adk" in cookiecutter.tags %}
|
|
58
|
-
data = {
|
|
59
|
-
"class_method": "async_stream_query",
|
|
60
|
-
"input": {
|
|
61
|
-
"user_id": "test",
|
|
62
|
-
"message": "What's the weather in San Francisco?",
|
|
63
|
-
},
|
|
64
|
-
}
|
|
65
|
-
{% else %}
|
|
66
|
-
data = {
|
|
67
|
-
"input": {
|
|
68
|
-
"input": {
|
|
69
|
-
"messages": [
|
|
70
|
-
{"type": "human", "content": "Hello, AI!"},
|
|
71
|
-
{"type": "ai", "content": "Hello!"},
|
|
72
|
-
{"type": "human", "content": "How are you?"},
|
|
73
|
-
]
|
|
74
|
-
},
|
|
75
|
-
"config": {
|
|
76
|
-
"metadata": {"user_id": "test-user", "session_id": "test-session"}
|
|
77
|
-
},
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
{% endif %}
|
|
81
|
-
start_time = time.time()
|
|
82
|
-
with self.client.post(
|
|
83
|
-
url_path,
|
|
84
|
-
headers=headers,
|
|
85
|
-
json=data,
|
|
86
|
-
catch_response=True,
|
|
87
|
-
{%- if "adk" in cookiecutter.tags %}
|
|
88
|
-
name="/streamQuery async_stream_query",
|
|
89
|
-
{%- else %}
|
|
90
|
-
name="/stream_messages first message",
|
|
91
|
-
{%- endif %}
|
|
92
|
-
stream=True,
|
|
93
|
-
params={"alt": "sse"},
|
|
94
|
-
) as response:
|
|
95
|
-
if response.status_code == 200:
|
|
96
|
-
events = []
|
|
97
|
-
for line in response.iter_lines():
|
|
98
|
-
if line:
|
|
99
|
-
line_str = line.decode("utf-8")
|
|
100
|
-
events.append(line_str)
|
|
101
|
-
|
|
102
|
-
if "429 Too Many Requests" in line_str:
|
|
103
|
-
self.environment.events.request.fire(
|
|
104
|
-
request_type="POST",
|
|
105
|
-
name=f"{url_path} rate_limited 429s",
|
|
106
|
-
response_time=0,
|
|
107
|
-
response_length=len(line),
|
|
108
|
-
response=response,
|
|
109
|
-
context={},
|
|
110
|
-
)
|
|
111
|
-
end_time = time.time()
|
|
112
|
-
total_time = end_time - start_time
|
|
113
|
-
self.environment.events.request.fire(
|
|
114
|
-
request_type="POST",
|
|
115
|
-
{%- if "adk" in cookiecutter.tags %}
|
|
116
|
-
name="/streamQuery end",
|
|
117
|
-
{%- else %}
|
|
118
|
-
name="/stream_messages end",
|
|
119
|
-
{%- endif %}
|
|
120
|
-
response_time=total_time * 1000, # Convert to milliseconds
|
|
121
|
-
response_length=len(events),
|
|
122
|
-
response=response,
|
|
123
|
-
context={},
|
|
124
|
-
)
|
|
125
|
-
else:
|
|
126
|
-
response.failure(f"Unexpected status code: {response.status_code}")
|
|
@@ -1,122 +0,0 @@
|
|
|
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 os
|
|
16
|
-
import time
|
|
17
|
-
{%- if "adk" in cookiecutter.tags %}
|
|
18
|
-
import uuid
|
|
19
|
-
|
|
20
|
-
import requests
|
|
21
|
-
from locust import HttpUser, between, task
|
|
22
|
-
{%- else %}
|
|
23
|
-
|
|
24
|
-
from locust import HttpUser, between, task
|
|
25
|
-
{%- endif %}
|
|
26
|
-
{% if "adk" in cookiecutter.tags %}
|
|
27
|
-
ENDPOINT = "/run_sse"
|
|
28
|
-
{% else %}
|
|
29
|
-
ENDPOINT = "/stream_messages"
|
|
30
|
-
{% endif %}
|
|
31
|
-
|
|
32
|
-
class ChatStreamUser(HttpUser):
|
|
33
|
-
"""Simulates a user interacting with the chat stream API."""
|
|
34
|
-
|
|
35
|
-
wait_time = between(1, 3) # Wait 1-3 seconds between tasks
|
|
36
|
-
|
|
37
|
-
@task
|
|
38
|
-
def chat_stream(self) -> None:
|
|
39
|
-
"""Simulates a chat stream interaction."""
|
|
40
|
-
headers = {"Content-Type": "application/json"}
|
|
41
|
-
if os.environ.get("_ID_TOKEN"):
|
|
42
|
-
headers["Authorization"] = f"Bearer {os.environ['_ID_TOKEN']}"
|
|
43
|
-
{%- if "adk" in cookiecutter.tags %}
|
|
44
|
-
# Create session first
|
|
45
|
-
user_id = f"user_{uuid.uuid4()}"
|
|
46
|
-
session_data = {"state": {"preferred_language": "English", "visit_count": 1}}
|
|
47
|
-
|
|
48
|
-
session_url = f"{self.client.base_url}/apps/{{cookiecutter.agent_directory}}/users/{user_id}/sessions"
|
|
49
|
-
session_response = requests.post(
|
|
50
|
-
session_url,
|
|
51
|
-
headers=headers,
|
|
52
|
-
json=session_data,
|
|
53
|
-
timeout=10,
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
# Get session_id from response
|
|
57
|
-
session_id = session_response.json()["id"]
|
|
58
|
-
|
|
59
|
-
# Send chat message
|
|
60
|
-
data = {
|
|
61
|
-
"app_name": "{{cookiecutter.agent_directory}}",
|
|
62
|
-
"user_id": user_id,
|
|
63
|
-
"session_id": session_id,
|
|
64
|
-
"new_message": {
|
|
65
|
-
"role": "user",
|
|
66
|
-
"parts": [{"text": "Hello! Weather in New york?"}],
|
|
67
|
-
},
|
|
68
|
-
"streaming": True,
|
|
69
|
-
}
|
|
70
|
-
{%- else %}
|
|
71
|
-
data = {
|
|
72
|
-
"input": {
|
|
73
|
-
"messages": [
|
|
74
|
-
{"type": "human", "content": "Hello, AI!"},
|
|
75
|
-
{"type": "ai", "content": "Hello!"},
|
|
76
|
-
{"type": "human", "content": "Who are you?"},
|
|
77
|
-
]
|
|
78
|
-
},
|
|
79
|
-
"config": {
|
|
80
|
-
"metadata": {"user_id": "test-user", "session_id": "test-session"}
|
|
81
|
-
},
|
|
82
|
-
}
|
|
83
|
-
{%- endif %}
|
|
84
|
-
start_time = time.time()
|
|
85
|
-
|
|
86
|
-
with self.client.post(
|
|
87
|
-
ENDPOINT,
|
|
88
|
-
name=f"{ENDPOINT} message",
|
|
89
|
-
headers=headers,
|
|
90
|
-
json=data,
|
|
91
|
-
catch_response=True,
|
|
92
|
-
stream=True,
|
|
93
|
-
params={"alt": "sse"},
|
|
94
|
-
) as response:
|
|
95
|
-
if response.status_code == 200:
|
|
96
|
-
events = []
|
|
97
|
-
for line in response.iter_lines():
|
|
98
|
-
if line:
|
|
99
|
-
line_str = line.decode("utf-8")
|
|
100
|
-
events.append(line_str)
|
|
101
|
-
|
|
102
|
-
if "429 Too Many Requests" in line_str:
|
|
103
|
-
self.environment.events.request.fire(
|
|
104
|
-
request_type="POST",
|
|
105
|
-
name=f"{ENDPOINT} rate_limited 429s",
|
|
106
|
-
response_time=0,
|
|
107
|
-
response_length=len(line),
|
|
108
|
-
response=response,
|
|
109
|
-
context={},
|
|
110
|
-
)
|
|
111
|
-
end_time = time.time()
|
|
112
|
-
total_time = end_time - start_time
|
|
113
|
-
self.environment.events.request.fire(
|
|
114
|
-
request_type="POST",
|
|
115
|
-
name=f"{ENDPOINT} end",
|
|
116
|
-
response_time=total_time * 1000, # Convert to milliseconds
|
|
117
|
-
response_length=len(events),
|
|
118
|
-
response=response,
|
|
119
|
-
context={},
|
|
120
|
-
)
|
|
121
|
-
else:
|
|
122
|
-
response.failure(f"Unexpected status code: {response.status_code}")
|
src/resources/idx/.idx/dev.nix
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# To learn more about how to use Nix to configure your environment
|
|
3
|
-
# see: https://firebase.google.com/docs/studio/customize-workspace
|
|
4
|
-
{ pkgs, ... }: {
|
|
5
|
-
# Which nixpkgs channel to use.
|
|
6
|
-
channel = "stable-24.11"; # or "unstable"
|
|
7
|
-
|
|
8
|
-
# Use https://search.nixos.org/packages to find packages
|
|
9
|
-
packages = [
|
|
10
|
-
pkgs.uv
|
|
11
|
-
pkgs.gnumake
|
|
12
|
-
pkgs.terraform
|
|
13
|
-
pkgs.gh
|
|
14
|
-
];
|
|
15
|
-
# Sets environment variables in the workspace
|
|
16
|
-
env = {};
|
|
17
|
-
idx = {
|
|
18
|
-
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
|
|
19
|
-
extensions = [
|
|
20
|
-
"ms-toolsai.jupyter"
|
|
21
|
-
"ms-python.python"
|
|
22
|
-
"krish-r.vscode-toggle-terminal"
|
|
23
|
-
];
|
|
24
|
-
workspace = {
|
|
25
|
-
# Runs when a workspace is first created with this `dev.nix` file
|
|
26
|
-
onCreate = {
|
|
27
|
-
create-venv = ''
|
|
28
|
-
# Load environment variables from .env file if it exists
|
|
29
|
-
source .env
|
|
30
|
-
echo "Logging into gcloud..."
|
|
31
|
-
echo "Please authenticate with Google Cloud by following the prompts."
|
|
32
|
-
gcloud auth login --update-adc --brief --quiet
|
|
33
|
-
|
|
34
|
-
echo "Setting gcloud project..."
|
|
35
|
-
gcloud config set project $GOOGLE_CLOUD_PROJECT
|
|
36
|
-
|
|
37
|
-
echo "Running agent starter pack creation..."
|
|
38
|
-
uvx agent-starter-pack create $AGENT_NAME
|
|
39
|
-
code ~/$WS_NAME/$AGENT_NAME/README.md
|
|
40
|
-
exec bash
|
|
41
|
-
'';
|
|
42
|
-
# Open editors for the following files by default, if they exist:
|
|
43
|
-
default.openFiles = [];
|
|
44
|
-
};
|
|
45
|
-
# To run something each time the workspace is (re)started, use the `onStart` hook
|
|
46
|
-
};
|
|
47
|
-
# Enable previews and customize configuration
|
|
48
|
-
previews = {};
|
|
49
|
-
};
|
|
50
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Agent Starter Pack",
|
|
3
|
-
"description": "Production-ready Gen AI Agent templates for Google Cloud. Addressing common challenges (Deployment & Operations, Evaluation, Customization, Observability) in building and deploying GenAI agents.",
|
|
4
|
-
"icon": "https://github.com/GoogleCloudPlatform/agent-starter-pack/blob/main/docs/images/icon.png?raw=true",
|
|
5
|
-
"params": [
|
|
6
|
-
{
|
|
7
|
-
"id": "agent_name",
|
|
8
|
-
"name": "Agent Name",
|
|
9
|
-
"description": "The name of the agent being created.",
|
|
10
|
-
"type": "string",
|
|
11
|
-
"required": true
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"id": "google_cloud_project_id",
|
|
15
|
-
"name": "Your Google Cloud Project ID",
|
|
16
|
-
"description": "The Google Cloud Platform Project ID where resources will be managed.",
|
|
17
|
-
"type": "string",
|
|
18
|
-
"required": true
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|