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
{src → agent_starter_pack}/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/server.py
RENAMED
|
@@ -11,26 +11,33 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
{% if cookiecutter.agent_name == "
|
|
14
|
+
{% if cookiecutter.agent_name == "adk_live" %}
|
|
15
15
|
import asyncio
|
|
16
16
|
import json
|
|
17
17
|
import logging
|
|
18
18
|
from collections.abc import Callable
|
|
19
19
|
from pathlib import Path
|
|
20
|
-
from typing import Any, Literal
|
|
21
20
|
|
|
22
21
|
import backoff
|
|
22
|
+
import google.auth
|
|
23
23
|
from fastapi import FastAPI, HTTPException, WebSocket
|
|
24
24
|
from fastapi.middleware.cors import CORSMiddleware
|
|
25
25
|
from fastapi.responses import FileResponse
|
|
26
26
|
from fastapi.staticfiles import StaticFiles
|
|
27
|
+
from google.adk.agents.live_request_queue import LiveRequest, LiveRequestQueue
|
|
28
|
+
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
|
|
29
|
+
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
|
|
30
|
+
from google.adk.runners import Runner
|
|
31
|
+
from google.adk.sessions.in_memory_session_service import InMemorySessionService
|
|
27
32
|
from google.cloud import logging as google_cloud_logging
|
|
28
|
-
from
|
|
29
|
-
from
|
|
30
|
-
from
|
|
33
|
+
from opentelemetry import trace
|
|
34
|
+
from opentelemetry.sdk.trace import TracerProvider, export
|
|
35
|
+
from vertexai.agent_engines import _utils
|
|
31
36
|
from websockets.exceptions import ConnectionClosedError
|
|
32
37
|
|
|
33
|
-
from .agent import
|
|
38
|
+
from .agent import root_agent
|
|
39
|
+
from .utils.tracing import CloudTraceLoggingSpanExporter
|
|
40
|
+
from .utils.typing import Feedback
|
|
34
41
|
|
|
35
42
|
app = FastAPI()
|
|
36
43
|
app.add_middleware(
|
|
@@ -55,118 +62,169 @@ logging_client = google_cloud_logging.Client()
|
|
|
55
62
|
logger = logging_client.logger(__name__)
|
|
56
63
|
logging.basicConfig(level=logging.INFO)
|
|
57
64
|
|
|
65
|
+
_, project_id = google.auth.default()
|
|
66
|
+
provider = TracerProvider()
|
|
67
|
+
processor = export.BatchSpanProcessor(
|
|
68
|
+
CloudTraceLoggingSpanExporter(project_id=project_id)
|
|
69
|
+
)
|
|
70
|
+
provider.add_span_processor(processor)
|
|
71
|
+
trace.set_tracer_provider(provider)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Initialize ADK services
|
|
75
|
+
session_service = InMemorySessionService()
|
|
76
|
+
artifact_service = InMemoryArtifactService()
|
|
77
|
+
memory_service = InMemoryMemoryService()
|
|
78
|
+
|
|
79
|
+
# Initialize ADK runner
|
|
80
|
+
runner = Runner(
|
|
81
|
+
agent=root_agent,
|
|
82
|
+
session_service=session_service,
|
|
83
|
+
artifact_service=artifact_service,
|
|
84
|
+
memory_service=memory_service,
|
|
85
|
+
app_name="live-app",
|
|
86
|
+
)
|
|
58
87
|
|
|
59
|
-
class GeminiSession:
|
|
60
|
-
"""Manages bidirectional communication between a client and the Gemini model."""
|
|
61
88
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
89
|
+
class AgentSession:
|
|
90
|
+
"""Manages bidirectional communication between a client and the agent."""
|
|
91
|
+
|
|
92
|
+
def __init__(self, websocket: WebSocket) -> None:
|
|
93
|
+
"""Initialize the agent session.
|
|
66
94
|
|
|
67
95
|
Args:
|
|
68
|
-
session: The Gemini session
|
|
69
96
|
websocket: The client websocket connection
|
|
70
|
-
user_id: Unique identifier for this client
|
|
71
|
-
tool_functions: Dictionary of available tool functions
|
|
72
97
|
"""
|
|
73
|
-
self.session = session
|
|
74
98
|
self.websocket = websocket
|
|
75
|
-
self.
|
|
76
|
-
self.user_id =
|
|
77
|
-
self.
|
|
78
|
-
self._tool_tasks: list[asyncio.Task] = []
|
|
99
|
+
self.input_queue: asyncio.Queue[dict] = asyncio.Queue()
|
|
100
|
+
self.user_id: str | None = None
|
|
101
|
+
self.session_id: str | None = None
|
|
79
102
|
|
|
80
103
|
async def receive_from_client(self) -> None:
|
|
81
|
-
"""Listen for and
|
|
82
|
-
|
|
83
|
-
Continuously receives messages and forwards audio data to Gemini.
|
|
84
|
-
Handles connection errors gracefully.
|
|
85
|
-
"""
|
|
104
|
+
"""Listen for messages from the client and put them in the queue."""
|
|
86
105
|
while True:
|
|
87
106
|
try:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
message = await self.websocket.receive()
|
|
108
|
+
|
|
109
|
+
if "text" in message:
|
|
110
|
+
data = json.loads(message["text"])
|
|
111
|
+
|
|
112
|
+
if isinstance(data, dict):
|
|
113
|
+
# Skip setup messages - they're for backend logging only
|
|
114
|
+
if "setup" in data:
|
|
115
|
+
logger.log_struct(
|
|
116
|
+
{**data["setup"], "type": "setup"}, severity="INFO"
|
|
117
|
+
)
|
|
118
|
+
logging.info(
|
|
119
|
+
"Received setup message (not forwarding to agent)"
|
|
120
|
+
)
|
|
121
|
+
continue
|
|
122
|
+
|
|
123
|
+
# Forward message to agent engine
|
|
124
|
+
await self.input_queue.put(data)
|
|
125
|
+
else:
|
|
126
|
+
logging.warning(
|
|
127
|
+
f"Received unexpected JSON structure from client: {data}"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
elif "bytes" in message:
|
|
131
|
+
# Handle binary data
|
|
132
|
+
await self.input_queue.put({"binary_data": message["bytes"]})
|
|
133
|
+
|
|
100
134
|
else:
|
|
101
|
-
logging.warning(
|
|
135
|
+
logging.warning(
|
|
136
|
+
f"Received unexpected message type from client: {message}"
|
|
137
|
+
)
|
|
138
|
+
|
|
102
139
|
except ConnectionClosedError as e:
|
|
103
|
-
logging.warning(f"Client
|
|
140
|
+
logging.warning(f"Client closed connection: {e}")
|
|
141
|
+
break
|
|
142
|
+
except json.JSONDecodeError as e:
|
|
143
|
+
logging.error(f"Error parsing JSON from client: {e}")
|
|
104
144
|
break
|
|
105
145
|
except Exception as e:
|
|
106
|
-
logging.error(f"Error receiving from client
|
|
146
|
+
logging.error(f"Error receiving from client: {e!s}")
|
|
107
147
|
break
|
|
108
148
|
|
|
109
|
-
def
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
message = types.LiveServerMessage.model_validate(raw_message)
|
|
154
|
-
tool_call = LiveServerToolCall.model_validate(message.tool_call)
|
|
155
|
-
# Create a separate task to handle the tool call without blocking
|
|
156
|
-
task = asyncio.create_task(
|
|
157
|
-
self._handle_tool_call(self.session, tool_call)
|
|
149
|
+
async def run_agent(self) -> None:
|
|
150
|
+
"""Run the agent with the input queue using bidi_stream_query protocol."""
|
|
151
|
+
try:
|
|
152
|
+
# Send setupComplete immediately
|
|
153
|
+
setup_complete_response: dict = {"setupComplete": {}}
|
|
154
|
+
await self.websocket.send_json(setup_complete_response)
|
|
155
|
+
|
|
156
|
+
# Wait for first request with user_id
|
|
157
|
+
first_request = await self.input_queue.get()
|
|
158
|
+
self.user_id = first_request.get("user_id")
|
|
159
|
+
if not self.user_id:
|
|
160
|
+
raise ValueError("The first request must have a user_id.")
|
|
161
|
+
|
|
162
|
+
self.session_id = first_request.get("session_id")
|
|
163
|
+
first_live_request = first_request.get("live_request")
|
|
164
|
+
|
|
165
|
+
# Create session if needed
|
|
166
|
+
if not self.session_id:
|
|
167
|
+
session = await session_service.create_session(
|
|
168
|
+
app_name="live-app",
|
|
169
|
+
user_id=self.user_id,
|
|
170
|
+
)
|
|
171
|
+
self.session_id = session.id
|
|
172
|
+
|
|
173
|
+
# Create LiveRequestQueue
|
|
174
|
+
live_request_queue = LiveRequestQueue()
|
|
175
|
+
|
|
176
|
+
# Add first live request if present
|
|
177
|
+
if first_live_request and isinstance(first_live_request, dict):
|
|
178
|
+
live_request_queue.send(LiveRequest.model_validate(first_live_request))
|
|
179
|
+
|
|
180
|
+
# Forward requests from input_queue to live_request_queue
|
|
181
|
+
async def _forward_requests() -> None:
|
|
182
|
+
while True:
|
|
183
|
+
request = await self.input_queue.get()
|
|
184
|
+
live_request = LiveRequest.model_validate(request)
|
|
185
|
+
live_request_queue.send(live_request)
|
|
186
|
+
|
|
187
|
+
# Forward events from agent to websocket
|
|
188
|
+
async def _forward_events() -> None:
|
|
189
|
+
events_async = runner.run_live(
|
|
190
|
+
user_id=self.user_id,
|
|
191
|
+
session_id=self.session_id,
|
|
192
|
+
live_request_queue=live_request_queue,
|
|
158
193
|
)
|
|
159
|
-
|
|
194
|
+
async for event in events_async:
|
|
195
|
+
event_dict = _utils.dump_event_for_json(event)
|
|
196
|
+
await self.websocket.send_json(event_dict)
|
|
197
|
+
|
|
198
|
+
# Check for error responses
|
|
199
|
+
if isinstance(event_dict, dict) and "error" in event_dict:
|
|
200
|
+
logging.error(f"Agent error: {event_dict['error']}")
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
# Run both tasks
|
|
204
|
+
requests_task = asyncio.create_task(_forward_requests())
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
await _forward_events()
|
|
208
|
+
finally:
|
|
209
|
+
requests_task.cancel()
|
|
210
|
+
try:
|
|
211
|
+
await requests_task
|
|
212
|
+
except asyncio.CancelledError:
|
|
213
|
+
pass
|
|
214
|
+
|
|
215
|
+
except Exception as e:
|
|
216
|
+
logging.error(f"Error in agent: {e}")
|
|
217
|
+
await self.websocket.send_json({"error": str(e)})
|
|
160
218
|
|
|
161
219
|
|
|
162
220
|
def get_connect_and_run_callable(websocket: WebSocket) -> Callable:
|
|
163
|
-
"""Create a callable that handles
|
|
221
|
+
"""Create a callable that handles agent connection with retry logic.
|
|
164
222
|
|
|
165
223
|
Args:
|
|
166
224
|
websocket: The client websocket connection
|
|
167
225
|
|
|
168
226
|
Returns:
|
|
169
|
-
Callable: An async function that establishes and manages the
|
|
227
|
+
Callable: An async function that establishes and manages the agent connection
|
|
170
228
|
"""
|
|
171
229
|
|
|
172
230
|
async def on_backoff(details: backoff._typing.Details) -> None:
|
|
@@ -180,18 +238,14 @@ def get_connect_and_run_callable(websocket: WebSocket) -> Callable:
|
|
|
180
238
|
backoff.expo, ConnectionClosedError, max_tries=10, on_backoff=on_backoff
|
|
181
239
|
)
|
|
182
240
|
async def connect_and_run() -> None:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
await asyncio.gather(
|
|
192
|
-
gemini_session.receive_from_client(),
|
|
193
|
-
gemini_session.receive_from_gemini(),
|
|
194
|
-
)
|
|
241
|
+
logging.info("Starting ADK agent")
|
|
242
|
+
session = AgentSession(websocket)
|
|
243
|
+
|
|
244
|
+
logging.info("Starting bidirectional communication with agent")
|
|
245
|
+
await asyncio.gather(
|
|
246
|
+
session.receive_from_client(),
|
|
247
|
+
session.run_agent(),
|
|
248
|
+
)
|
|
195
249
|
|
|
196
250
|
return connect_and_run
|
|
197
251
|
|
|
@@ -204,15 +258,38 @@ async def websocket_endpoint(websocket: WebSocket) -> None:
|
|
|
204
258
|
await connect_and_run()
|
|
205
259
|
|
|
206
260
|
|
|
207
|
-
|
|
208
|
-
|
|
261
|
+
@app.get("/")
|
|
262
|
+
async def serve_frontend_root() -> FileResponse:
|
|
263
|
+
"""Serve the frontend index.html at the root path."""
|
|
264
|
+
index_file = frontend_build_dir / "index.html"
|
|
265
|
+
if index_file.exists():
|
|
266
|
+
return FileResponse(str(index_file))
|
|
267
|
+
raise HTTPException(
|
|
268
|
+
status_code=404,
|
|
269
|
+
detail="Frontend not built. Run 'npm run build' in the frontend directory.",
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@app.get("/{full_path:path}")
|
|
274
|
+
async def serve_frontend_spa(full_path: str) -> FileResponse:
|
|
275
|
+
"""Catch-all route to serve the frontend for SPA routing.
|
|
276
|
+
|
|
277
|
+
This ensures that client-side routes are handled by the React app.
|
|
278
|
+
Excludes API routes (ws, feedback) and static assets.
|
|
279
|
+
"""
|
|
280
|
+
# Don't intercept API routes
|
|
281
|
+
if full_path.startswith(("ws", "feedback", "static", "api")):
|
|
282
|
+
raise HTTPException(status_code=404, detail="Not found")
|
|
209
283
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
284
|
+
# Serve index.html for all other routes (SPA routing)
|
|
285
|
+
index_file = frontend_build_dir / "index.html"
|
|
286
|
+
if index_file.exists():
|
|
287
|
+
return FileResponse(str(index_file))
|
|
288
|
+
raise HTTPException(
|
|
289
|
+
status_code=404,
|
|
290
|
+
detail="Frontend not built. Run 'npm run build' in the frontend directory.",
|
|
291
|
+
)
|
|
292
|
+
{% elif cookiecutter.is_adk %}
|
|
216
293
|
import os
|
|
217
294
|
|
|
218
295
|
import google.auth
|
|
@@ -358,7 +435,7 @@ def stream_messages(
|
|
|
358
435
|
set_tracing_properties(config)
|
|
359
436
|
input_dict = input.model_dump()
|
|
360
437
|
|
|
361
|
-
for data in agent.stream(input_dict, config=config, stream_mode="messages"):
|
|
438
|
+
for data in agent.stream(input_dict, config=config, stream_mode="messages"):
|
|
362
439
|
yield dumps(data) + "\n"
|
|
363
440
|
|
|
364
441
|
|
|
@@ -397,40 +474,7 @@ def collect_feedback(feedback: Feedback) -> dict[str, str]:
|
|
|
397
474
|
"""
|
|
398
475
|
logger.log_struct(feedback.model_dump(), severity="INFO")
|
|
399
476
|
return {"status": "success"}
|
|
400
|
-
{% if cookiecutter.agent_name == "live_api" %}
|
|
401
477
|
|
|
402
|
-
@app.get("/")
|
|
403
|
-
async def serve_frontend_root() -> FileResponse:
|
|
404
|
-
"""Serve the frontend index.html at the root path."""
|
|
405
|
-
index_file = frontend_build_dir / "index.html"
|
|
406
|
-
if index_file.exists():
|
|
407
|
-
return FileResponse(str(index_file))
|
|
408
|
-
raise HTTPException(
|
|
409
|
-
status_code=404,
|
|
410
|
-
detail="Frontend not built. Run 'npm run build' in the frontend directory.",
|
|
411
|
-
)
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
@app.get("/{full_path:path}")
|
|
415
|
-
async def serve_frontend_spa(full_path: str) -> FileResponse:
|
|
416
|
-
"""Catch-all route to serve the frontend for SPA routing.
|
|
417
|
-
|
|
418
|
-
This ensures that client-side routes are handled by the React app.
|
|
419
|
-
Excludes API routes (ws, feedback) and static assets.
|
|
420
|
-
"""
|
|
421
|
-
# Don't intercept API routes
|
|
422
|
-
if full_path.startswith(("ws", "feedback", "static", "api")):
|
|
423
|
-
raise HTTPException(status_code=404, detail="Not found")
|
|
424
|
-
|
|
425
|
-
# Serve index.html for all other routes (SPA routing)
|
|
426
|
-
index_file = frontend_build_dir / "index.html"
|
|
427
|
-
if index_file.exists():
|
|
428
|
-
return FileResponse(str(index_file))
|
|
429
|
-
raise HTTPException(
|
|
430
|
-
status_code=404,
|
|
431
|
-
detail="Frontend not built. Run 'npm run build' in the frontend directory.",
|
|
432
|
-
)
|
|
433
|
-
{% endif %}
|
|
434
478
|
|
|
435
479
|
# Main execution
|
|
436
480
|
if __name__ == "__main__":
|