agent-starter-pack 0.3.3__py3-none-any.whl → 0.21.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.
- agent_starter_pack/agents/README.md +7 -0
- agents/langgraph_base_react/template/.templateconfig.yaml → agent_starter_pack/agents/adk_a2a_base/.template/templateconfig.yaml +5 -10
- agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
- src/deployment_targets/cloud_run/Dockerfile → agent_starter_pack/agents/adk_a2a_base/app/__init__.py +2 -14
- agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
- agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
- agents/crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → agent_starter_pack/agents/adk_a2a_base/notebooks/evaluating_adk_agent.ipynb +163 -199
- {agents/adk_base → agent_starter_pack/agents/adk_a2a_base}/tests/integration/test_agent.py +2 -2
- agents/adk_base/template/.templateconfig.yaml → agent_starter_pack/agents/adk_base/.template/templateconfig.yaml +4 -1
- {agents → agent_starter_pack/agents}/adk_base/README.md +1 -1
- agent_starter_pack/agents/adk_base/app/__init__.py +17 -0
- {agents → agent_starter_pack/agents}/adk_base/app/agent.py +5 -2
- {agents → agent_starter_pack/agents}/adk_base/notebooks/adk_app_testing.ipynb +128 -82
- agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb → agent_starter_pack/agents/adk_base/notebooks/evaluating_adk_agent.ipynb +181 -207
- agent_starter_pack/agents/adk_base/tests/integration/test_agent.py +58 -0
- agents/crewai_coding_crew/template/.templateconfig.yaml → agent_starter_pack/agents/adk_live/.template/templateconfig.yaml +5 -9
- agent_starter_pack/agents/adk_live/README.md +32 -0
- agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
- agent_starter_pack/agents/adk_live/app/agent.py +51 -0
- agent_starter_pack/agents/adk_live/tests/unit/test_dummy.py +38 -0
- agents/agentic_rag/template/.templateconfig.yaml → agent_starter_pack/agents/agentic_rag/.template/templateconfig.yaml +7 -3
- {agents → agent_starter_pack/agents}/agentic_rag/README.md +1 -1
- agent_starter_pack/agents/agentic_rag/app/__init__.py +17 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/agent.py +8 -4
- {agents → agent_starter_pack/agents}/agentic_rag/notebooks/adk_app_testing.ipynb +128 -82
- agent_starter_pack/agents/agentic_rag/notebooks/evaluating_adk_agent.ipynb +1535 -0
- {agents → agent_starter_pack/agents}/agentic_rag/tests/integration/test_agent.py +3 -3
- agent_starter_pack/agents/langgraph_base/.template/templateconfig.yaml +31 -0
- agent_starter_pack/agents/langgraph_base/README.md +30 -0
- agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
- agent_starter_pack/agents/langgraph_base/app/agent.py +34 -0
- {agents/crewai_coding_crew → agent_starter_pack/agents/langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +30 -17
- {agents/langgraph_base_react → agent_starter_pack/agents/langgraph_base}/tests/integration/test_agent.py +2 -2
- {src → agent_starter_pack}/base_template/.gitignore +5 -3
- agent_starter_pack/base_template/GEMINI.md +5 -0
- agent_starter_pack/base_template/Makefile +339 -0
- agent_starter_pack/base_template/README.md +267 -0
- agent_starter_pack/base_template/deployment/README.md +11 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/apis.tf +2 -2
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/apis.tf +6 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/iam.tf +12 -11
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/providers.tf +5 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/storage.tf +1 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/variables.tf +10 -10
- agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
- agent_starter_pack/base_template/deployment/terraform/github.tf +337 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/iam.tf +20 -41
- {src → agent_starter_pack}/base_template/deployment/terraform/locals.tf +10 -3
- {src/resources/setup_cicd → agent_starter_pack/base_template/deployment/terraform}/providers.tf +8 -1
- {src → agent_starter_pack}/base_template/deployment/terraform/service_accounts.tf +7 -8
- agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/storage.tf +7 -16
- {src → agent_starter_pack}/base_template/deployment/terraform/variables.tf +61 -28
- {src → agent_starter_pack}/base_template/deployment/terraform/vars/env.tfvars +6 -1
- agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +43 -0
- src/base_template/deployment/terraform/build_triggers.tf → agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}build_triggers.tf{% else %}unused_build_triggers.tf{% endif %} +55 -38
- agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
- {src → agent_starter_pack}/base_template/pyproject.toml +24 -37
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +132 -0
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +65 -0
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +259 -0
- src/base_template/deployment/cd/deploy-to-prod.yaml → agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/deploy-to-prod.yaml +38 -30
- src/base_template/deployment/ci/pr_checks.yaml → agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/pr_checks.yaml +5 -5
- agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +322 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
- {src/base_template/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/typing.py +7 -9
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/__init__.py +25 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}converters{% else %}unused_converters{% endif %}/part_converter.py +138 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/__init__.py +13 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/a2a_agent_executor.py +265 -0
- agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_a2a and cookiecutter.agent_name == 'langgraph_base' %}executor{% else %}unused_executor{% endif %}/task_result_aggregator.py +152 -0
- agent_starter_pack/cli/commands/create.py +1256 -0
- agent_starter_pack/cli/commands/enhance.py +611 -0
- agent_starter_pack/cli/commands/list.py +203 -0
- agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
- agent_starter_pack/cli/commands/setup_cicd.py +862 -0
- {src → agent_starter_pack}/cli/main.py +10 -2
- {src → agent_starter_pack}/cli/utils/cicd.py +139 -48
- agent_starter_pack/cli/utils/gcp.py +263 -0
- agent_starter_pack/cli/utils/logging.py +103 -0
- agent_starter_pack/cli/utils/remote_template.py +677 -0
- agent_starter_pack/cli/utils/template.py +1466 -0
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/process_data.py +1 -1
- {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/submit_pipeline.py +20 -6
- {src → agent_starter_pack}/data_ingestion/pyproject.toml +1 -0
- {src → agent_starter_pack}/data_ingestion/uv.lock +602 -494
- agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +484 -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 +424 -0
- agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +263 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
- agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/{% if cookiecutter.is_adk_live %}expose_app.py{% else %}unused_expose_app.py{% endif %} +519 -0
- agent_starter_pack/deployment_targets/cloud_run/Dockerfile +51 -0
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +243 -0
- agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +417 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +705 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +321 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +165 -0
- agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +329 -0
- agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/fast_api_app.py +556 -0
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package-lock.json +79 -1044
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package.json +1 -9
- agent_starter_pack/frontends/adk_live_react/frontend/src/App.tsx +65 -0
- {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
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/SidePanel.tsx +516 -0
- agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/side-panel.scss +563 -0
- 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 +40 -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 +210 -24
- {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/utils.ts +27 -5
- agent_starter_pack/resources/docs/adk-cheatsheet.md +1628 -0
- agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
- agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
- agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +4946 -0
- agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +4991 -0
- agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +4963 -0
- agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +5006 -0
- agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +5487 -0
- agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +5532 -0
- agent_starter_pack/resources/locks/uv-langgraph_base-agent_engine.lock +5788 -0
- agent_starter_pack/resources/locks/uv-langgraph_base-cloud_run.lock +5811 -0
- {src → agent_starter_pack}/utils/generate_locks.py +15 -12
- {src → agent_starter_pack}/utils/lock_utils.py +4 -7
- {src → agent_starter_pack}/utils/watch_and_rebuild.py +2 -2
- agent_starter_pack-0.21.0.dist-info/METADATA +182 -0
- agent_starter_pack-0.21.0.dist-info/RECORD +171 -0
- agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
- llm.txt +362 -0
- agent_starter_pack-0.3.3.dist-info/METADATA +0 -164
- agent_starter_pack-0.3.3.dist-info/RECORD +0 -176
- agent_starter_pack-0.3.3.dist-info/entry_points.txt +0 -2
- agents/crewai_coding_crew/README.md +0 -34
- agents/crewai_coding_crew/app/agent.py +0 -86
- agents/crewai_coding_crew/app/crew/config/agents.yaml +0 -39
- agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
- agents/crewai_coding_crew/app/crew/crew.py +0 -71
- agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
- agents/langgraph_base_react/README.md +0 -9
- agents/langgraph_base_react/app/agent.py +0 -73
- agents/live_api/README.md +0 -37
- agents/live_api/app/agent.py +0 -78
- agents/live_api/app/server.py +0 -196
- agents/live_api/app/templates.py +0 -51
- agents/live_api/app/vector_store.py +0 -55
- agents/live_api/template/.templateconfig.yaml +0 -29
- agents/live_api/tests/integration/test_server_e2e.py +0 -254
- agents/live_api/tests/load_test/load_test.py +0 -40
- agents/live_api/tests/unit/test_server.py +0 -143
- src/base_template/Makefile +0 -72
- src/base_template/README.md +0 -208
- src/base_template/app/__init__.py +0 -3
- src/base_template/app/utils/tracing.py +0 -155
- src/base_template/deployment/README.md +0 -126
- src/base_template/deployment/cd/staging.yaml +0 -216
- src/base_template/deployment/terraform/dev/log_sinks.tf +0 -63
- src/base_template/deployment/terraform/log_sinks.tf +0 -70
- src/base_template/deployment/terraform/providers.tf +0 -37
- src/cli/commands/create.py +0 -664
- src/cli/commands/setup_cicd.py +0 -829
- src/cli/utils/gcp.py +0 -117
- src/cli/utils/logging.py +0 -51
- src/cli/utils/template.py +0 -737
- src/deployment_targets/agent_engine/app/agent_engine_app.py +0 -336
- src/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
- src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +0 -183
- src/deployment_targets/agent_engine/tests/load_test/README.md +0 -42
- src/deployment_targets/agent_engine/tests/load_test/load_test.py +0 -107
- src/deployment_targets/cloud_run/app/server.py +0 -154
- src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +0 -249
- src/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +0 -0
- src/deployment_targets/cloud_run/tests/load_test/README.md +0 -83
- src/deployment_targets/cloud_run/tests/load_test/load_test.py +0 -118
- src/deployment_targets/cloud_run/uv.lock +0 -6952
- src/frontends/live_api_react/frontend/src/App.tsx +0 -205
- src/frontends/live_api_react/frontend/src/components/control-tray/ControlTray.tsx +0 -217
- src/frontends/live_api_react/frontend/src/components/control-tray/control-tray.scss +0 -201
- src/frontends/live_api_react/frontend/src/components/side-panel/SidePanel.tsx +0 -161
- src/frontends/live_api_react/frontend/src/components/side-panel/side-panel.scss +0 -285
- src/frontends/streamlit/frontend/side_bar.py +0 -214
- src/frontends/streamlit/frontend/streamlit_app.py +0 -265
- src/frontends/streamlit/frontend/style/app_markdown.py +0 -37
- src/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
- src/frontends/streamlit/frontend/utils/local_chat_history.py +0 -125
- src/frontends/streamlit/frontend/utils/message_editing.py +0 -59
- src/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
- src/frontends/streamlit/frontend/utils/stream_handler.py +0 -301
- src/frontends/streamlit/frontend/utils/title_summary.py +0 -94
- src/frontends/streamlit_adk/frontend/side_bar.py +0 -214
- src/frontends/streamlit_adk/frontend/streamlit_app.py +0 -314
- src/frontends/streamlit_adk/frontend/style/app_markdown.py +0 -37
- src/frontends/streamlit_adk/frontend/utils/chat_utils.py +0 -84
- src/frontends/streamlit_adk/frontend/utils/local_chat_history.py +0 -110
- src/frontends/streamlit_adk/frontend/utils/message_editing.py +0 -61
- src/frontends/streamlit_adk/frontend/utils/multimodal_utils.py +0 -223
- src/frontends/streamlit_adk/frontend/utils/stream_handler.py +0 -311
- src/frontends/streamlit_adk/frontend/utils/title_summary.py +0 -129
- src/resources/containers/data_processing/Dockerfile +0 -27
- src/resources/containers/e2e-tests/Dockerfile +0 -19
- src/resources/idx/.idx/dev.nix +0 -57
- src/resources/idx/idx-template.json +0 -21
- src/resources/idx/idx-template.nix +0 -26
- src/resources/locks/uv-adk_base-agent_engine.lock +0 -5338
- src/resources/locks/uv-adk_base-cloud_run.lock +0 -5930
- src/resources/locks/uv-agentic_rag-agent_engine.lock +0 -5528
- src/resources/locks/uv-agentic_rag-cloud_run.lock +0 -6120
- src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6231
- src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -6839
- src/resources/locks/uv-langgraph_base_react-agent_engine.lock +0 -5233
- src/resources/locks/uv-langgraph_base_react-cloud_run.lock +0 -5862
- src/resources/locks/uv-live_api-cloud_run.lock +0 -5832
- src/resources/setup_cicd/cicd_variables.tf +0 -41
- src/resources/setup_cicd/github.tf +0 -87
- {agents → agent_starter_pack/agents}/agentic_rag/app/retrievers.py +0 -0
- {agents → agent_starter_pack/agents}/agentic_rag/app/templates.py +0 -0
- {src → agent_starter_pack}/base_template/deployment/terraform/dev/vars/env.tfvars +0 -0
- {src → agent_starter_pack}/base_template/tests/unit/test_dummy.py +0 -0
- {src/deployment_targets/agent_engine/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/gcs.py +0 -0
- {src → agent_starter_pack}/cli/utils/__init__.py +0 -0
- {src → agent_starter_pack}/cli/utils/datastores.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/pipeline.py +0 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/deployment_metadata.json +0 -0
- {src → agent_starter_pack}/deployment_targets/agent_engine/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
- {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/licenses/LICENSE +0 -0
agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/fast_api_app.py
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
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
|
+
import asyncio
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
from collections.abc import Callable
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
import backoff
|
|
22
|
+
import google.auth
|
|
23
|
+
from fastapi import FastAPI, HTTPException, WebSocket
|
|
24
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
25
|
+
from fastapi.responses import FileResponse
|
|
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
|
|
32
|
+
from google.cloud import logging as google_cloud_logging
|
|
33
|
+
from vertexai.agent_engines import _utils
|
|
34
|
+
from websockets.exceptions import ConnectionClosedError
|
|
35
|
+
|
|
36
|
+
from .agent import app as adk_app
|
|
37
|
+
from .app_utils.telemetry import setup_telemetry
|
|
38
|
+
from .app_utils.typing import Feedback
|
|
39
|
+
|
|
40
|
+
app = FastAPI()
|
|
41
|
+
app.add_middleware(
|
|
42
|
+
CORSMiddleware,
|
|
43
|
+
allow_origins=["*"],
|
|
44
|
+
allow_methods=["*"],
|
|
45
|
+
allow_headers=["*"],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Get the path to the frontend build directory
|
|
49
|
+
current_dir = Path(__file__).parent
|
|
50
|
+
frontend_build_dir = current_dir.parent / "frontend" / "build"
|
|
51
|
+
|
|
52
|
+
# Mount static files if build directory exists
|
|
53
|
+
if frontend_build_dir.exists():
|
|
54
|
+
app.mount(
|
|
55
|
+
"/static",
|
|
56
|
+
StaticFiles(directory=str(frontend_build_dir / "static")),
|
|
57
|
+
name="static",
|
|
58
|
+
)
|
|
59
|
+
logging_client = google_cloud_logging.Client()
|
|
60
|
+
logger = logging_client.logger(__name__)
|
|
61
|
+
logging.basicConfig(level=logging.INFO)
|
|
62
|
+
|
|
63
|
+
setup_telemetry()
|
|
64
|
+
_, project_id = google.auth.default()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Initialize ADK services
|
|
68
|
+
session_service = InMemorySessionService()
|
|
69
|
+
artifact_service = InMemoryArtifactService()
|
|
70
|
+
memory_service = InMemoryMemoryService()
|
|
71
|
+
|
|
72
|
+
# Initialize ADK runner
|
|
73
|
+
runner = Runner(
|
|
74
|
+
app=adk_app,
|
|
75
|
+
session_service=session_service,
|
|
76
|
+
artifact_service=artifact_service,
|
|
77
|
+
memory_service=memory_service,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class AgentSession:
|
|
82
|
+
"""Manages bidirectional communication between a client and the agent."""
|
|
83
|
+
|
|
84
|
+
def __init__(self, websocket: WebSocket) -> None:
|
|
85
|
+
"""Initialize the agent session.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
websocket: The client websocket connection
|
|
89
|
+
"""
|
|
90
|
+
self.websocket = websocket
|
|
91
|
+
self.input_queue: asyncio.Queue[dict] = asyncio.Queue()
|
|
92
|
+
self.user_id: str | None = None
|
|
93
|
+
self.session_id: str | None = None
|
|
94
|
+
|
|
95
|
+
async def receive_from_client(self) -> None:
|
|
96
|
+
"""Listen for messages from the client and put them in the queue."""
|
|
97
|
+
while True:
|
|
98
|
+
try:
|
|
99
|
+
message = await self.websocket.receive()
|
|
100
|
+
|
|
101
|
+
if "text" in message:
|
|
102
|
+
data = json.loads(message["text"])
|
|
103
|
+
|
|
104
|
+
if isinstance(data, dict):
|
|
105
|
+
# Skip setup messages - they're for backend logging only
|
|
106
|
+
if "setup" in data:
|
|
107
|
+
logger.log_struct(
|
|
108
|
+
{**data["setup"], "type": "setup"}, severity="INFO"
|
|
109
|
+
)
|
|
110
|
+
logging.info(
|
|
111
|
+
"Received setup message (not forwarding to agent)"
|
|
112
|
+
)
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
# Forward message to agent engine
|
|
116
|
+
await self.input_queue.put(data)
|
|
117
|
+
else:
|
|
118
|
+
logging.warning(
|
|
119
|
+
f"Received unexpected JSON structure from client: {data}"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
elif "bytes" in message:
|
|
123
|
+
# Handle binary data
|
|
124
|
+
await self.input_queue.put({"binary_data": message["bytes"]})
|
|
125
|
+
|
|
126
|
+
else:
|
|
127
|
+
logging.warning(
|
|
128
|
+
f"Received unexpected message type from client: {message}"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
except ConnectionClosedError as e:
|
|
132
|
+
logging.warning(f"Client closed connection: {e}")
|
|
133
|
+
break
|
|
134
|
+
except json.JSONDecodeError as e:
|
|
135
|
+
logging.error(f"Error parsing JSON from client: {e}")
|
|
136
|
+
break
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logging.error(f"Error receiving from client: {e!s}")
|
|
139
|
+
break
|
|
140
|
+
|
|
141
|
+
async def run_agent(self) -> None:
|
|
142
|
+
"""Run the agent with the input queue using bidi_stream_query protocol."""
|
|
143
|
+
try:
|
|
144
|
+
# Send setupComplete immediately
|
|
145
|
+
setup_complete_response: dict = {"setupComplete": {}}
|
|
146
|
+
await self.websocket.send_json(setup_complete_response)
|
|
147
|
+
|
|
148
|
+
# Wait for first request with user_id
|
|
149
|
+
first_request = await self.input_queue.get()
|
|
150
|
+
self.user_id = first_request.get("user_id")
|
|
151
|
+
if not self.user_id:
|
|
152
|
+
raise ValueError("The first request must have a user_id.")
|
|
153
|
+
|
|
154
|
+
self.session_id = first_request.get("session_id")
|
|
155
|
+
first_live_request = first_request.get("live_request")
|
|
156
|
+
|
|
157
|
+
# Create session if needed
|
|
158
|
+
if not self.session_id:
|
|
159
|
+
session = await session_service.create_session(
|
|
160
|
+
app_name="live-app",
|
|
161
|
+
user_id=self.user_id,
|
|
162
|
+
)
|
|
163
|
+
self.session_id = session.id
|
|
164
|
+
|
|
165
|
+
# Create LiveRequestQueue
|
|
166
|
+
live_request_queue = LiveRequestQueue()
|
|
167
|
+
|
|
168
|
+
# Add first live request if present
|
|
169
|
+
if first_live_request and isinstance(first_live_request, dict):
|
|
170
|
+
live_request_queue.send(LiveRequest.model_validate(first_live_request))
|
|
171
|
+
|
|
172
|
+
# Forward requests from input_queue to live_request_queue
|
|
173
|
+
async def _forward_requests() -> None:
|
|
174
|
+
while True:
|
|
175
|
+
request = await self.input_queue.get()
|
|
176
|
+
live_request = LiveRequest.model_validate(request)
|
|
177
|
+
live_request_queue.send(live_request)
|
|
178
|
+
|
|
179
|
+
# Forward events from agent to websocket
|
|
180
|
+
async def _forward_events() -> None:
|
|
181
|
+
events_async = runner.run_live(
|
|
182
|
+
user_id=self.user_id,
|
|
183
|
+
session_id=self.session_id,
|
|
184
|
+
live_request_queue=live_request_queue,
|
|
185
|
+
)
|
|
186
|
+
async for event in events_async:
|
|
187
|
+
event_dict = _utils.dump_event_for_json(event)
|
|
188
|
+
await self.websocket.send_json(event_dict)
|
|
189
|
+
|
|
190
|
+
# Check for error responses
|
|
191
|
+
if isinstance(event_dict, dict) and "error" in event_dict:
|
|
192
|
+
logging.error(f"Agent error: {event_dict['error']}")
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
# Run both tasks
|
|
196
|
+
requests_task = asyncio.create_task(_forward_requests())
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
await _forward_events()
|
|
200
|
+
finally:
|
|
201
|
+
requests_task.cancel()
|
|
202
|
+
try:
|
|
203
|
+
await requests_task
|
|
204
|
+
except asyncio.CancelledError:
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
except Exception as e:
|
|
208
|
+
logging.error(f"Error in agent: {e}")
|
|
209
|
+
await self.websocket.send_json({"error": str(e)})
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def get_connect_and_run_callable(websocket: WebSocket) -> Callable:
|
|
213
|
+
"""Create a callable that handles agent connection with retry logic.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
websocket: The client websocket connection
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Callable: An async function that establishes and manages the agent connection
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
async def on_backoff(details: backoff._typing.Details) -> None:
|
|
223
|
+
await websocket.send_json(
|
|
224
|
+
{
|
|
225
|
+
"status": f"Model connection error, retrying in {details['wait']} seconds..."
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
@backoff.on_exception(
|
|
230
|
+
backoff.expo, ConnectionClosedError, max_tries=10, on_backoff=on_backoff
|
|
231
|
+
)
|
|
232
|
+
async def connect_and_run() -> None:
|
|
233
|
+
logging.info("Starting ADK agent")
|
|
234
|
+
session = AgentSession(websocket)
|
|
235
|
+
|
|
236
|
+
logging.info("Starting bidirectional communication with agent")
|
|
237
|
+
await asyncio.gather(
|
|
238
|
+
session.receive_from_client(),
|
|
239
|
+
session.run_agent(),
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
return connect_and_run
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@app.websocket("/ws")
|
|
246
|
+
async def websocket_endpoint(websocket: WebSocket) -> None:
|
|
247
|
+
"""Handle new websocket connections."""
|
|
248
|
+
await websocket.accept()
|
|
249
|
+
connect_and_run = get_connect_and_run_callable(websocket)
|
|
250
|
+
await connect_and_run()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@app.get("/")
|
|
254
|
+
async def serve_frontend_root() -> FileResponse:
|
|
255
|
+
"""Serve the frontend index.html at the root path."""
|
|
256
|
+
index_file = frontend_build_dir / "index.html"
|
|
257
|
+
if index_file.exists():
|
|
258
|
+
return FileResponse(str(index_file))
|
|
259
|
+
raise HTTPException(
|
|
260
|
+
status_code=404,
|
|
261
|
+
detail="Frontend not built. Run 'npm run build' in the frontend directory.",
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@app.get("/{full_path:path}")
|
|
266
|
+
async def serve_frontend_spa(full_path: str) -> FileResponse:
|
|
267
|
+
"""Catch-all route to serve the frontend for SPA routing.
|
|
268
|
+
|
|
269
|
+
This ensures that client-side routes are handled by the React app.
|
|
270
|
+
Excludes API routes (ws, feedback) and static assets.
|
|
271
|
+
"""
|
|
272
|
+
# Don't intercept API routes
|
|
273
|
+
if full_path.startswith(("ws", "feedback", "static", "api")):
|
|
274
|
+
raise HTTPException(status_code=404, detail="Not found")
|
|
275
|
+
|
|
276
|
+
# Serve index.html for all other routes (SPA routing)
|
|
277
|
+
index_file = frontend_build_dir / "index.html"
|
|
278
|
+
if index_file.exists():
|
|
279
|
+
return FileResponse(str(index_file))
|
|
280
|
+
raise HTTPException(
|
|
281
|
+
status_code=404,
|
|
282
|
+
detail="Frontend not built. Run 'npm run build' in the frontend directory.",
|
|
283
|
+
)
|
|
284
|
+
{% elif cookiecutter.is_adk %}
|
|
285
|
+
import os
|
|
286
|
+
{%- if cookiecutter.is_a2a %}
|
|
287
|
+
from collections.abc import AsyncIterator
|
|
288
|
+
from contextlib import asynccontextmanager
|
|
289
|
+
{%- endif %}
|
|
290
|
+
{%- if cookiecutter.session_type == "cloud_sql" %}
|
|
291
|
+
from urllib.parse import quote
|
|
292
|
+
{%- endif %}
|
|
293
|
+
|
|
294
|
+
import google.auth
|
|
295
|
+
{%- if cookiecutter.is_a2a %}
|
|
296
|
+
from a2a.server.apps import A2AFastAPIApplication
|
|
297
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
298
|
+
from a2a.server.tasks import InMemoryTaskStore
|
|
299
|
+
from a2a.types import AgentCapabilities, AgentCard
|
|
300
|
+
from a2a.utils.constants import (
|
|
301
|
+
AGENT_CARD_WELL_KNOWN_PATH,
|
|
302
|
+
EXTENDED_AGENT_CARD_PATH,
|
|
303
|
+
)
|
|
304
|
+
{%- endif %}
|
|
305
|
+
from fastapi import FastAPI
|
|
306
|
+
{%- if cookiecutter.is_a2a %}
|
|
307
|
+
from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
|
|
308
|
+
from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder
|
|
309
|
+
from google.adk.artifacts.gcs_artifact_service import GcsArtifactService
|
|
310
|
+
from google.adk.runners import Runner
|
|
311
|
+
from google.adk.sessions import InMemorySessionService
|
|
312
|
+
{%- else %}
|
|
313
|
+
from google.adk.cli.fast_api import get_fast_api_app
|
|
314
|
+
{%- endif %}
|
|
315
|
+
from google.cloud import logging as google_cloud_logging
|
|
316
|
+
{% if cookiecutter.session_type == "agent_engine" -%}
|
|
317
|
+
from vertexai import agent_engines
|
|
318
|
+
{% endif %}
|
|
319
|
+
|
|
320
|
+
{%- if cookiecutter.is_a2a %}
|
|
321
|
+
from {{cookiecutter.agent_directory}}.agent import app as adk_app
|
|
322
|
+
{%- endif %}
|
|
323
|
+
from {{cookiecutter.agent_directory}}.app_utils.gcs import create_bucket_if_not_exists
|
|
324
|
+
from {{cookiecutter.agent_directory}}.app_utils.telemetry import setup_telemetry
|
|
325
|
+
from {{cookiecutter.agent_directory}}.app_utils.typing import Feedback
|
|
326
|
+
|
|
327
|
+
setup_telemetry()
|
|
328
|
+
_, project_id = google.auth.default()
|
|
329
|
+
logging_client = google_cloud_logging.Client()
|
|
330
|
+
logger = logging_client.logger(__name__)
|
|
331
|
+
{%- if not cookiecutter.is_a2a %}
|
|
332
|
+
allow_origins = (
|
|
333
|
+
os.getenv("ALLOW_ORIGINS", "").split(",") if os.getenv("ALLOW_ORIGINS") else None
|
|
334
|
+
)
|
|
335
|
+
{%- endif %}
|
|
336
|
+
|
|
337
|
+
# Artifact bucket for ADK
|
|
338
|
+
bucket_name = f"gs://{project_id}-{{cookiecutter.project_name}}-logs"
|
|
339
|
+
create_bucket_if_not_exists(
|
|
340
|
+
bucket_name=bucket_name, project=project_id, location="us-central1"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
{%- if cookiecutter.is_a2a %}
|
|
344
|
+
|
|
345
|
+
runner = Runner(
|
|
346
|
+
app=adk_app,
|
|
347
|
+
artifact_service=GcsArtifactService(bucket_name=bucket_name),
|
|
348
|
+
session_service=InMemorySessionService(),
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
request_handler = DefaultRequestHandler(
|
|
352
|
+
agent_executor=A2aAgentExecutor(runner=runner), task_store=InMemoryTaskStore()
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
A2A_RPC_PATH = f"/a2a/{adk_app.name}"
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
async def build_dynamic_agent_card() -> AgentCard:
|
|
359
|
+
"""Builds the Agent Card dynamically from the root_agent."""
|
|
360
|
+
agent_card_builder = AgentCardBuilder(
|
|
361
|
+
agent=adk_app.root_agent,
|
|
362
|
+
capabilities=AgentCapabilities(streaming=True),
|
|
363
|
+
rpc_url=f"{os.getenv('APP_URL', 'http://0.0.0.0:8000')}{A2A_RPC_PATH}",
|
|
364
|
+
agent_version=os.getenv("AGENT_VERSION", "0.1.0"),
|
|
365
|
+
)
|
|
366
|
+
agent_card = await agent_card_builder.build()
|
|
367
|
+
return agent_card
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@asynccontextmanager
|
|
371
|
+
async def lifespan(app_instance: FastAPI) -> AsyncIterator[None]:
|
|
372
|
+
agent_card = await build_dynamic_agent_card()
|
|
373
|
+
a2a_app = A2AFastAPIApplication(agent_card=agent_card, http_handler=request_handler)
|
|
374
|
+
a2a_app.add_routes_to_app(
|
|
375
|
+
app_instance,
|
|
376
|
+
agent_card_url=f"{A2A_RPC_PATH}{AGENT_CARD_WELL_KNOWN_PATH}",
|
|
377
|
+
rpc_url=A2A_RPC_PATH,
|
|
378
|
+
extended_agent_card_url=f"{A2A_RPC_PATH}{EXTENDED_AGENT_CARD_PATH}",
|
|
379
|
+
)
|
|
380
|
+
yield
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
app = FastAPI(
|
|
384
|
+
title="{{cookiecutter.project_name}}",
|
|
385
|
+
description="API for interacting with the Agent {{cookiecutter.project_name}}",
|
|
386
|
+
lifespan=lifespan,
|
|
387
|
+
)
|
|
388
|
+
{%- else %}
|
|
389
|
+
|
|
390
|
+
AGENT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
391
|
+
|
|
392
|
+
{%- if cookiecutter.session_type == "cloud_sql" %}
|
|
393
|
+
# Cloud SQL session configuration
|
|
394
|
+
db_user = os.environ.get("DB_USER", "postgres")
|
|
395
|
+
db_name = os.environ.get("DB_NAME", "postgres")
|
|
396
|
+
db_pass = os.environ.get("DB_PASS")
|
|
397
|
+
instance_connection_name = os.environ.get("INSTANCE_CONNECTION_NAME")
|
|
398
|
+
|
|
399
|
+
session_service_uri = None
|
|
400
|
+
if instance_connection_name and db_pass:
|
|
401
|
+
# Use Unix socket for Cloud SQL
|
|
402
|
+
# URL-encode username and password to handle special characters (e.g., '[', '?', '#', '$')
|
|
403
|
+
# These characters can cause URL parsing errors, especially '[' which triggers IPv6 validation
|
|
404
|
+
encoded_user = quote(db_user, safe="")
|
|
405
|
+
encoded_pass = quote(db_pass, safe="")
|
|
406
|
+
# URL-encode the connection name to prevent colons from being misinterpreted
|
|
407
|
+
encoded_instance = instance_connection_name.replace(":", "%3A")
|
|
408
|
+
|
|
409
|
+
session_service_uri = (
|
|
410
|
+
f"postgresql+psycopg2://{encoded_user}:{encoded_pass}@"
|
|
411
|
+
f"/{db_name}"
|
|
412
|
+
f"?host=/cloudsql/{encoded_instance}"
|
|
413
|
+
)
|
|
414
|
+
{%- elif cookiecutter.session_type == "agent_engine" %}
|
|
415
|
+
# Agent Engine session configuration
|
|
416
|
+
# Check if we should use in-memory session for testing (set USE_IN_MEMORY_SESSION=true for E2E tests)
|
|
417
|
+
use_in_memory_session = os.environ.get("USE_IN_MEMORY_SESSION", "").lower() in (
|
|
418
|
+
"true",
|
|
419
|
+
"1",
|
|
420
|
+
"yes",
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
if use_in_memory_session:
|
|
424
|
+
# Use in-memory session for local testing
|
|
425
|
+
session_service_uri = None
|
|
426
|
+
else:
|
|
427
|
+
# Use environment variable for agent name, default to project name
|
|
428
|
+
agent_name = os.environ.get(
|
|
429
|
+
"AGENT_ENGINE_SESSION_NAME", "{{cookiecutter.project_name}}"
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
# Check if an agent with this name already exists
|
|
433
|
+
existing_agents = list(agent_engines.list(filter=f"display_name={agent_name}"))
|
|
434
|
+
|
|
435
|
+
if existing_agents:
|
|
436
|
+
# Use the existing agent
|
|
437
|
+
agent_engine = existing_agents[0]
|
|
438
|
+
else:
|
|
439
|
+
# Create a new agent if none exists
|
|
440
|
+
agent_engine = agent_engines.create(display_name=agent_name)
|
|
441
|
+
|
|
442
|
+
session_service_uri = f"agentengine://{agent_engine.resource_name}"
|
|
443
|
+
{%- else %}
|
|
444
|
+
# In-memory session configuration - no persistent storage
|
|
445
|
+
session_service_uri = None
|
|
446
|
+
{%- endif %}
|
|
447
|
+
|
|
448
|
+
app: FastAPI = get_fast_api_app(
|
|
449
|
+
agents_dir=AGENT_DIR,
|
|
450
|
+
web=True,
|
|
451
|
+
artifact_service_uri=bucket_name,
|
|
452
|
+
allow_origins=allow_origins,
|
|
453
|
+
session_service_uri=session_service_uri,
|
|
454
|
+
otel_to_cloud=True,
|
|
455
|
+
)
|
|
456
|
+
app.title = "{{cookiecutter.project_name}}"
|
|
457
|
+
app.description = "API for interacting with the Agent {{cookiecutter.project_name}}"
|
|
458
|
+
{%- endif %}
|
|
459
|
+
{% else %}
|
|
460
|
+
import os
|
|
461
|
+
from collections.abc import AsyncIterator
|
|
462
|
+
from contextlib import asynccontextmanager
|
|
463
|
+
|
|
464
|
+
from a2a.server.apps import A2AFastAPIApplication
|
|
465
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
466
|
+
from a2a.server.tasks import InMemoryTaskStore
|
|
467
|
+
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
|
|
468
|
+
from a2a.utils.constants import (
|
|
469
|
+
AGENT_CARD_WELL_KNOWN_PATH,
|
|
470
|
+
EXTENDED_AGENT_CARD_PATH,
|
|
471
|
+
)
|
|
472
|
+
from fastapi import FastAPI
|
|
473
|
+
from google.cloud import logging as google_cloud_logging
|
|
474
|
+
|
|
475
|
+
from {{cookiecutter.agent_directory}}.agent import root_agent
|
|
476
|
+
from {{cookiecutter.agent_directory}}.app_utils.executor.a2a_agent_executor import (
|
|
477
|
+
LangGraphAgentExecutor,
|
|
478
|
+
)
|
|
479
|
+
from {{cookiecutter.agent_directory}}.app_utils.telemetry import setup_telemetry
|
|
480
|
+
from {{cookiecutter.agent_directory}}.app_utils.typing import Feedback
|
|
481
|
+
|
|
482
|
+
setup_telemetry()
|
|
483
|
+
|
|
484
|
+
request_handler = DefaultRequestHandler(
|
|
485
|
+
agent_executor=LangGraphAgentExecutor(graph=root_agent),
|
|
486
|
+
task_store=InMemoryTaskStore(),
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
A2A_RPC_PATH = "/a2a/{{cookiecutter.agent_directory}}"
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def build_agent_card() -> AgentCard:
|
|
493
|
+
"""Builds the Agent Card for the LangGraph agent."""
|
|
494
|
+
skill = AgentSkill(
|
|
495
|
+
id="root_agent-get_weather",
|
|
496
|
+
name="get_weather",
|
|
497
|
+
description="Simulates a web search. Use it get information on weather.",
|
|
498
|
+
tags=["llm", "tools"],
|
|
499
|
+
examples=["What's the weather in San Francisco?"],
|
|
500
|
+
)
|
|
501
|
+
agent_card = AgentCard(
|
|
502
|
+
name="root_agent",
|
|
503
|
+
description="API for interacting with the Agent {{cookiecutter.project_name}}",
|
|
504
|
+
url=f"{os.getenv('APP_URL', 'http://0.0.0.0:8000')}{A2A_RPC_PATH}",
|
|
505
|
+
version=os.getenv("AGENT_VERSION", "0.1.0"),
|
|
506
|
+
default_input_modes=["text/plain"],
|
|
507
|
+
default_output_modes=["text/plain"],
|
|
508
|
+
capabilities=AgentCapabilities(streaming=True),
|
|
509
|
+
skills=[skill],
|
|
510
|
+
)
|
|
511
|
+
return agent_card
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
@asynccontextmanager
|
|
515
|
+
async def lifespan(app_instance: FastAPI) -> AsyncIterator[None]:
|
|
516
|
+
agent_card = build_agent_card()
|
|
517
|
+
a2a_app = A2AFastAPIApplication(agent_card=agent_card, http_handler=request_handler)
|
|
518
|
+
a2a_app.add_routes_to_app(
|
|
519
|
+
app_instance,
|
|
520
|
+
agent_card_url=f"{A2A_RPC_PATH}{AGENT_CARD_WELL_KNOWN_PATH}",
|
|
521
|
+
rpc_url=A2A_RPC_PATH,
|
|
522
|
+
extended_agent_card_url=f"{A2A_RPC_PATH}{EXTENDED_AGENT_CARD_PATH}",
|
|
523
|
+
)
|
|
524
|
+
yield
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
# Initialize FastAPI app and logging
|
|
528
|
+
app = FastAPI(
|
|
529
|
+
title="{{cookiecutter.project_name}}",
|
|
530
|
+
description="API for interacting with the Agent {{cookiecutter.project_name}}",
|
|
531
|
+
lifespan=lifespan,
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
logging_client = google_cloud_logging.Client()
|
|
535
|
+
logger = logging_client.logger(__name__)
|
|
536
|
+
{% endif %}
|
|
537
|
+
|
|
538
|
+
@app.post("/feedback")
|
|
539
|
+
def collect_feedback(feedback: Feedback) -> dict[str, str]:
|
|
540
|
+
"""Collect and log feedback.
|
|
541
|
+
|
|
542
|
+
Args:
|
|
543
|
+
feedback: The feedback data to log
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
Success message
|
|
547
|
+
"""
|
|
548
|
+
logger.log_struct(feedback.model_dump(), severity="INFO")
|
|
549
|
+
return {"status": "success"}
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
# Main execution
|
|
553
|
+
if __name__ == "__main__":
|
|
554
|
+
import uvicorn
|
|
555
|
+
|
|
556
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|