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.
Files changed (255) hide show
  1. agent_starter_pack/agents/README.md +7 -0
  2. agents/langgraph_base_react/template/.templateconfig.yaml → agent_starter_pack/agents/adk_a2a_base/.template/templateconfig.yaml +5 -10
  3. agent_starter_pack/agents/adk_a2a_base/README.md +37 -0
  4. src/deployment_targets/cloud_run/Dockerfile → agent_starter_pack/agents/adk_a2a_base/app/__init__.py +2 -14
  5. agent_starter_pack/agents/adk_a2a_base/app/agent.py +70 -0
  6. agent_starter_pack/agents/adk_a2a_base/notebooks/adk_a2a_app_testing.ipynb +583 -0
  7. agents/crewai_coding_crew/notebooks/evaluating_crewai_agent.ipynb → agent_starter_pack/agents/adk_a2a_base/notebooks/evaluating_adk_agent.ipynb +163 -199
  8. {agents/adk_base → agent_starter_pack/agents/adk_a2a_base}/tests/integration/test_agent.py +2 -2
  9. agents/adk_base/template/.templateconfig.yaml → agent_starter_pack/agents/adk_base/.template/templateconfig.yaml +4 -1
  10. {agents → agent_starter_pack/agents}/adk_base/README.md +1 -1
  11. agent_starter_pack/agents/adk_base/app/__init__.py +17 -0
  12. {agents → agent_starter_pack/agents}/adk_base/app/agent.py +5 -2
  13. {agents → agent_starter_pack/agents}/adk_base/notebooks/adk_app_testing.ipynb +128 -82
  14. agents/langgraph_base_react/notebooks/evaluating_langgraph_agent.ipynb → agent_starter_pack/agents/adk_base/notebooks/evaluating_adk_agent.ipynb +181 -207
  15. agent_starter_pack/agents/adk_base/tests/integration/test_agent.py +58 -0
  16. agents/crewai_coding_crew/template/.templateconfig.yaml → agent_starter_pack/agents/adk_live/.template/templateconfig.yaml +5 -9
  17. agent_starter_pack/agents/adk_live/README.md +32 -0
  18. agent_starter_pack/agents/adk_live/app/__init__.py +17 -0
  19. agent_starter_pack/agents/adk_live/app/agent.py +51 -0
  20. agent_starter_pack/agents/adk_live/tests/unit/test_dummy.py +38 -0
  21. agents/agentic_rag/template/.templateconfig.yaml → agent_starter_pack/agents/agentic_rag/.template/templateconfig.yaml +7 -3
  22. {agents → agent_starter_pack/agents}/agentic_rag/README.md +1 -1
  23. agent_starter_pack/agents/agentic_rag/app/__init__.py +17 -0
  24. {agents → agent_starter_pack/agents}/agentic_rag/app/agent.py +8 -4
  25. {agents → agent_starter_pack/agents}/agentic_rag/notebooks/adk_app_testing.ipynb +128 -82
  26. agent_starter_pack/agents/agentic_rag/notebooks/evaluating_adk_agent.ipynb +1535 -0
  27. {agents → agent_starter_pack/agents}/agentic_rag/tests/integration/test_agent.py +3 -3
  28. agent_starter_pack/agents/langgraph_base/.template/templateconfig.yaml +31 -0
  29. agent_starter_pack/agents/langgraph_base/README.md +30 -0
  30. agent_starter_pack/agents/langgraph_base/app/__init__.py +17 -0
  31. agent_starter_pack/agents/langgraph_base/app/agent.py +34 -0
  32. {agents/crewai_coding_crew → agent_starter_pack/agents/langgraph_base}/notebooks/evaluating_langgraph_agent.ipynb +30 -17
  33. {agents/langgraph_base_react → agent_starter_pack/agents/langgraph_base}/tests/integration/test_agent.py +2 -2
  34. {src → agent_starter_pack}/base_template/.gitignore +5 -3
  35. agent_starter_pack/base_template/GEMINI.md +5 -0
  36. agent_starter_pack/base_template/Makefile +339 -0
  37. agent_starter_pack/base_template/README.md +267 -0
  38. agent_starter_pack/base_template/deployment/README.md +11 -0
  39. {src → agent_starter_pack}/base_template/deployment/terraform/apis.tf +2 -2
  40. {src → agent_starter_pack}/base_template/deployment/terraform/dev/apis.tf +6 -1
  41. {src → agent_starter_pack}/base_template/deployment/terraform/dev/iam.tf +12 -11
  42. {src → agent_starter_pack}/base_template/deployment/terraform/dev/providers.tf +5 -1
  43. {src → agent_starter_pack}/base_template/deployment/terraform/dev/storage.tf +1 -1
  44. {src → agent_starter_pack}/base_template/deployment/terraform/dev/variables.tf +10 -10
  45. agent_starter_pack/base_template/deployment/terraform/dev/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +193 -0
  46. agent_starter_pack/base_template/deployment/terraform/github.tf +337 -0
  47. {src → agent_starter_pack}/base_template/deployment/terraform/iam.tf +20 -41
  48. {src → agent_starter_pack}/base_template/deployment/terraform/locals.tf +10 -3
  49. {src/resources/setup_cicd → agent_starter_pack/base_template/deployment/terraform}/providers.tf +8 -1
  50. {src → agent_starter_pack}/base_template/deployment/terraform/service_accounts.tf +7 -8
  51. agent_starter_pack/base_template/deployment/terraform/sql/completions.sql +138 -0
  52. {src → agent_starter_pack}/base_template/deployment/terraform/storage.tf +7 -16
  53. {src → agent_starter_pack}/base_template/deployment/terraform/variables.tf +61 -28
  54. {src → agent_starter_pack}/base_template/deployment/terraform/vars/env.tfvars +6 -1
  55. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.cicd_runner == 'github_actions' %}wif.tf{% else %}unused_wif.tf{% endif %} +43 -0
  56. 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
  57. agent_starter_pack/base_template/deployment/terraform/{% if cookiecutter.is_adk %}telemetry.tf{% else %}unused_telemetry.tf{% endif %} +206 -0
  58. {src → agent_starter_pack}/base_template/pyproject.toml +24 -37
  59. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/deploy-to-prod.yaml +132 -0
  60. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/pr_checks.yaml +65 -0
  61. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'github_actions' %}.github{% else %}unused_github{% endif %}/workflows/staging.yaml +259 -0
  62. 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
  63. 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
  64. agent_starter_pack/base_template/{% if cookiecutter.cicd_runner == 'google_cloud_build' %}.cloudbuild{% else %}unused_.cloudbuild{% endif %}/staging.yaml +322 -0
  65. agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils/telemetry.py +96 -0
  66. {src/base_template/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/typing.py +7 -9
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. agent_starter_pack/cli/commands/create.py +1256 -0
  73. agent_starter_pack/cli/commands/enhance.py +611 -0
  74. agent_starter_pack/cli/commands/list.py +203 -0
  75. agent_starter_pack/cli/commands/register_gemini_enterprise.py +1070 -0
  76. agent_starter_pack/cli/commands/setup_cicd.py +862 -0
  77. {src → agent_starter_pack}/cli/main.py +10 -2
  78. {src → agent_starter_pack}/cli/utils/cicd.py +139 -48
  79. agent_starter_pack/cli/utils/gcp.py +263 -0
  80. agent_starter_pack/cli/utils/logging.py +103 -0
  81. agent_starter_pack/cli/utils/remote_template.py +677 -0
  82. agent_starter_pack/cli/utils/template.py +1466 -0
  83. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/process_data.py +1 -1
  84. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/submit_pipeline.py +20 -6
  85. {src → agent_starter_pack}/data_ingestion/pyproject.toml +1 -0
  86. {src → agent_starter_pack}/data_ingestion/uv.lock +602 -494
  87. agent_starter_pack/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +484 -0
  88. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/README.md +84 -0
  89. agent_starter_pack/deployment_targets/agent_engine/tests/load_test/load_test.py +424 -0
  90. agent_starter_pack/deployment_targets/agent_engine/tests/{% if cookiecutter.is_a2a %}helpers.py{% else %}unused_helpers.py{% endif %} +138 -0
  91. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/agent_engine_app.py +263 -0
  92. agent_starter_pack/deployment_targets/agent_engine/{{cookiecutter.agent_directory}}/app_utils/deploy.py +414 -0
  93. 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
  94. agent_starter_pack/deployment_targets/cloud_run/Dockerfile +51 -0
  95. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/dev/service.tf +243 -0
  96. agent_starter_pack/deployment_targets/cloud_run/deployment/terraform/service.tf +417 -0
  97. agent_starter_pack/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +705 -0
  98. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +321 -0
  99. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/README.md +165 -0
  100. agent_starter_pack/deployment_targets/cloud_run/tests/load_test/load_test.py +329 -0
  101. agent_starter_pack/deployment_targets/cloud_run/{{cookiecutter.agent_directory}}/fast_api_app.py +556 -0
  102. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package-lock.json +79 -1044
  103. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/package.json +1 -9
  104. agent_starter_pack/frontends/adk_live_react/frontend/src/App.tsx +65 -0
  105. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/Logger.tsx +8 -3
  106. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/logger.scss +26 -0
  107. agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/SidePanel.tsx +516 -0
  108. agent_starter_pack/frontends/adk_live_react/frontend/src/components/side-panel/side-panel.scss +563 -0
  109. agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/TranscriptionPreview.tsx +106 -0
  110. agent_starter_pack/frontends/adk_live_react/frontend/src/components/transcription-preview/transcription-preview.scss +150 -0
  111. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-live-api.ts +8 -2
  112. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/multimodal-live-types.ts +40 -2
  113. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-recorder.ts +1 -1
  114. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audio-streamer.ts +1 -1
  115. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/multimodal-live-client.ts +210 -24
  116. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/utils.ts +27 -5
  117. agent_starter_pack/resources/docs/adk-cheatsheet.md +1628 -0
  118. agent_starter_pack/resources/locks/uv-adk_a2a_base-agent_engine.lock +4966 -0
  119. agent_starter_pack/resources/locks/uv-adk_a2a_base-cloud_run.lock +5011 -0
  120. agent_starter_pack/resources/locks/uv-adk_base-agent_engine.lock +4946 -0
  121. agent_starter_pack/resources/locks/uv-adk_base-cloud_run.lock +4991 -0
  122. agent_starter_pack/resources/locks/uv-adk_live-agent_engine.lock +4963 -0
  123. agent_starter_pack/resources/locks/uv-adk_live-cloud_run.lock +5006 -0
  124. agent_starter_pack/resources/locks/uv-agentic_rag-agent_engine.lock +5487 -0
  125. agent_starter_pack/resources/locks/uv-agentic_rag-cloud_run.lock +5532 -0
  126. agent_starter_pack/resources/locks/uv-langgraph_base-agent_engine.lock +5788 -0
  127. agent_starter_pack/resources/locks/uv-langgraph_base-cloud_run.lock +5811 -0
  128. {src → agent_starter_pack}/utils/generate_locks.py +15 -12
  129. {src → agent_starter_pack}/utils/lock_utils.py +4 -7
  130. {src → agent_starter_pack}/utils/watch_and_rebuild.py +2 -2
  131. agent_starter_pack-0.21.0.dist-info/METADATA +182 -0
  132. agent_starter_pack-0.21.0.dist-info/RECORD +171 -0
  133. agent_starter_pack-0.21.0.dist-info/entry_points.txt +2 -0
  134. llm.txt +362 -0
  135. agent_starter_pack-0.3.3.dist-info/METADATA +0 -164
  136. agent_starter_pack-0.3.3.dist-info/RECORD +0 -176
  137. agent_starter_pack-0.3.3.dist-info/entry_points.txt +0 -2
  138. agents/crewai_coding_crew/README.md +0 -34
  139. agents/crewai_coding_crew/app/agent.py +0 -86
  140. agents/crewai_coding_crew/app/crew/config/agents.yaml +0 -39
  141. agents/crewai_coding_crew/app/crew/config/tasks.yaml +0 -37
  142. agents/crewai_coding_crew/app/crew/crew.py +0 -71
  143. agents/crewai_coding_crew/tests/integration/test_agent.py +0 -47
  144. agents/langgraph_base_react/README.md +0 -9
  145. agents/langgraph_base_react/app/agent.py +0 -73
  146. agents/live_api/README.md +0 -37
  147. agents/live_api/app/agent.py +0 -78
  148. agents/live_api/app/server.py +0 -196
  149. agents/live_api/app/templates.py +0 -51
  150. agents/live_api/app/vector_store.py +0 -55
  151. agents/live_api/template/.templateconfig.yaml +0 -29
  152. agents/live_api/tests/integration/test_server_e2e.py +0 -254
  153. agents/live_api/tests/load_test/load_test.py +0 -40
  154. agents/live_api/tests/unit/test_server.py +0 -143
  155. src/base_template/Makefile +0 -72
  156. src/base_template/README.md +0 -208
  157. src/base_template/app/__init__.py +0 -3
  158. src/base_template/app/utils/tracing.py +0 -155
  159. src/base_template/deployment/README.md +0 -126
  160. src/base_template/deployment/cd/staging.yaml +0 -216
  161. src/base_template/deployment/terraform/dev/log_sinks.tf +0 -63
  162. src/base_template/deployment/terraform/log_sinks.tf +0 -70
  163. src/base_template/deployment/terraform/providers.tf +0 -37
  164. src/cli/commands/create.py +0 -664
  165. src/cli/commands/setup_cicd.py +0 -829
  166. src/cli/utils/gcp.py +0 -117
  167. src/cli/utils/logging.py +0 -51
  168. src/cli/utils/template.py +0 -737
  169. src/deployment_targets/agent_engine/app/agent_engine_app.py +0 -336
  170. src/deployment_targets/agent_engine/notebooks/intro_agent_engine.ipynb +0 -1025
  171. src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +0 -183
  172. src/deployment_targets/agent_engine/tests/load_test/README.md +0 -42
  173. src/deployment_targets/agent_engine/tests/load_test/load_test.py +0 -107
  174. src/deployment_targets/cloud_run/app/server.py +0 -154
  175. src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +0 -249
  176. src/deployment_targets/cloud_run/tests/load_test/.results/.placeholder +0 -0
  177. src/deployment_targets/cloud_run/tests/load_test/README.md +0 -83
  178. src/deployment_targets/cloud_run/tests/load_test/load_test.py +0 -118
  179. src/deployment_targets/cloud_run/uv.lock +0 -6952
  180. src/frontends/live_api_react/frontend/src/App.tsx +0 -205
  181. src/frontends/live_api_react/frontend/src/components/control-tray/ControlTray.tsx +0 -217
  182. src/frontends/live_api_react/frontend/src/components/control-tray/control-tray.scss +0 -201
  183. src/frontends/live_api_react/frontend/src/components/side-panel/SidePanel.tsx +0 -161
  184. src/frontends/live_api_react/frontend/src/components/side-panel/side-panel.scss +0 -285
  185. src/frontends/streamlit/frontend/side_bar.py +0 -214
  186. src/frontends/streamlit/frontend/streamlit_app.py +0 -265
  187. src/frontends/streamlit/frontend/style/app_markdown.py +0 -37
  188. src/frontends/streamlit/frontend/utils/chat_utils.py +0 -67
  189. src/frontends/streamlit/frontend/utils/local_chat_history.py +0 -125
  190. src/frontends/streamlit/frontend/utils/message_editing.py +0 -59
  191. src/frontends/streamlit/frontend/utils/multimodal_utils.py +0 -217
  192. src/frontends/streamlit/frontend/utils/stream_handler.py +0 -301
  193. src/frontends/streamlit/frontend/utils/title_summary.py +0 -94
  194. src/frontends/streamlit_adk/frontend/side_bar.py +0 -214
  195. src/frontends/streamlit_adk/frontend/streamlit_app.py +0 -314
  196. src/frontends/streamlit_adk/frontend/style/app_markdown.py +0 -37
  197. src/frontends/streamlit_adk/frontend/utils/chat_utils.py +0 -84
  198. src/frontends/streamlit_adk/frontend/utils/local_chat_history.py +0 -110
  199. src/frontends/streamlit_adk/frontend/utils/message_editing.py +0 -61
  200. src/frontends/streamlit_adk/frontend/utils/multimodal_utils.py +0 -223
  201. src/frontends/streamlit_adk/frontend/utils/stream_handler.py +0 -311
  202. src/frontends/streamlit_adk/frontend/utils/title_summary.py +0 -129
  203. src/resources/containers/data_processing/Dockerfile +0 -27
  204. src/resources/containers/e2e-tests/Dockerfile +0 -19
  205. src/resources/idx/.idx/dev.nix +0 -57
  206. src/resources/idx/idx-template.json +0 -21
  207. src/resources/idx/idx-template.nix +0 -26
  208. src/resources/locks/uv-adk_base-agent_engine.lock +0 -5338
  209. src/resources/locks/uv-adk_base-cloud_run.lock +0 -5930
  210. src/resources/locks/uv-agentic_rag-agent_engine.lock +0 -5528
  211. src/resources/locks/uv-agentic_rag-cloud_run.lock +0 -6120
  212. src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +0 -6231
  213. src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +0 -6839
  214. src/resources/locks/uv-langgraph_base_react-agent_engine.lock +0 -5233
  215. src/resources/locks/uv-langgraph_base_react-cloud_run.lock +0 -5862
  216. src/resources/locks/uv-live_api-cloud_run.lock +0 -5832
  217. src/resources/setup_cicd/cicd_variables.tf +0 -41
  218. src/resources/setup_cicd/github.tf +0 -87
  219. {agents → agent_starter_pack/agents}/agentic_rag/app/retrievers.py +0 -0
  220. {agents → agent_starter_pack/agents}/agentic_rag/app/templates.py +0 -0
  221. {src → agent_starter_pack}/base_template/deployment/terraform/dev/vars/env.tfvars +0 -0
  222. {src → agent_starter_pack}/base_template/tests/unit/test_dummy.py +0 -0
  223. {src/deployment_targets/agent_engine/app/utils → agent_starter_pack/base_template/{{cookiecutter.agent_directory}}/app_utils}/gcs.py +0 -0
  224. {src → agent_starter_pack}/cli/utils/__init__.py +0 -0
  225. {src → agent_starter_pack}/cli/utils/datastores.py +0 -0
  226. {src → agent_starter_pack}/cli/utils/version.py +0 -0
  227. {src → agent_starter_pack}/data_ingestion/README.md +0 -0
  228. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/components/ingest_data.py +0 -0
  229. {src → agent_starter_pack}/data_ingestion/data_ingestion_pipeline/pipeline.py +0 -0
  230. {src → agent_starter_pack}/deployment_targets/agent_engine/deployment_metadata.json +0 -0
  231. {src → agent_starter_pack}/deployment_targets/agent_engine/tests/load_test/.results/.placeholder +0 -0
  232. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/favicon.ico +0 -0
  233. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/index.html +0 -0
  234. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/public/robots.txt +0 -0
  235. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.scss +0 -0
  236. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/App.test.tsx +0 -0
  237. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/AudioPulse.tsx +0 -0
  238. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/audio-pulse/audio-pulse.scss +0 -0
  239. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/components/logger/mock-logs.ts +0 -0
  240. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/contexts/LiveAPIContext.tsx +0 -0
  241. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-media-stream-mux.ts +0 -0
  242. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-screen-capture.ts +0 -0
  243. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/hooks/use-webcam.ts +0 -0
  244. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.css +0 -0
  245. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/index.tsx +0 -0
  246. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/react-app-env.d.ts +0 -0
  247. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/reportWebVitals.ts +0 -0
  248. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/setupTests.ts +0 -0
  249. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/audioworklet-registry.ts +0 -0
  250. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/store-logger.ts +0 -0
  251. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/audio-processing.ts +0 -0
  252. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/src/utils/worklets/vol-meter.ts +0 -0
  253. {src/frontends/live_api_react → agent_starter_pack/frontends/adk_live_react}/frontend/tsconfig.json +0 -0
  254. {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/WHEEL +0 -0
  255. {agent_starter_pack-0.3.3.dist-info → agent_starter_pack-0.21.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,1628 @@
1
+ # Google Agent Development Kit (ADK) Python Cheatsheet
2
+
3
+ This document serves as a long-form, comprehensive reference for building, orchestrating, and deploying AI agents using the Python Agent Development Kit (ADK). It aims to cover every significant aspect with greater detail, more code examples, and in-depth best practices.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Core Concepts & Project Structure](#1-core-concepts--project-structure)
8
+ * 1.1 ADK's Foundational Principles
9
+ * 1.2 Essential Primitives
10
+ * 1.3 Standard Project Layout
11
+ * 1.A Build Agents without Code (Agent Config)
12
+ 2. [Agent Definitions (`LlmAgent`)](#2-agent-definitions-llmagent)
13
+ * 2.1 Basic `LlmAgent` Setup
14
+ * 2.2 Advanced `LlmAgent` Configuration
15
+ * 2.3 LLM Instruction Crafting
16
+ * 2.4 Production Wrapper (`App`)
17
+ 3. [Orchestration with Workflow Agents](#3-orchestration-with-workflow-agents)
18
+ * 3.1 `SequentialAgent`: Linear Execution
19
+ * 3.2 `ParallelAgent`: Concurrent Execution
20
+ * 3.3 `LoopAgent`: Iterative Processes
21
+ 4. [Multi-Agent Systems & Communication](#4-multi-agent-systems--communication)
22
+ * 4.1 Agent Hierarchy
23
+ * 4.2 Inter-Agent Communication Mechanisms
24
+ * 4.3 Common Multi-Agent Patterns
25
+ * 4.A Distributed Communication (A2A Protocol)
26
+ 5. [Building Custom Agents (`BaseAgent`)](#5-building-custom-agents-baseagent)
27
+ * 5.1 When to Use Custom Agents
28
+ * 5.2 Implementing `_run_async_impl`
29
+ 6. [Models: Gemini, LiteLLM, and Vertex AI](#6-models-gemini-litellm-and-vertex-ai)
30
+ * 6.1 Google Gemini Models (AI Studio & Vertex AI)
31
+ * 6.2 Other Cloud & Proprietary Models via LiteLLM
32
+ * 6.3 Open & Local Models via LiteLLM (Ollama, vLLM)
33
+ * 6.4 Customizing LLM API Clients
34
+ 7. [Tools: The Agent's Capabilities](#7-tools-the-agents-capabilities)
35
+ * 7.1 Defining Function Tools: Principles & Best Practices
36
+ * 7.2 The `ToolContext` Object: Accessing Runtime Information
37
+ * 7.3 All Tool Types & Their Usage
38
+ * 7.4 Tool Confirmation (Human-in-the-Loop)
39
+ 8. [Context, State, and Memory Management](#8-context-state-and-memory-management)
40
+ * 8.1 The `Session` Object & `SessionService`
41
+ * 8.2 `State`: The Conversational Scratchpad
42
+ * 8.3 `Memory`: Long-Term Knowledge & Retrieval
43
+ * 8.4 `Artifacts`: Binary Data Management
44
+ 9. [Runtime, Events, and Execution Flow](#9-runtime-events-and-execution-flow)
45
+ * 9.1 Runtime Configuration (`RunConfig`)
46
+ * 9.2 The `Runner`: The Orchestrator
47
+ * 9.3 The Event Loop: Core Execution Flow
48
+ * 9.4 `Event` Object: The Communication Backbone
49
+ * 9.5 Asynchronous Programming (Python Specific)
50
+ 10. [Control Flow with Callbacks](#10-control-flow-with-callbacks)
51
+ * 10.1 Callback Mechanism: Interception & Control
52
+ * 10.2 Types of Callbacks
53
+ * 10.3 Callback Best Practices
54
+ * 10.A Global Control with Plugins
55
+ 11. [Authentication for Tools](#11-authentication-for-tools)
56
+ * 11.1 Core Concepts: `AuthScheme` & `AuthCredential`
57
+ * 11.2 Interactive OAuth/OIDC Flows
58
+ * 11.3 Custom Tool Authentication
59
+ 12. [Deployment Strategies](#12-deployment-strategies)
60
+ * 12.1 Local Development & Testing (`adk web`, `adk run`, `adk api_server`)
61
+ * 12.2 Vertex AI Agent Engine
62
+ * 12.3 Cloud Run
63
+ * 12.4 Google Kubernetes Engine (GKE)
64
+ * 12.5 CI/CD Integration
65
+ 13. [Evaluation and Safety](#13-evaluation-and-safety)
66
+ * 13.1 Agent Evaluation (`adk eval`)
67
+ * 13.2 Safety & Guardrails
68
+ 14. [Debugging, Logging & Observability](#14-debugging-logging--observability)
69
+ 15. [Streaming & Advanced I/O](#15-streaming--advanced-io)
70
+ 16. [Performance Optimization](#16-performance-optimization)
71
+ 17. [General Best Practices & Common Pitfalls](#17-general-best-practices--common-pitfalls)
72
+ 18. [Official API & CLI References](#18-official-api--cli-references)
73
+
74
+ ---
75
+
76
+ ## 1. Core Concepts & Project Structure
77
+
78
+ ### 1.1 ADK's Foundational Principles
79
+
80
+ * **Modularity**: Break down complex problems into smaller, manageable agents and tools.
81
+ * **Composability**: Combine simple agents and tools to build sophisticated systems.
82
+ * **Observability**: Detailed event logging and tracing capabilities to understand agent behavior.
83
+ * **Extensibility**: Easily integrate with external services, models, and frameworks.
84
+ * **Deployment-Agnostic**: Design agents once, deploy anywhere.
85
+
86
+ ### 1.2 Essential Primitives
87
+
88
+ * **`Agent`**: The core intelligent unit. Can be `LlmAgent` (LLM-driven) or `BaseAgent` (custom/workflow).
89
+ * **`Tool`**: Callable function/class providing external capabilities (`FunctionTool`, `OpenAPIToolset`, etc.).
90
+ * **`Session`**: A unique, stateful conversation thread with history (`events`) and short-term memory (`state`).
91
+ * **`State`**: Key-value dictionary within a `Session` for transient conversation data.
92
+ * **`Memory`**: Long-term, searchable knowledge base beyond a single session (`MemoryService`).
93
+ * **`Artifact`**: Named, versioned binary data (files, images) associated with a session or user.
94
+ * **`Runner`**: The execution engine; orchestrates agent activity and event flow.
95
+ * **`Event`**: Atomic unit of communication and history; carries content and side-effect `actions`.
96
+ * **`InvocationContext`**: The comprehensive root context object holding all runtime information for a single `run_async` call.
97
+
98
+ ### 1.3 Standard Project Layout
99
+
100
+ A well-structured ADK project is crucial for maintainability and leveraging `adk` CLI tools.
101
+
102
+ ```
103
+ your_project_root/
104
+ ├── my_first_agent/ # Each folder is a distinct agent app
105
+ │ ├── __init__.py # Makes `my_first_agent` a Python package (`from . import agent`)
106
+ │ ├── agent.py # Contains `root_agent` definition and `LlmAgent`/WorkflowAgent instances
107
+ │ ├── tools.py # Custom tool function definitions
108
+ │ ├── data/ # Optional: static data, templates
109
+ │ └── .env # Environment variables (API keys, project IDs)
110
+ ├── my_second_agent/
111
+ │ ├── __init__.py
112
+ │ └── agent.py
113
+ ├── requirements.txt # Project's Python dependencies (e.g., google-adk, litellm)
114
+ ├── tests/ # Unit and integration tests
115
+ │ ├── unit/
116
+ │ │ └── test_tools.py
117
+ │ └── integration/
118
+ │ └── test_my_first_agent.py
119
+ │ └── my_first_agent.evalset.json # Evaluation dataset for `adk eval`
120
+ └── main.py # Optional: Entry point for custom FastAPI server deployment
121
+ ```
122
+ * `adk web` and `adk run` automatically discover agents in subdirectories with `__init__.py` and `agent.py`.
123
+ * `.env` files are automatically loaded by `adk` tools when run from the root or agent directory.
124
+
125
+ ### 1.A Build Agents without Code (Agent Config)
126
+
127
+ ADK allows you to define agents, tools, and even multi-agent workflows using a simple YAML format, eliminating the need to write Python code for orchestration. This is ideal for rapid prototyping and for non-programmers to configure agents.
128
+
129
+ #### **Getting Started with Agent Config**
130
+
131
+ * **Create a Config-based Agent**:
132
+ ```bash
133
+ adk create --type=config my_yaml_agent
134
+ ```
135
+ This generates a `my_yaml_agent/` folder with `root_agent.yaml` and `.env` files.
136
+
137
+ * **Environment Setup** (in `.env` file):
138
+ ```bash
139
+ # For Google AI Studio (simpler setup)
140
+ GOOGLE_GENAI_USE_VERTEXAI=0
141
+ GOOGLE_API_KEY=<your-Google-Gemini-API-key>
142
+
143
+ # For Google Cloud Vertex AI (production)
144
+ GOOGLE_GENAI_USE_VERTEXAI=1
145
+ GOOGLE_CLOUD_PROJECT=<your_gcp_project>
146
+ GOOGLE_CLOUD_LOCATION=us-central1
147
+ ```
148
+
149
+ #### **Core Agent Config Structure**
150
+
151
+ * **Basic Agent (`root_agent.yaml`)**:
152
+ ```yaml
153
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
154
+ name: assistant_agent
155
+ model: gemini-2.5-flash
156
+ description: A helper agent that can answer users' various questions.
157
+ instruction: You are an agent to help answer users' various questions.
158
+ ```
159
+
160
+ * **Agent with Built-in Tools**:
161
+ ```yaml
162
+ name: search_agent
163
+ model: gemini-2.0-flash
164
+ description: 'an agent whose job it is to perform Google search queries and answer questions about the results.'
165
+ instruction: You are an agent whose job is to perform Google search queries and answer questions about the results.
166
+ tools:
167
+ - name: google_search # Built-in ADK tool
168
+ ```
169
+
170
+ * **Agent with Custom Tools**:
171
+ ```yaml
172
+ agent_class: LlmAgent
173
+ model: gemini-2.5-flash
174
+ name: prime_agent
175
+ description: Handles checking if numbers are prime.
176
+ instruction: |
177
+ You are responsible for checking whether numbers are prime.
178
+ When asked to check primes, you must call the check_prime tool with a list of integers.
179
+ Never attempt to determine prime numbers manually.
180
+ tools:
181
+ - name: ma_llm.check_prime # Reference to Python function
182
+ ```
183
+
184
+ * **Multi-Agent System with Sub-Agents**:
185
+ ```yaml
186
+ agent_class: LlmAgent
187
+ model: gemini-2.5-flash
188
+ name: root_agent
189
+ description: Learning assistant that provides tutoring in code and math.
190
+ instruction: |
191
+ You are a learning assistant that helps students with coding and math questions.
192
+
193
+ You delegate coding questions to the code_tutor_agent and math questions to the math_tutor_agent.
194
+
195
+ Follow these steps:
196
+ 1. If the user asks about programming or coding, delegate to the code_tutor_agent.
197
+ 2. If the user asks about math concepts or problems, delegate to the math_tutor_agent.
198
+ 3. Always provide clear explanations and encourage learning.
199
+ sub_agents:
200
+ - config_path: code_tutor_agent.yaml
201
+ - config_path: math_tutor_agent.yaml
202
+ ```
203
+
204
+ #### **Loading Agent Config in Python**
205
+
206
+ ```python
207
+ from google.adk.agents import config_agent_utils
208
+ root_agent = config_agent_utils.from_config("{agent_folder}/root_agent.yaml")
209
+ ```
210
+
211
+ #### **Running Agent Config Agents**
212
+
213
+ From the agent directory, use any of these commands:
214
+ * `adk web` - Launch web UI interface
215
+ * `adk run` - Run in terminal without UI
216
+ * `adk api_server` - Run as a service for other applications
217
+
218
+ #### **Deployment Support**
219
+
220
+ Agent Config agents can be deployed using:
221
+ * `adk deploy cloud_run` - Deploy to Google Cloud Run
222
+ * `adk deploy agent_engine` - Deploy to Vertex AI Agent Engine
223
+
224
+ #### **Key Features & Capabilities**
225
+
226
+ * **Supported Built-in Tools**: `google_search`, `load_artifacts`, `url_context`, `exit_loop`, `preload_memory`, `get_user_choice`, `enterprise_web_search`, `load_web_page`
227
+ * **Custom Tool Integration**: Reference Python functions using fully qualified module paths
228
+ * **Multi-Agent Orchestration**: Link agents via `config_path` references
229
+ * **Schema Validation**: Built-in YAML schema for IDE support and validation
230
+
231
+ #### **Current Limitations** (Experimental Feature)
232
+
233
+ * **Model Support**: Only Gemini models currently supported
234
+ * **Language Support**: Custom tools must be written in Python
235
+ * **Unsupported Agent Types**: `LangGraphAgent`, `A2aAgent`
236
+ * **Unsupported Tools**: `AgentTool`, `LongRunningFunctionTool`, `VertexAiSearchTool`, `MCPToolset`, `LangchainTool`, `ExampleTool`
237
+
238
+ For complete examples and reference, see the [ADK samples repository](https://github.com/search?q=repo%3Agoogle%2Fadk-python+path%3A%2F%5Econtributing%5C%2Fsamples%5C%2F%2F+.yaml&type=code).
239
+
240
+ ---
241
+
242
+ ## 2. Agent Definitions (`LlmAgent`)
243
+
244
+ The `LlmAgent` is the cornerstone of intelligent behavior, leveraging an LLM for reasoning and decision-making.
245
+
246
+ ### 2.1 Basic `LlmAgent` Setup
247
+
248
+ ```python
249
+ from google.adk.agents import Agent
250
+
251
+ def get_current_time(city: str) -> dict:
252
+ """Returns the current time in a specified city."""
253
+ # Mock implementation
254
+ if city.lower() == "new york":
255
+ return {"status": "success", "time": "10:30 AM EST"}
256
+ return {"status": "error", "message": f"Time for {city} not available."}
257
+
258
+ my_first_llm_agent = Agent(
259
+ name="time_teller_agent",
260
+ model="gemini-2.5-flash", # Essential: The LLM powering the agent
261
+ instruction="You are a helpful assistant that tells the current time in cities. Use the 'get_current_time' tool for this purpose.",
262
+ description="Tells the current time in a specified city.", # Crucial for multi-agent delegation
263
+ tools=[get_current_time] # List of callable functions/tool instances
264
+ )
265
+ ```
266
+
267
+ ### 2.2 Advanced `LlmAgent` Configuration
268
+
269
+ * **`generate_content_config`**: Controls LLM generation parameters (temperature, token limits, safety).
270
+ ```python
271
+ from google.genai import types as genai_types
272
+ from google.adk.agents import Agent
273
+
274
+ gen_config = genai_types.GenerateContentConfig(
275
+ temperature=0.2, # Controls randomness (0.0-1.0), lower for more deterministic.
276
+ top_p=0.9, # Nucleus sampling: sample from top_p probability mass.
277
+ top_k=40, # Top-k sampling: sample from top_k most likely tokens.
278
+ max_output_tokens=1024, # Max tokens in LLM's response.
279
+ stop_sequences=["## END"] # LLM will stop generating if these sequences appear.
280
+ )
281
+ agent = Agent(
282
+ # ... basic config ...
283
+ generate_content_config=gen_config
284
+ )
285
+ ```
286
+
287
+ * **`output_key`**: Automatically saves the agent's final text or structured (if `output_schema` is used) response to the `session.state` under this key. Facilitates data flow between agents.
288
+ ```python
289
+ agent = Agent(
290
+ # ... basic config ...
291
+ output_key="llm_final_response_text"
292
+ )
293
+ # After agent runs, session.state['llm_final_response_text'] will contain its output.
294
+ ```
295
+
296
+ * **`input_schema` & `output_schema`**: Define strict JSON input/output formats using Pydantic models.
297
+ > **Warning**: Using `output_schema` forces the LLM to generate JSON and **disables** its ability to use tools or delegate to other agents.
298
+
299
+ #### **Example: Defining and Using Structured Output**
300
+
301
+ This is the most reliable way to make an LLM produce predictable, parseable JSON, which is essential for multi-agent workflows.
302
+
303
+ 1. **Define the Schema with Pydantic:**
304
+ ```python
305
+ from pydantic import BaseModel, Field
306
+ from typing import Literal
307
+
308
+ class SearchQuery(BaseModel):
309
+ """Model representing a specific search query for web search."""
310
+ search_query: str = Field(
311
+ description="A highly specific and targeted query for web search."
312
+ )
313
+
314
+ class Feedback(BaseModel):
315
+ """Model for providing evaluation feedback on research quality."""
316
+ grade: Literal["pass", "fail"] = Field(
317
+ description="Evaluation result. 'pass' if the research is sufficient, 'fail' if it needs revision."
318
+ )
319
+ comment: str = Field(
320
+ description="Detailed explanation of the evaluation, highlighting strengths and/or weaknesses of the research."
321
+ )
322
+ follow_up_queries: list[SearchQuery] | None = Field(
323
+ default=None,
324
+ description="A list of specific, targeted follow-up search queries needed to fix research gaps. This should be null or empty if the grade is 'pass'."
325
+ )
326
+ ```
327
+ * **`BaseModel` & `Field`**: Define data types, defaults, and crucial `description` fields. These descriptions are sent to the LLM to guide its output.
328
+ * **`Literal`**: Enforces strict enum-like values (`"pass"` or `"fail"`), preventing the LLM from hallucinating unexpected values.
329
+
330
+ 2. **Assign the Schema to an `LlmAgent`:**
331
+ ```python
332
+ research_evaluator = LlmAgent(
333
+ name="research_evaluator",
334
+ model="gemini-2.5-pro",
335
+ instruction="""You are a meticulous quality assurance analyst. Evaluate the research findings in 'section_research_findings' and be very critical.
336
+ If you find significant gaps, assign a grade of 'fail', write a detailed comment, and generate 5-7 specific follow-up queries.
337
+ If the research is thorough, grade it 'pass'.
338
+ Your response must be a single, raw JSON object validating against the 'Feedback' schema.
339
+ """,
340
+ output_schema=Feedback, # This forces the LLM to output JSON matching the Feedback model.
341
+ output_key="research_evaluation", # The resulting JSON object will be saved to state.
342
+ disallow_transfer_to_peers=True, # Prevents this agent from delegating. Its job is only to evaluate.
343
+ )
344
+ ```
345
+
346
+ * **`include_contents`**: Controls whether the conversation history is sent to the LLM.
347
+ * `'default'` (default): Sends relevant history.
348
+ * `'none'`: Sends no history; agent operates purely on current turn's input and `instruction`. Useful for stateless API wrapper agents.
349
+ ```python
350
+ agent = Agent(..., include_contents='none')
351
+ ```
352
+
353
+ * **`planner`**: Assign a `BasePlanner` instance to enable multi-step reasoning.
354
+ * **`BuiltInPlanner`**: Leverages a model's native "thinking" or planning capabilities (e.g., Gemini).
355
+ ```python
356
+ from google.adk.planners import BuiltInPlanner
357
+ from google.genai.types import ThinkingConfig
358
+
359
+ agent = Agent(
360
+ model="gemini-2.5-flash",
361
+ planner=BuiltInPlanner(
362
+ thinking_config=ThinkingConfig(include_thoughts=True)
363
+ ),
364
+ # ... tools ...
365
+ )
366
+ ```
367
+ * **`PlanReActPlanner`**: Instructs the model to follow a structured Plan-Reason-Act output format, useful for models without built-in planning.
368
+
369
+ * **`code_executor`**: Assign a `BaseCodeExecutor` to allow the agent to execute code blocks.
370
+ * **`BuiltInCodeExecutor`**: The standard, sandboxed code executor provided by ADK for safe execution.
371
+ ```python
372
+ from google.adk.code_executors import BuiltInCodeExecutor
373
+ agent = Agent(
374
+ name="code_agent",
375
+ model="gemini-2.5-flash",
376
+ instruction="Write and execute Python code to solve math problems.",
377
+ code_executor=BuiltInCodeExecutor() # Corrected from a list to an instance
378
+ )
379
+ ```
380
+
381
+ * **Callbacks**: Hooks for observing and modifying agent behavior at key lifecycle points (`before_model_callback`, `after_tool_callback`, etc.). (Covered in Callbacks).
382
+
383
+ ### 2.3 LLM Instruction Crafting (`instruction`)
384
+
385
+ The `instruction` is critical. It guides the LLM's behavior, persona, and tool usage. The following examples demonstrate powerful techniques for creating specialized, reliable agents.
386
+
387
+ **Best Practices & Examples:**
388
+
389
+ * **Be Specific & Concise**: Avoid ambiguity.
390
+ * **Define Persona & Role**: Give the LLM a clear role.
391
+ * **Constrain Behavior & Tool Use**: Explicitly state what the LLM *and should not* do.
392
+ * **Define Output Format**: Tell the LLM *exactly* what its output should look like, especially when not using `output_schema`.
393
+ * **Dynamic Injection**: Use `{state_key}` to inject runtime data from `session.state` into the prompt.
394
+ * **Iteration**: Test, observe, and refine instructions.
395
+
396
+ **Example 1: Constraining Tool Use and Output Format**
397
+ ```python
398
+ import datetime
399
+ from google.adk.tools import google_search
400
+
401
+
402
+ plan_generator = LlmAgent(
403
+ model="gemini-2.5-flash",
404
+ name="plan_generator",
405
+ description="Generates a 4-5 line action-oriented research plan.",
406
+ instruction=f"""
407
+ You are a research strategist. Your job is to create a high-level RESEARCH PLAN, not a summary.
408
+ **RULE: Your output MUST be a bulleted list of 4-5 action-oriented research goals or key questions.**
409
+ - A good goal starts with a verb like "Analyze," "Identify," "Investigate."
410
+ - A bad output is a statement of fact like "The event was in April 2024."
411
+ **TOOL USE IS STRICTLY LIMITED:**
412
+ Your goal is to create a generic, high-quality plan *without searching*.
413
+ Only use `google_search` if a topic is ambiguous and you absolutely cannot create a plan without it.
414
+ You are explicitly forbidden from researching the *content* or *themes* of the topic.
415
+ Current date: {datetime.datetime.now().strftime("%Y-%m-%d")}
416
+ """,
417
+ tools=[google_search],
418
+ )
419
+ ```
420
+
421
+ **Example 2: Injecting Data from State and Specifying Custom Tags**
422
+ This agent's `instruction` relies on data placed in `session.state` by previous agents.
423
+ ```python
424
+ report_composer = LlmAgent(
425
+ model="gemini-2.5-pro",
426
+ name="report_composer_with_citations",
427
+ include_contents="none", # History not needed; all data is injected.
428
+ description="Transforms research data and a markdown outline into a final, cited report.",
429
+ instruction="""
430
+ Transform the provided data into a polished, professional, and meticulously cited research report.
431
+
432
+ ---
433
+ ### INPUT DATA
434
+ * Research Plan: `{research_plan}`
435
+ * Research Findings: `{section_research_findings}`
436
+ * Citation Sources: `{sources}`
437
+ * Report Structure: `{report_sections}`
438
+
439
+ ---
440
+ ### CRITICAL: Citation System
441
+ To cite a source, you MUST insert a special citation tag directly after the claim it supports.
442
+
443
+ **The only correct format is:** `<cite source="src-ID_NUMBER" />`
444
+
445
+ ---
446
+ ### Final Instructions
447
+ Generate a comprehensive report using ONLY the `<cite source="src-ID_NUMBER" />` tag system for all citations.
448
+ The final report must strictly follow the structure provided in the **Report Structure** markdown outline.
449
+ Do not include a "References" or "Sources" section; all citations must be in-line.
450
+ """,
451
+ output_key="final_cited_report",
452
+ )
453
+ ```
454
+
455
+ ### 2.4 Production Wrapper (`App`)
456
+ Wraps the `root_agent` to enable production-grade runtime features that an `Agent` cannot handle alone.
457
+
458
+ ```python
459
+ from google.adk.apps.app import App
460
+ from google.adk.agents.context_cache_config import ContextCacheConfig
461
+ from google.adk.apps.events_compaction_config import EventsCompactionConfig
462
+ from google.adk.apps.resumability_config import ResumabilityConfig
463
+
464
+ production_app = App(
465
+ name="my_app",
466
+ root_agent=my_agent,
467
+ # 1. Reduce costs/latency for long contexts
468
+ context_cache_config=ContextCacheConfig(min_tokens=2048, ttl_seconds=600),
469
+ # 2. Allow resuming crashed workflows from last state
470
+ resumability_config=ResumabilityConfig(is_resumable=True),
471
+ # 3. Manage long conversation history automatically
472
+ events_compaction_config=EventsCompactionConfig(compaction_interval=5, overlap_size=1)
473
+ )
474
+
475
+ # Usage: Pass 'app' instead of 'agent' to the Runner
476
+ # runner = Runner(app=production_app, ...)
477
+ ```
478
+
479
+ ---
480
+
481
+ ## 3. Orchestration with Workflow Agents
482
+
483
+ Workflow agents (`SequentialAgent`, `ParallelAgent`, `LoopAgent`) provide deterministic control flow, combining LLM capabilities with structured execution. They do **not** use an LLM for their own orchestration logic.
484
+
485
+ ### 3.1 `SequentialAgent`: Linear Execution
486
+
487
+ Executes `sub_agents` one after another in the order defined. The `InvocationContext` is passed along, allowing state changes to be visible to subsequent agents.
488
+
489
+ ```python
490
+ from google.adk.agents import SequentialAgent, Agent
491
+
492
+ # Agent 1: Summarizes a document and saves to state
493
+ summarizer = Agent(
494
+ name="DocumentSummarizer",
495
+ model="gemini-2.5-flash",
496
+ instruction="Summarize the provided document in 3 sentences.",
497
+ output_key="document_summary" # Output saved to session.state['document_summary']
498
+ )
499
+
500
+ # Agent 2: Generates questions based on the summary from state
501
+ question_generator = Agent(
502
+ name="QuestionGenerator",
503
+ model="gemini-2.5-flash",
504
+ instruction="Generate 3 comprehension questions based on this summary: {document_summary}",
505
+ # 'document_summary' is dynamically injected from session.state
506
+ )
507
+
508
+ document_pipeline = SequentialAgent(
509
+ name="SummaryQuestionPipeline",
510
+ sub_agents=[summarizer, question_generator], # Order matters!
511
+ description="Summarizes a document then generates questions."
512
+ )
513
+ ```
514
+
515
+ ### 3.2 `ParallelAgent`: Concurrent Execution
516
+
517
+ Executes `sub_agents` simultaneously. Useful for independent tasks to reduce overall latency. All sub-agents share the same `session.state`.
518
+
519
+ ```python
520
+ from google.adk.agents import ParallelAgent, Agent, SequentialAgent
521
+
522
+ # Agents to fetch data concurrently
523
+ fetch_stock_price = Agent(name="StockPriceFetcher", ..., output_key="stock_data")
524
+ fetch_news_headlines = Agent(name="NewsFetcher", ..., output_key="news_data")
525
+ fetch_social_sentiment = Agent(name="SentimentAnalyzer", ..., output_key="sentiment_data")
526
+
527
+ # Agent to merge results (runs after ParallelAgent, usually in a SequentialAgent)
528
+ merger_agent = Agent(
529
+ name="ReportGenerator",
530
+ model="gemini-2.5-flash",
531
+ instruction="Combine stock data: {stock_data}, news: {news_data}, and sentiment: {sentiment_data} into a market report."
532
+ )
533
+
534
+ # Pipeline to run parallel fetching then sequential merging
535
+ market_analysis_pipeline = SequentialAgent(
536
+ name="MarketAnalyzer",
537
+ sub_agents=[
538
+ ParallelAgent(
539
+ name="ConcurrentFetch",
540
+ sub_agents=[fetch_stock_price, fetch_news_headlines, fetch_social_sentiment]
541
+ ),
542
+ merger_agent # Runs after all parallel agents complete
543
+ ]
544
+ )
545
+ ```
546
+ * **Concurrency Caution**: When parallel agents write to the same `state` key, race conditions can occur. Always use distinct `output_key`s or manage concurrent writes explicitly.
547
+
548
+ ### 3.3 `LoopAgent`: Iterative Processes
549
+
550
+ Repeatedly executes its `sub_agents` (sequentially within each loop iteration) until a condition is met or `max_iterations` is reached.
551
+
552
+ #### **Termination of `LoopAgent`**
553
+ A `LoopAgent` terminates when:
554
+ 1. `max_iterations` is reached.
555
+ 2. Any `Event` yielded by a sub-agent (or a tool within it) sets `actions.escalate = True`. This provides dynamic, content-driven loop termination.
556
+
557
+ #### **Example: Iterative Refinement Loop with a Custom `BaseAgent` for Control**
558
+ This example shows a loop that continues until a condition, determined by an evaluation agent, is met.
559
+
560
+ ```python
561
+ from google.adk.agents import LoopAgent, Agent, BaseAgent
562
+ from google.adk.events import Event, EventActions
563
+ from google.adk.agents.invocation_context import InvocationContext
564
+ from typing import AsyncGenerator
565
+
566
+ # An LLM Agent that evaluates research and produces structured JSON output
567
+ research_evaluator = Agent(
568
+ name="research_evaluator",
569
+ # ... configuration from Section 2.2 ...
570
+ output_schema=Feedback,
571
+ output_key="research_evaluation",
572
+ )
573
+
574
+ # An LLM Agent that performs additional searches based on feedback
575
+ enhanced_search_executor = Agent(
576
+ name="enhanced_search_executor",
577
+ instruction="Execute the follow-up queries from 'research_evaluation' and combine with existing findings.",
578
+ # ... other configurations ...
579
+ )
580
+
581
+ # A custom BaseAgent to check the evaluation and stop the loop
582
+ class EscalationChecker(BaseAgent):
583
+ """Checks research evaluation and escalates to stop the loop if grade is 'pass'."""
584
+ async def _run_async_impl(self, ctx: InvocationContext) -> AsyncGenerator[Event, None]:
585
+ evaluation = ctx.session.state.get("research_evaluation")
586
+ if evaluation and evaluation.get("grade") == "pass":
587
+ # The key to stopping the loop: yield an Event with escalate=True
588
+ yield Event(author=self.name, actions=EventActions(escalate=True))
589
+ else:
590
+ # Let the loop continue
591
+ yield Event(author=self.name)
592
+
593
+ # Define the loop
594
+ iterative_refinement_loop = LoopAgent(
595
+ name="IterativeRefinementLoop",
596
+ sub_agents=[
597
+ research_evaluator, # Step 1: Evaluate
598
+ EscalationChecker(name="EscalationChecker"), # Step 2: Check and maybe stop
599
+ enhanced_search_executor, # Step 3: Refine (only runs if loop didn't stop)
600
+ ],
601
+ max_iterations=5, # Fallback to prevent infinite loops
602
+ description="Iteratively evaluates and refines research until it passes quality checks."
603
+ )
604
+ ```
605
+
606
+ ---
607
+
608
+ ## 4. Multi-Agent Systems & Communication
609
+
610
+ Building complex applications by composing multiple, specialized agents.
611
+
612
+ ### 4.1 Agent Hierarchy
613
+
614
+ A hierarchical (tree-like) structure of parent-child relationships defined by the `sub_agents` parameter during `BaseAgent` initialization. An agent can only have one parent.
615
+
616
+ ```python
617
+ # Conceptual Hierarchy
618
+ # Root
619
+ # └── Coordinator (LlmAgent)
620
+ # ├── SalesAgent (LlmAgent)
621
+ # └── SupportAgent (LlmAgent)
622
+ # └── DataPipeline (SequentialAgent)
623
+ # ├── DataFetcher (LlmAgent)
624
+ # └── DataProcessor (LlmAgent)
625
+ ```
626
+
627
+ ### 4.2 Inter-Agent Communication Mechanisms
628
+
629
+ 1. **Shared Session State (`session.state`)**: The most common and robust method. Agents read from and write to the same mutable dictionary.
630
+ * **Mechanism**: Agent A sets `ctx.session.state['key'] = value`. Agent B later reads `ctx.session.state.get('key')`. `output_key` on `LlmAgent` is a convenient auto-setter.
631
+ * **Best for**: Passing intermediate results, shared configurations, and flags in pipelines (Sequential, Loop agents).
632
+
633
+ 2. **LLM-Driven Delegation (`transfer_to_agent`)**: A `LlmAgent` can dynamically hand over control to another agent based on its reasoning.
634
+ * **Mechanism**: The LLM generates a special `transfer_to_agent` function call. The ADK framework intercepts this, routes the next turn to the target agent.
635
+ * **Prerequisites**:
636
+ * The initiating `LlmAgent` needs `instruction` to guide delegation and `description` of the target agent(s).
637
+ * Target agents need clear `description`s to help the LLM decide.
638
+ * Target agent must be discoverable within the current agent's hierarchy (direct `sub_agent` or a descendant).
639
+ * **Configuration**: Can be enabled/disabled via `disallow_transfer_to_parent` and `disallow_transfer_to_peers` on `LlmAgent`.
640
+
641
+ 3. **Explicit Invocation (`AgentTool`)**: An `LlmAgent` can treat another `BaseAgent` instance as a callable tool.
642
+ * **Mechanism**: Wrap the target agent (`target_agent`) in `AgentTool(agent=target_agent)` and add it to the calling `LlmAgent`'s `tools` list. The `AgentTool` generates a `FunctionDeclaration` for the LLM. When called, `AgentTool` runs the target agent and returns its final response as the tool result.
643
+ * **Best for**: Hierarchical task decomposition, where a higher-level agent needs a specific output from a lower-level agent.
644
+
645
+ **Delegation vs. Agent-as-a-Tool**
646
+ * **Delegation (`sub_agents`)**: The parent agent *transfers control*. The sub-agent interacts directly with the user for subsequent turns until it finishes.
647
+ * **Agent-as-a-Tool (`AgentTool`)**: The parent agent *calls* another agent like a function. The parent remains in control, receives the sub-agent's entire interaction as a single tool result, and summarizes it for the user.
648
+
649
+ ```python
650
+ # Delegation: "I'll let the specialist handle this conversation."
651
+ root = Agent(name="root", sub_agents=[specialist])
652
+
653
+ # Agent-as-a-Tool: "I need the specialist to do a task and give me the results."
654
+ from google.adk.tools import AgentTool
655
+ root = Agent(name="root", tools=[AgentTool(specialist)])
656
+ ```
657
+
658
+ ### 4.3 Common Multi-Agent Patterns
659
+
660
+ * **Coordinator/Dispatcher**: A central agent routes requests to specialized sub-agents (often via LLM-driven delegation).
661
+ * **Sequential Pipeline**: `SequentialAgent` orchestrates a fixed sequence of tasks, passing data via shared state.
662
+ * **Parallel Fan-Out/Gather**: `ParallelAgent` runs concurrent tasks, followed by a final agent that synthesizes results from state.
663
+ * **Review/Critique (Generator-Critic)**: `SequentialAgent` with a generator followed by a critic, often in a `LoopAgent` for iterative refinement.
664
+ * **Hierarchical Task Decomposition (Planner/Executor)**: High-level agents break down complex problems, delegating sub-tasks to lower-level agents (often via `AgentTool` and delegation).
665
+
666
+ #### **Example: Hierarchical Planner/Executor Pattern**
667
+ This pattern combines several mechanisms. A top-level `interactive_planner_agent` uses another agent (`plan_generator`) as a tool to create a plan, then delegates the execution of that plan to a complex `SequentialAgent` (`research_pipeline`).
668
+
669
+ ```python
670
+ from google.adk.agents import LlmAgent, SequentialAgent, LoopAgent
671
+ from google.adk.tools.agent_tool import AgentTool
672
+
673
+ # Assume plan_generator, section_planner, research_evaluator, etc. are defined.
674
+
675
+ # The execution pipeline itself is a complex agent.
676
+ research_pipeline = SequentialAgent(
677
+ name="research_pipeline",
678
+ description="Executes a pre-approved research plan. It performs iterative research, evaluation, and composes a final, cited report.",
679
+ sub_agents=[
680
+ section_planner,
681
+ section_researcher,
682
+ LoopAgent(
683
+ name="iterative_refinement_loop",
684
+ max_iterations=3,
685
+ sub_agents=[
686
+ research_evaluator,
687
+ EscalationChecker(name="escalation_checker"),
688
+ enhanced_search_executor,
689
+ ],
690
+ ),
691
+ report_composer,
692
+ ],
693
+ )
694
+
695
+ # The top-level agent that interacts with the user.
696
+ interactive_planner_agent = LlmAgent(
697
+ name="interactive_planner_agent",
698
+ model="gemini-2.5-flash",
699
+ description="The primary research assistant. It collaborates with the user to create a research plan, and then executes it upon approval.",
700
+ instruction="""
701
+ You are a research planning assistant. Your workflow is:
702
+ 1. **Plan:** Use the `plan_generator` tool to create a draft research plan.
703
+ 2. **Refine:** Incorporate user feedback until the plan is approved.
704
+ 3. **Execute:** Once the user gives EXPLICIT approval (e.g., "looks good, run it"), you MUST delegate the task to the `research_pipeline` agent.
705
+ Your job is to Plan, Refine, and Delegate. Do not do the research yourself.
706
+ """,
707
+ # The planner delegates to the pipeline.
708
+ sub_agents=[research_pipeline],
709
+ # The planner uses another agent as a tool.
710
+ tools=[AgentTool(plan_generator)],
711
+ output_key="research_plan",
712
+ )
713
+
714
+ # The root agent of the application is the top-level planner.
715
+ root_agent = interactive_planner_agent
716
+ ```
717
+
718
+ ### 4.A. Distributed Communication (A2A Protocol)
719
+
720
+ The Agent-to-Agent (A2A) Protocol enables agents to communicate over a network, even if they are written in different languages or run as separate services. Use A2A for integrating with third-party agents, building microservice-based agent architectures, or when a strong, formal API contract is needed. For internal code organization, prefer local sub-agents.
721
+
722
+ * **Exposing an Agent**: Make an existing ADK agent available to others over A2A.
723
+ * **`to_a2a()` Utility**: The simplest method. Wraps your `root_agent` and creates a runnable FastAPI app, auto-generating the required `agent.json` card.
724
+ ```python
725
+ from google.adk.a2a.utils.agent_to_a2a import to_a2a
726
+ # root_agent is your existing ADK Agent instance
727
+ a2a_app = to_a2a(root_agent, port=8001)
728
+ # Run with: uvicorn your_module:a2a_app --host localhost --port 8001
729
+ ```
730
+ * **`adk api_server --a2a`**: A CLI command that serves agents from a directory. Requires you to manually create an `agent.json` card for each agent you want to expose.
731
+
732
+ * **Consuming a Remote Agent**: Use a remote A2A agent as if it were a local agent.
733
+ * **`RemoteA2aAgent`**: This agent acts as a client proxy. You initialize it with the URL to the remote agent's card.
734
+ ```python
735
+ from google.adk.a2a.remote_a2a_agent import RemoteA2aAgent
736
+
737
+ # This agent can now be used as a sub-agent or tool
738
+ prime_checker_agent = RemoteA2aAgent(
739
+ name="prime_agent",
740
+ description="A remote agent that checks if numbers are prime.",
741
+ agent_card="http://localhost:8001/a2a/check_prime_agent/.well-known/agent.json"
742
+ )
743
+ ```
744
+
745
+ ---
746
+
747
+ ## 5. Building Custom Agents (`BaseAgent`)
748
+
749
+ For unique orchestration logic that doesn't fit standard workflow agents, inherit directly from `BaseAgent`.
750
+
751
+ ### 5.1 When to Use Custom Agents
752
+
753
+ * **Complex Conditional Logic**: `if/else` branching based on multiple state variables.
754
+ * **Dynamic Agent Selection**: Choosing which sub-agent to run based on runtime evaluation.
755
+ * **Direct External Integrations**: Calling external APIs or libraries directly within the orchestration flow.
756
+ * **Custom Loop/Retry Logic**: More sophisticated iteration patterns than `LoopAgent`, such as the `EscalationChecker` example.
757
+
758
+ ### 5.2 Implementing `_run_async_impl`
759
+
760
+ This is the core asynchronous method you must override.
761
+
762
+ #### **Example: A Custom Agent for Loop Control**
763
+ This agent reads state, applies simple Python logic, and yields an `Event` with an `escalate` action to control a `LoopAgent`.
764
+
765
+ ```python
766
+ from google.adk.agents import BaseAgent
767
+ from google.adk.agents.invocation_context import InvocationContext
768
+ from google.adk.events import Event, EventActions
769
+ from typing import AsyncGenerator
770
+ import logging
771
+
772
+ class EscalationChecker(BaseAgent):
773
+ """Checks research evaluation and escalates to stop the loop if grade is 'pass'."""
774
+
775
+ def __init__(self, name: str):
776
+ super().__init__(name=name)
777
+
778
+ async def _run_async_impl(
779
+ self, ctx: InvocationContext
780
+ ) -> AsyncGenerator[Event, None]:
781
+ # 1. Read from session state.
782
+ evaluation_result = ctx.session.state.get("research_evaluation")
783
+
784
+ # 2. Apply custom Python logic.
785
+ if evaluation_result and evaluation_result.get("grade") == "pass":
786
+ logging.info(
787
+ f"[{self.name}] Research passed. Escalating to stop loop."
788
+ )
789
+ # 3. Yield an Event with a control Action.
790
+ yield Event(author=self.name, actions=EventActions(escalate=True))
791
+ else:
792
+ logging.info(
793
+ f"[{self.name}] Research failed or not found. Loop continues."
794
+ )
795
+ # Yielding an event without actions lets the flow continue.
796
+ yield Event(author=self.name)
797
+ ```
798
+ * **Asynchronous Generator**: `async def ... yield Event`. This allows pausing and resuming execution.
799
+ * **`ctx: InvocationContext`**: Provides access to all session state (`ctx.session.state`).
800
+ * **Calling Sub-Agents**: Use `async for event in self.sub_agent_instance.run_async(ctx): yield event`.
801
+ * **Control Flow**: Use standard Python `if/else`, `for/while` loops for complex logic.
802
+
803
+ ---
804
+
805
+ ## 6. Models: Gemini, LiteLLM, and Vertex AI
806
+
807
+ ADK's model flexibility allows integrating various LLMs for different needs.
808
+
809
+ ### 6.1 Google Gemini Models (AI Studio & Vertex AI)
810
+
811
+ * **Default Integration**: Native support via `google-genai` library.
812
+ * **AI Studio (Easy Start)**:
813
+ * Set `GOOGLE_API_KEY="YOUR_API_KEY"` (environment variable).
814
+ * Set `GOOGLE_GENAI_USE_VERTEXAI="False"`.
815
+ * Model strings: `"gemini-2.5-flash"`, `"gemini-2.5-pro"`, etc.
816
+ * **Vertex AI (Production)**:
817
+ * Authenticate via `gcloud auth application-default login` (recommended).
818
+ * Set `GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID"`, `GOOGLE_CLOUD_LOCATION="your-region"` (environment variables).
819
+ * Set `GOOGLE_GENAI_USE_VERTEXAI="True"`.
820
+ * Model strings: `"gemini-2.5-flash"`, `"gemini-2.5-pro"`, or full Vertex AI endpoint resource names for specific deployments.
821
+
822
+ ### 6.2 Other Cloud & Proprietary Models via LiteLLM
823
+
824
+ `LiteLlm` provides a unified interface to 100+ LLMs (OpenAI, Anthropic, Cohere, etc.).
825
+
826
+ * **Installation**: `pip install litellm`
827
+ * **API Keys**: Set environment variables as required by LiteLLM (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`).
828
+ * **Usage**:
829
+ ```python
830
+ from google.adk.models.lite_llm import LiteLlm
831
+ agent_openai = Agent(model=LiteLlm(model="openai/gpt-4o"), ...)
832
+ agent_claude = Agent(model=LiteLlm(model="anthropic/claude-3-haiku-20240307"), ...)
833
+ ```
834
+
835
+ ### 6.3 Open & Local Models via LiteLLM (Ollama, vLLM)
836
+
837
+ For self-hosting, cost savings, privacy, or offline use.
838
+
839
+ * **Ollama Integration**: Run Ollama locally (`ollama run <model>`).
840
+ ```bash
841
+ export OLLAMA_API_BASE="http://localhost:11434" # Ensure Ollama server is running
842
+ ```
843
+ ```python
844
+ from google.adk.models.lite_llm import LiteLlm
845
+ # Use 'ollama_chat' provider for tool-calling capabilities with Ollama models
846
+ agent_ollama = Agent(model=LiteLlm(model="ollama_chat/llama3:instruct"), ...)
847
+ ```
848
+
849
+ * **Self-Hosted Endpoint (e.g., vLLM)**:
850
+ ```python
851
+ from google.adk.models.lite_llm import LiteLlm
852
+ api_base_url = "https://your-vllm-endpoint.example.com/v1"
853
+ agent_vllm = Agent(
854
+ model=LiteLlm(
855
+ model="your-model-name-on-vllm",
856
+ api_base=api_base_url,
857
+ extra_headers={"Authorization": "Bearer YOUR_TOKEN"},
858
+ ),
859
+ ...
860
+ )
861
+ ```
862
+
863
+ ### 6.4 Customizing LLM API Clients
864
+
865
+ For `google-genai` (used by Gemini models), you can configure the underlying client.
866
+
867
+ ```python
868
+ import os
869
+ from google.genai import configure as genai_configure
870
+
871
+ genai_configure.use_defaults(
872
+ timeout=60, # seconds
873
+ client_options={"api_key": os.getenv("GOOGLE_API_KEY")},
874
+ )
875
+ ```
876
+
877
+ ---
878
+
879
+ ## 7. Tools: The Agent's Capabilities
880
+
881
+ Tools extend an agent's abilities beyond text generation.
882
+
883
+ ### 7.1 Defining Function Tools: Principles & Best Practices
884
+
885
+ * **Signature**: `def my_tool(param1: Type, param2: Type, tool_context: ToolContext) -> dict:`
886
+ * **Function Name**: Descriptive verb-noun (e.g., `schedule_meeting`).
887
+ * **Parameters**: Clear names, required type hints, **NO DEFAULT VALUES**.
888
+ * **Return Type**: **Must** be a `dict` (JSON-serializable), preferably with a `'status'` key.
889
+ * **Docstring**: **CRITICAL**. Explain purpose, when to use, arguments, and return value structure. **AVOID** mentioning `tool_context`.
890
+
891
+ ```python
892
+ def calculate_compound_interest(
893
+ principal: float,
894
+ rate: float,
895
+ years: int,
896
+ compounding_frequency: int,
897
+ tool_context: ToolContext
898
+ ) -> dict:
899
+ """Calculates the future value of an investment with compound interest.
900
+
901
+ Use this tool to calculate the future value of an investment given a
902
+ principal amount, interest rate, number of years, and how often the
903
+ interest is compounded per year.
904
+
905
+ Args:
906
+ principal (float): The initial amount of money invested.
907
+ rate (float): The annual interest rate (e.g., 0.05 for 5%).
908
+ years (int): The number of years the money is invested.
909
+ compounding_frequency (int): The number of times interest is compounded
910
+ per year (e.g., 1 for annually, 12 for monthly).
911
+
912
+ Returns:
913
+ dict: Contains the calculation result.
914
+ - 'status' (str): "success" or "error".
915
+ - 'future_value' (float, optional): The calculated future value.
916
+ - 'error_message' (str, optional): Description of error, if any.
917
+ """
918
+ # ... implementation ...
919
+ ```
920
+
921
+ ### 7.2 The `ToolContext` Object: Accessing Runtime Information
922
+
923
+ `ToolContext` is the gateway for tools to interact with the ADK runtime.
924
+
925
+ * `tool_context.state`: Read and write to the current `Session`'s `state` dictionary.
926
+ * `tool_context.actions`: Modify the `EventActions` object (e.g., `tool_context.actions.escalate = True`).
927
+ * `tool_context.load_artifact(filename)` / `tool_context.save_artifact(filename, part)`: Manage binary data.
928
+ * `tool_context.search_memory(query)`: Query the long-term `MemoryService`.
929
+
930
+ ### 7.3 All Tool Types & Their Usage
931
+
932
+ 1. **Custom Function Tools**:
933
+ * **`FunctionTool`**: The most common type, wrapping a standard Python function.
934
+ * **`LongRunningFunctionTool`**: Wraps an `async` function that `yields` intermediate results, for tasks that provide progress updates.
935
+ * **`AgentTool`**: Wraps another `BaseAgent` instance, allowing it to be invoked as a tool by a parent agent.
936
+
937
+ 2. **Built-in Tools**: Ready-to-use tools provided by ADK.
938
+ * `google_search`: Provides Google Search grounding.
939
+ * **Code Execution**:
940
+ * `BuiltInCodeExecutor`: Local, convenient for development. **Not** for untrusted production use.
941
+ * `GkeCodeExecutor`: Production-grade. Executes code in ephemeral, sandboxed pods on Google Kubernetes Engine (GKE) using gVisor for isolation. Requires GKE cluster setup.
942
+ * `VertexAiSearchTool`: Provides grounding from your private Vertex AI Search data stores.
943
+ * `BigQueryToolset`: A collection of tools for interacting with BigQuery (e.g., `list_datasets`, `execute_sql`).
944
+ > **Warning**: An agent can only use one type of built-in tool at a time and they cannot be used in sub-agents.
945
+
946
+ 3. **Third-Party Tool Wrappers**: For seamless integration with other frameworks.
947
+ * `LangchainTool`: Wraps a tool from the LangChain ecosystem.
948
+
949
+ 4. **OpenAPI & Protocol Tools**: For interacting with APIs and services.
950
+ * **`OpenAPIToolset`**: Automatically generates a set of `RestApiTool`s from an OpenAPI (Swagger) v3 specification.
951
+ * **`MCPToolset`**: Connects to an external Model Context Protocol (MCP) server to dynamically load its tools.
952
+
953
+ 5. **Google Cloud Tools**: For deep integration with Google Cloud services.
954
+ * **`ApiHubToolset`**: Turns any documented API from Apigee API Hub into a tool.
955
+ * **`ApplicationIntegrationToolset`**: Turns Application Integration workflows and Integration Connectors (e.g., Salesforce, SAP) into callable tools.
956
+ * **Toolbox for Databases**: An open-source MCP server that ADK can connect to for database interactions.
957
+
958
+ 6. **Dynamic Toolsets (`BaseToolset`)**: Instead of a static list of tools, use a `Toolset` to dynamically determine which tools an agent can use based on the current context (e.g., user permissions).
959
+ ```python
960
+ from google.adk.tools.base_toolset import BaseToolset
961
+
962
+ class AdminAwareToolset(BaseToolset):
963
+ async def get_tools(self, context: ReadonlyContext) -> list[BaseTool]:
964
+ # Check state to see if user is admin
965
+ if context.state.get('user:role') == 'admin':
966
+ return [admin_delete_tool, standard_query_tool]
967
+ return [standard_query_tool]
968
+
969
+ # Usage:
970
+ agent = Agent(tools=[AdminAwareToolset()])
971
+ ```
972
+
973
+ ### 7.4 Tool Confirmation (Human-in-the-Loop)
974
+ ADK can pause tool execution to request human or system confirmation before proceeding, essential for sensitive actions.
975
+
976
+ * **Boolean Confirmation**: Simple yes/no via `FunctionTool(..., require_confirmation=True)`.
977
+ * **Dynamic Confirmation**: Pass a function to `require_confirmation` to decide at runtime based on arguments.
978
+ * **Advanced/Payload Confirmation**: Use `tool_context.request_confirmation()` inside the tool for structured feedback.
979
+
980
+ ```python
981
+ from google.adk.tools import FunctionTool, ToolContext
982
+
983
+ # 1. Simple Boolean Confirmation
984
+ # Pauses execution until a 'confirmed': True/False event is received.
985
+ sensitive_tool = FunctionTool(delete_database, require_confirmation=True)
986
+
987
+ # 2. Dynamic Threshold Confirmation
988
+ def needs_approval(amount: float, **kwargs) -> bool:
989
+ return amount > 10000
990
+
991
+ transfer_tool = FunctionTool(wire_money, require_confirmation=needs_approval)
992
+
993
+ # 3. Advanced Payload Confirmation (inside tool definition)
994
+ def book_flight(destination: str, price: float, tool_context: ToolContext):
995
+ # Pause and ask user to select a seat class before continuing
996
+ tool_context.request_confirmation(
997
+ hint="Please confirm booking and select seat class.",
998
+ payload={"seat_class": ["economy", "business", "first"]} # Expected structure
999
+ )
1000
+ return {"status": "pending_confirmation"}
1001
+ ```
1002
+
1003
+ ---
1004
+
1005
+ ## 8. Context, State, and Memory Management
1006
+
1007
+ Effective context management is crucial for coherent, multi-turn conversations.
1008
+
1009
+ ### 8.1 The `Session` Object & `SessionService`
1010
+
1011
+ * **`Session`**: The container for a single, ongoing conversation (`id`, `state`, `events`).
1012
+ * **`SessionService`**: Manages the lifecycle of `Session` objects (`create_session`, `get_session`, `append_event`).
1013
+ * **Implementations**: `InMemorySessionService` (dev), `VertexAiSessionService` (prod), `DatabaseSessionService` (self-managed).
1014
+
1015
+ ### 8.2 `State`: The Conversational Scratchpad
1016
+
1017
+ A mutable dictionary within `session.state` for short-term, dynamic data.
1018
+
1019
+ * **Update Mechanism**: Always update via `context.state` (in callbacks/tools) or `LlmAgent.output_key`.
1020
+ * **Prefixes for Scope**:
1021
+ * **(No prefix)**: Session-specific (e.g., `session.state['booking_step']`).
1022
+ * `user:`: Persistent for a `user_id` across all their sessions (e.g., `session.state['user:preferred_currency']`).
1023
+ * `app:`: Persistent for `app_name` across all users and sessions.
1024
+ * `temp:`: Ephemeral state that only exists for the current **invocation** (one user request -> final agent response cycle). It is discarded afterwards.
1025
+
1026
+ ### 8.3 `Memory`: Long-Term Knowledge & Retrieval
1027
+
1028
+ For knowledge beyond a single conversation.
1029
+
1030
+ * **`BaseMemoryService`**: Defines the interface (`add_session_to_memory`, `search_memory`).
1031
+ * **Implementations**: `InMemoryMemoryService`, `VertexAiRagMemoryService`.
1032
+ * **Usage**: Agents interact via tools (e.g., the built-in `load_memory` tool).
1033
+
1034
+ ### 8.4 `Artifacts`: Binary Data Management
1035
+
1036
+ For named, versioned binary data (files, images).
1037
+
1038
+ * **Representation**: `google.genai.types.Part` (containing a `Blob` with `data: bytes` and `mime_type: str`).
1039
+ * **`BaseArtifactService`**: Manages storage (`save_artifact`, `load_artifact`).
1040
+ * **Implementations**: `InMemoryArtifactService`, `GcsArtifactService`.
1041
+
1042
+ ---
1043
+
1044
+ ## 9. Runtime, Events, and Execution Flow
1045
+
1046
+ The `Runner` is the central orchestrator of an ADK application.
1047
+
1048
+ ### 9.1 Runtime Configuration (`RunConfig`)
1049
+ Passed to `run` or `run_live` to control execution limits and output formats.
1050
+
1051
+ ```python
1052
+ from google.adk.agents.run_config import RunConfig
1053
+ from google.genai import types
1054
+
1055
+ config = RunConfig(
1056
+ # Safety limits
1057
+ max_llm_calls=100, # Prevent infinite agent loops
1058
+
1059
+ # Streaming & Modality
1060
+ response_modalities=["AUDIO", "TEXT"], # Request specific output formats
1061
+
1062
+ # Voice configuration (for AUDIO modality)
1063
+ speech_config=types.SpeechConfig(
1064
+ voice_config=types.VoiceConfig(
1065
+ prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name="Kore")
1066
+ )
1067
+ ),
1068
+
1069
+ # Debugging
1070
+ save_input_blobs_as_artifacts=True # Save uploaded files to ArtifactService
1071
+ )
1072
+ ```
1073
+
1074
+ ### 9.2 The `Runner`: The Orchestrator
1075
+
1076
+ * **Role**: Manages the agent's lifecycle, the event loop, and coordinates with services.
1077
+ * **Entry Point**: `runner.run_async(user_id, session_id, new_message)`.
1078
+
1079
+ ### 9.3 The Event Loop: Core Execution Flow
1080
+
1081
+ 1. User input becomes a `user` `Event`.
1082
+ 2. `Runner` calls `agent.run_async(invocation_context)`.
1083
+ 3. Agent `yield`s an `Event` (e.g., tool call, text response). Execution pauses.
1084
+ 4. `Runner` processes the `Event` (applies state changes, etc.) and yields it to the client.
1085
+ 5. Execution resumes. This cycle repeats until the agent is done.
1086
+
1087
+ ### 9.4 `Event` Object: The Communication Backbone
1088
+
1089
+ `Event` objects carry all information and signals.
1090
+
1091
+ * `Event.author`: Source of the event (`'user'`, agent name, `'system'`).
1092
+ * `Event.content`: The primary payload (text, function calls, function responses).
1093
+ * `Event.actions`: Signals side effects (`state_delta`, `transfer_to_agent`, `escalate`).
1094
+ * `Event.is_final_response()`: Helper to identify the complete, displayable message.
1095
+
1096
+ ### 9.5 Asynchronous Programming (Python Specific)
1097
+
1098
+ ADK is built on `asyncio`. Use `async def`, `await`, and `async for` for all I/O-bound operations.
1099
+
1100
+ ---
1101
+
1102
+ ## 10. Control Flow with Callbacks
1103
+
1104
+ Callbacks are functions that intercept and control agent execution at specific points.
1105
+
1106
+ ### 10.1 Callback Mechanism: Interception & Control
1107
+
1108
+ * **Definition**: A Python function assigned to an agent's `callback` parameter (e.g., `after_agent_callback=my_func`).
1109
+ * **Context**: Receives a `CallbackContext` (or `ToolContext`) with runtime info.
1110
+ * **Return Value**: **Crucially determines flow.**
1111
+ * `return None`: Allow the default action to proceed.
1112
+ * `return <Specific Object>`: **Override** the default action/result.
1113
+
1114
+ ### 10.2 Types of Callbacks
1115
+
1116
+ 1. **Agent Lifecycle**: `before_agent_callback`, `after_agent_callback`.
1117
+ 2. **LLM Interaction**: `before_model_callback`, `after_model_callback`.
1118
+ 3. **Tool Execution**: `before_tool_callback`, `after_tool_callback`.
1119
+
1120
+ ### 10.3 Callback Best Practices
1121
+
1122
+ * **Keep Focused**: Each callback for a single purpose.
1123
+ * **Performance**: Avoid blocking I/O or heavy computation.
1124
+ * **Error Handling**: Use `try...except` to prevent crashes.
1125
+
1126
+ #### **Example 1: Data Aggregation with `after_agent_callback`**
1127
+ This callback runs after an agent, inspects the `session.events` to find structured data from tool calls (like `google_search` results), and saves it to state for later use.
1128
+
1129
+ ```python
1130
+ from google.adk.agents.callback_context import CallbackContext
1131
+
1132
+ def collect_research_sources_callback(callback_context: CallbackContext) -> None:
1133
+ """Collects and organizes web research sources from agent events."""
1134
+ session = callback_context._invocation_context.session
1135
+ # Get existing sources from state to append to them.
1136
+ url_to_short_id = callback_context.state.get("url_to_short_id", {})
1137
+ sources = callback_context.state.get("sources", {})
1138
+ id_counter = len(url_to_short_id) + 1
1139
+
1140
+ # Iterate through all events in the session to find grounding metadata.
1141
+ for event in session.events:
1142
+ if not (event.grounding_metadata and event.grounding_metadata.grounding_chunks):
1143
+ continue
1144
+ # ... logic to parse grounding_chunks and grounding_supports ...
1145
+ # (See full implementation in the original code snippet)
1146
+
1147
+ # Save the updated source map back to state.
1148
+ callback_context.state["url_to_short_id"] = url_to_short_id
1149
+ callback_context.state["sources"] = sources
1150
+
1151
+ # Used in an agent like this:
1152
+ # section_researcher = LlmAgent(..., after_agent_callback=collect_research_sources_callback)
1153
+ ```
1154
+
1155
+ #### **Example 2: Output Transformation with `after_agent_callback`**
1156
+ This callback takes an LLM's raw output (containing custom tags), uses Python to format it into markdown, and returns the modified content, overriding the original.
1157
+
1158
+ ```python
1159
+ import re
1160
+ from google.adk.agents.callback_context import CallbackContext
1161
+ from google.genai import types as genai_types
1162
+
1163
+ def citation_replacement_callback(callback_context: CallbackContext) -> genai_types.Content:
1164
+ """Replaces <cite> tags in a report with Markdown-formatted links."""
1165
+ # 1. Get raw report and sources from state.
1166
+ final_report = callback_context.state.get("final_cited_report", "")
1167
+ sources = callback_context.state.get("sources", {})
1168
+
1169
+ # 2. Define a replacer function for regex substitution.
1170
+ def tag_replacer(match: re.Match) -> str:
1171
+ short_id = match.group(1)
1172
+ if not (source_info := sources.get(short_id)):
1173
+ return "" # Remove invalid tags
1174
+ title = source_info.get("title", short_id)
1175
+ return f" [{title}]({source_info['url']})"
1176
+
1177
+ # 3. Use regex to find all <cite> tags and replace them.
1178
+ processed_report = re.sub(
1179
+ r'<cite\s+source\s*=\s*["\']?(src-\d+)["\']?\s*/>',
1180
+ tag_replacer,
1181
+ final_report,
1182
+ )
1183
+ processed_report = re.sub(r"\s+([.,;:])", r"\1", processed_report) # Fix spacing
1184
+
1185
+ # 4. Save the new version to state and return it to override the original agent output.
1186
+ callback_context.state["final_report_with_citations"] = processed_report
1187
+ return genai_types.Content(parts=[genai_types.Part(text=processed_report)])
1188
+
1189
+ # Used in an agent like this:
1190
+ # report_composer = LlmAgent(..., after_agent_callback=citation_replacement_callback)
1191
+ ```
1192
+
1193
+ ### 10.A. Global Control with Plugins
1194
+
1195
+ Plugins are stateful, reusable modules for implementing cross-cutting concerns that apply globally to all agents, tools, and model calls managed by a `Runner`. Unlike Callbacks which are configured per-agent, Plugins are registered once on the `Runner`.
1196
+
1197
+ * **Use Cases**: Ideal for universal logging, application-wide policy enforcement, global caching, and collecting metrics.
1198
+ * **Execution Order**: Plugin callbacks run **before** their corresponding agent-level callbacks. If a plugin callback returns a value, the agent-level callback is skipped.
1199
+ * **Defining a Plugin**: Inherit from `BasePlugin` and implement callback methods.
1200
+ ```python
1201
+ from google.adk.plugins import BasePlugin
1202
+ from google.adk.agents.callback_context import CallbackContext
1203
+ from google.adk.models.llm_request import LlmRequest
1204
+
1205
+ class AuditLoggingPlugin(BasePlugin):
1206
+ def __init__(self):
1207
+ super().__init__(name="audit_logger")
1208
+
1209
+ async def before_model_callback(self, callback_context: CallbackContext, llm_request: LlmRequest):
1210
+ # Log every prompt sent to any LLM
1211
+ print(f"[AUDIT] Agent {callback_context.agent_name} calling LLM with: {llm_request.contents[-1]}")
1212
+
1213
+ async def on_tool_error_callback(self, tool, error, **kwargs):
1214
+ # Global error handler for all tools
1215
+ print(f"[ALERT] Tool {tool.name} failed: {error}")
1216
+ # Optionally return a dict to suppress the exception and provide fallback
1217
+ return {"status": "error", "message": "An internal error occurred, handled by plugin."}
1218
+ ```
1219
+ * **Registering a Plugin**:
1220
+ ```python
1221
+ from google.adk.runners import Runner
1222
+ # runner = Runner(agent=root_agent, ..., plugins=[AuditLoggingPlugin()])
1223
+ ```
1224
+ * **Error Handling Callbacks**: Plugins support unique error hooks like `on_model_error_callback` and `on_tool_error_callback` for centralized error management.
1225
+ * **Limitation**: Plugins are not supported by the `adk web` interface.
1226
+
1227
+ ---
1228
+
1229
+ ## 11. Authentication for Tools
1230
+
1231
+ Enabling agents to securely access protected external resources.
1232
+
1233
+ ### 11.1 Core Concepts: `AuthScheme` & `AuthCredential`
1234
+
1235
+ * **`AuthScheme`**: Defines *how* an API expects authentication (e.g., `APIKey`, `HTTPBearer`, `OAuth2`, `OpenIdConnectWithConfig`).
1236
+ * **`AuthCredential`**: Holds *initial* information to *start* the auth process (e.g., API key value, OAuth client ID/secret).
1237
+
1238
+ ### 11.2 Interactive OAuth/OIDC Flows
1239
+
1240
+ When a tool requires user interaction (OAuth consent), ADK pauses and signals your `Agent Client` application.
1241
+
1242
+ 1. **Detect Auth Request**: `runner.run_async()` yields an event with a special `adk_request_credential` function call.
1243
+ 2. **Redirect User**: Extract `auth_uri` from `auth_config` in the event. Your client app redirects the user's browser to this `auth_uri` (appending `redirect_uri`).
1244
+ 3. **Handle Callback**: Your client app has a pre-registered `redirect_uri` to receive the user after authorization. It captures the full callback URL (containing `authorization_code`).
1245
+ 4. **Send Auth Result to ADK**: Your client prepares a `FunctionResponse` for `adk_request_credential`, setting `auth_config.exchanged_auth_credential.oauth2.auth_response_uri` to the captured callback URL.
1246
+ 5. **Resume Execution**: `runner.run_async()` is called again with this `FunctionResponse`. ADK performs the token exchange, stores the access token, and retries the original tool call.
1247
+
1248
+ ### 11.3 Custom Tool Authentication
1249
+
1250
+ If building a `FunctionTool` that needs authentication:
1251
+
1252
+ 1. **Check for Cached Creds**: `tool_context.state.get("my_token_cache_key")`.
1253
+ 2. **Check for Auth Response**: `tool_context.get_auth_response(my_auth_config)`.
1254
+ 3. **Initiate Auth**: If no creds, call `tool_context.request_credential(my_auth_config)` and return a pending status. This triggers the external flow.
1255
+ 4. **Cache Credentials**: After obtaining, store in `tool_context.state`.
1256
+ 5. **Make API Call**: Use the valid credentials (e.g., `google.oauth2.credentials.Credentials`).
1257
+
1258
+ ---
1259
+
1260
+ ## 12. Deployment Strategies
1261
+
1262
+ From local dev to production.
1263
+
1264
+ ### 12.1 Local Development & Testing (`adk web`, `adk run`, `adk api_server`)
1265
+
1266
+ * **`adk web`**: Launches a local web UI for interactive chat, session inspection, and visual tracing.
1267
+ ```bash
1268
+ adk web /path/to/your/project_root
1269
+ ```
1270
+ * **`adk run`**: Command-line interactive chat.
1271
+ ```bash
1272
+ adk run /path/to/your/agent_folder
1273
+ ```
1274
+ * **`adk api_server`**: Launches a local FastAPI server exposing `/run`, `/run_sse`, `/list-apps`, etc., for API testing with `curl` or client libraries.
1275
+ ```bash
1276
+ adk api_server /path/to/your/project_root
1277
+ ```
1278
+
1279
+ ### 12.2 Vertex AI Agent Engine
1280
+
1281
+ Fully managed, scalable service for ADK agents on Google Cloud.
1282
+
1283
+ * **Features**: Auto-scaling, session management, observability integration.
1284
+ * **ADK CLI**: `adk deploy agent_engine --project <id> --region <loc> ... /path/to/agent`
1285
+ * **Deployment**: Use `vertexai.agent_engines.create()`.
1286
+ ```python
1287
+ from vertexai.preview import reasoning_engines # or agent_engines directly in later versions
1288
+
1289
+ # Wrap your root_agent for deployment
1290
+ app_for_engine = reasoning_engines.AdkApp(agent=root_agent, enable_tracing=True)
1291
+
1292
+ # Deploy
1293
+ remote_app = agent_engines.create(
1294
+ agent_engine=app_for_engine,
1295
+ requirements=["google-cloud-aiplatform[adk,agent_engines]"],
1296
+ display_name="My Production Agent"
1297
+ )
1298
+ print(remote_app.resource_name) # projects/PROJECT_NUM/locations/REGION/reasoningEngines/ID
1299
+ ```
1300
+ * **Interaction**: Use `remote_app.stream_query()`, `create_session()`, etc.
1301
+
1302
+ ### 12.3 Cloud Run
1303
+
1304
+ Serverless container platform for custom web applications.
1305
+
1306
+ * **ADK CLI**: `adk deploy cloud_run --project <id> --region <loc> ... /path/to/agent`
1307
+ * **Deployment**:
1308
+ 1. Create a `Dockerfile` for your FastAPI app (using `google.adk.cli.fast_api.get_fast_api_app`).
1309
+ 2. Use `gcloud run deploy --source .`.
1310
+ 3. Alternatively, `adk deploy cloud_run` (simpler, opinionated).
1311
+ * **Example `main.py`**:
1312
+ ```python
1313
+ import os
1314
+ from fastapi import FastAPI
1315
+ from google.adk.cli.fast_api import get_fast_api_app
1316
+
1317
+ # Ensure your agent_folder (e.g., 'my_first_agent') is in the same directory as main.py
1318
+ app: FastAPI = get_fast_api_app(
1319
+ agents_dir=os.path.dirname(os.path.abspath(__file__)),
1320
+ session_service_uri="sqlite:///./sessions.db", # In-container SQLite, for simple cases
1321
+ # For production: use a persistent DB (Cloud SQL) or VertexAiSessionService
1322
+ allow_origins=["*"],
1323
+ web=True # Serve ADK UI
1324
+ )
1325
+ # uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8080))) # If running directly
1326
+ ```
1327
+
1328
+ ### 12.4 Google Kubernetes Engine (GKE)
1329
+
1330
+ For maximum control, run your containerized agent in a Kubernetes cluster.
1331
+
1332
+ * **ADK CLI**: `adk deploy gke --project <id> --cluster_name <name> ... /path/to/agent`
1333
+ * **Deployment**:
1334
+ 1. Build Docker image (`gcloud builds submit`).
1335
+ 2. Create Kubernetes Deployment and Service YAMLs.
1336
+ 3. Apply with `kubectl apply -f deployment.yaml`.
1337
+ 4. Configure Workload Identity for GCP permissions.
1338
+
1339
+ ### 12.5 CI/CD Integration
1340
+
1341
+ * Automate testing (`pytest`, `adk eval`) in CI.
1342
+ * Automate container builds and deployments (e.g., Cloud Build, GitHub Actions).
1343
+ * Use environment variables for secrets.
1344
+
1345
+ ---
1346
+
1347
+ ## 13. Evaluation and Safety
1348
+
1349
+ Critical for robust, production-ready agents.
1350
+
1351
+ ### 13.1 Agent Evaluation (`adk eval`)
1352
+
1353
+ Systematically assess agent performance using predefined test cases.
1354
+
1355
+ * **Evalset File (`.evalset.json`)**: Contains `eval_cases`, each with a `conversation` (user queries, expected tool calls, expected intermediate/final responses) and `session_input` (initial state).
1356
+ ```json
1357
+ {
1358
+ "eval_set_id": "weather_bot_eval",
1359
+ "eval_cases": [
1360
+ {
1361
+ "eval_id": "london_weather_query",
1362
+ "conversation": [
1363
+ {
1364
+ "user_content": {"parts": [{"text": "What's the weather in London?"}]},
1365
+ "final_response": {"parts": [{"text": "The weather in London is cloudy..."}]},
1366
+ "intermediate_data": {
1367
+ "tool_uses": [{"name": "get_weather", "args": {"city": "London"}}]
1368
+ }
1369
+ }
1370
+ ],
1371
+ "session_input": {"app_name": "weather_app", "user_id": "test_user", "state": {}}
1372
+ }
1373
+ ]
1374
+ }
1375
+ ```
1376
+ * **Running Evaluation**:
1377
+ * `adk web`: Interactive UI for creating/running eval cases.
1378
+ * `adk eval /path/to/agent_folder /path/to/evalset.json`: CLI execution.
1379
+ * `pytest`: Integrate `AgentEvaluator.evaluate()` into unit/integration tests.
1380
+ * **Metrics**: `tool_trajectory_avg_score` (tool calls match expected), `response_match_score` (final response similarity using ROUGE). Configurable via `test_config.json`.
1381
+
1382
+ ### 13.2 Safety & Guardrails
1383
+
1384
+ Multi-layered defense against harmful content, misalignment, and unsafe actions.
1385
+
1386
+ 1. **Identity and Authorization**:
1387
+ * **Agent-Auth**: Tool acts with the agent's service account (e.g., `Vertex AI User` role). Simple, but all users share access level. Logs needed for attribution.
1388
+ * **User-Auth**: Tool acts with the end-user's identity (via OAuth tokens). Reduces risk of abuse.
1389
+ 2. **In-Tool Guardrails**: Design tools defensively. Tools can read policies from `tool_context.state` (set deterministically by developer) and validate model-provided arguments before execution.
1390
+ ```python
1391
+ def execute_sql(query: str, tool_context: ToolContext) -> dict:
1392
+ policy = tool_context.state.get("user:sql_policy", {})
1393
+ if not policy.get("allow_writes", False) and ("INSERT" in query.upper() or "DELETE" in query.upper()):
1394
+ return {"status": "error", "message": "Policy: Write operations are not allowed."}
1395
+ # ... execute query ...
1396
+ ```
1397
+ 3. **Built-in Gemini Safety Features**:
1398
+ * **Content Safety Filters**: Automatically block harmful content (CSAM, PII, hate speech, etc.). Configurable thresholds.
1399
+ * **System Instructions**: Guide model behavior, define prohibited topics, brand tone, disclaimers.
1400
+ 4. **Model and Tool Callbacks (LLM as a Guardrail)**: Use callbacks to inspect inputs/outputs.
1401
+ * `before_model_callback`: Intercept `LlmRequest` before it hits the LLM. Block (return `LlmResponse`) or modify.
1402
+ * `before_tool_callback`: Intercept tool calls (name, args) before execution. Block (return `dict`) or modify.
1403
+ * **LLM-based Safety**: Use a cheap/fast LLM (e.g., Gemini Flash) in a callback to classify input/output safety.
1404
+ ```python
1405
+ def safety_checker_callback(context: CallbackContext, llm_request: LlmRequest) -> Optional[LlmResponse]:
1406
+ # Use a separate, small LLM to classify safety
1407
+ safety_llm_agent = Agent(name="SafetyChecker", model="gemini-2.5-flash-001", instruction="Classify input as 'safe' or 'unsafe'. Output ONLY the word.")
1408
+ # Run the safety agent (might need a new runner instance or direct model call)
1409
+ # For simplicity, a mock:
1410
+ user_input = llm_request.contents[-1].parts[0].text
1411
+ if "dangerous_phrase" in user_input.lower():
1412
+ context.state["safety_violation"] = True
1413
+ return LlmResponse(content=genai_types.Content(parts=[genai_types.Part(text="I cannot process this request due to safety concerns.")]))
1414
+ return None
1415
+ ```
1416
+ 5. **Sandboxed Code Execution**:
1417
+ * `BuiltInCodeExecutor`: Uses secure, sandboxed execution environments.
1418
+ * Vertex AI Code Interpreter Extension.
1419
+ * If custom, ensure hermetic environments (no network, isolated).
1420
+ 6. **Network Controls & VPC-SC**: Confine agent activity within secure perimeters (VPC Service Controls) to prevent data exfiltration.
1421
+ 7. **Output Escaping in UIs**: Always properly escape LLM-generated content in web UIs to prevent XSS attacks and indirect prompt injections.
1422
+
1423
+ **Grounding**: A key safety and reliability feature that connects agent responses to verifiable information.
1424
+ * **Mechanism**: Uses tools like `google_search` or `VertexAiSearchTool` to fetch real-time or private data.
1425
+ * **Benefit**: Reduces model hallucination by basing responses on retrieved facts.
1426
+ * **Requirement**: When using `google_search`, your application UI **must** display the provided search suggestions and citations to comply with terms of service.
1427
+
1428
+ ---
1429
+
1430
+ ## 14. Debugging, Logging & Observability
1431
+
1432
+ * **`adk web` UI**: Best first step. Provides visual trace, session history, and state inspection.
1433
+ * **Event Stream Logging**: Iterate `runner.run_async()` events and print relevant fields.
1434
+ ```python
1435
+ async for event in runner.run_async(...):
1436
+ print(f"[{event.author}] Event ID: {event.id}, Invocation: {event.invocation_id}")
1437
+ if event.content and event.content.parts:
1438
+ if event.content.parts[0].text:
1439
+ print(f" Text: {event.content.parts[0].text[:100]}...")
1440
+ if event.get_function_calls():
1441
+ print(f" Tool Call: {event.get_function_calls()[0].name} with {event.get_function_calls()[0].args}")
1442
+ if event.get_function_responses():
1443
+ print(f" Tool Response: {event.get_function_responses()[0].response}")
1444
+ if event.actions:
1445
+ if event.actions.state_delta:
1446
+ print(f" State Delta: {event.actions.state_delta}")
1447
+ if event.actions.transfer_to_agent:
1448
+ print(f" TRANSFER TO: {event.actions.transfer_to_agent}")
1449
+ if event.error_message:
1450
+ print(f" ERROR: {event.error_message}")
1451
+ ```
1452
+ * **Tool/Callback `print` statements**: Simple logging directly within your functions.
1453
+ * **Logging**: Use Python's standard `logging` module. Control verbosity with `adk web --log_level DEBUG` or `adk web -v`.
1454
+ * **One-Line Observability Integrations**: ADK has native hooks for popular tracing platforms.
1455
+ * **AgentOps**:
1456
+ ```python
1457
+ import agentops
1458
+ agentops.init(api_key="...") # Automatically instruments ADK agents
1459
+ ```
1460
+ * **Arize Phoenix**:
1461
+ ```python
1462
+ from phoenix.otel import register
1463
+ register(project_name="my_agent", auto_instrument=True)
1464
+ ```
1465
+ * **Google Cloud Trace**: Enable via flag during deployment: `adk deploy [cloud_run|agent_engine] --trace_to_cloud ...`
1466
+ * **Session History (`session.events`)**: Persisted for detailed post-mortem analysis.
1467
+
1468
+ ---
1469
+
1470
+ ## 15. Streaming & Advanced I/O
1471
+
1472
+ ADK supports real-time, bidirectional communication for interactive experiences like live voice conversations.
1473
+
1474
+ #### Bidirectional Streaming Loop (`run_live`)
1475
+ For real-time voice/video, use `run_live` with a `LiveRequestQueue`. This enables low-latency, two-way communication where the user can interrupt the agent.
1476
+
1477
+ ```python
1478
+ import asyncio
1479
+ from google.adk.agents import LiveRequestQueue
1480
+ from google.adk.agents.run_config import RunConfig
1481
+
1482
+ async def start_streaming_session(runner, session, user_id):
1483
+ # 1. Configure modalities (e.g., AUDIO output for voice agents)
1484
+ run_config = RunConfig(response_modalities=["AUDIO"])
1485
+
1486
+ # 2. Create input queue for client data (audio chunks, text)
1487
+ live_queue = LiveRequestQueue()
1488
+
1489
+ # 3. Start the bidirectional stream
1490
+ live_events = runner.run_live(
1491
+ session=session,
1492
+ live_request_queue=live_queue,
1493
+ run_config=run_config
1494
+ )
1495
+
1496
+ # 4. Process events (simplified loop)
1497
+ try:
1498
+ async for event in live_events:
1499
+ # Handle agent output (text or audio bytes)
1500
+ if event.content and event.content.parts:
1501
+ part = event.content.parts[0]
1502
+ if part.inline_data and part.inline_data.mime_type.startswith("audio/"):
1503
+ # Send audio bytes to client
1504
+ await client.send_audio(part.inline_data.data)
1505
+ elif part.text:
1506
+ # Send text to client
1507
+ await client.send_text(part.text)
1508
+
1509
+ # Handle turn signals
1510
+ if event.turn_complete:
1511
+ pass # Signal client that agent finished speaking
1512
+ finally:
1513
+ live_queue.close()
1514
+
1515
+ # To send user input to agent during the stream:
1516
+ # await live_queue.send_content(Content(role="user", parts=[Part(text="Hello")]))
1517
+ # await live_queue.send_realtime(Blob(mime_type="audio/pcm", data=audio_bytes))
1518
+ ```
1519
+
1520
+ * **Streaming Tools**: A special type of `FunctionTool` that can stream intermediate results back to the agent.
1521
+ * **Definition**: Must be an `async` function with a return type of `AsyncGenerator`.
1522
+ ```python
1523
+ from typing import AsyncGenerator
1524
+
1525
+ async def monitor_stock_price(symbol: str) -> AsyncGenerator[str, None]:
1526
+ """Yields stock price updates as they occur."""
1527
+ while True:
1528
+ price = await get_live_price(symbol)
1529
+ yield f"Update for {symbol}: ${price}"
1530
+ await asyncio.sleep(5)
1531
+ ```
1532
+
1533
+ * **Advanced I/O Modalities**: ADK (especially with Gemini Live API models) supports richer interactions.
1534
+ * **Audio**: Input via `Blob(mime_type="audio/pcm", data=bytes)`, Output via `genai_types.SpeechConfig` in `RunConfig`.
1535
+ * **Vision (Images/Video)**: Input via `Blob(mime_type="image/jpeg", data=bytes)` or `Blob(mime_type="video/mp4", data=bytes)`. Models like `gemini-2.5-flash-exp` can process these.
1536
+ * **Multimodal Input in `Content`**:
1537
+ ```python
1538
+ multimodal_content = genai_types.Content(
1539
+ parts=[
1540
+ genai_types.Part(text="Describe this image:"),
1541
+ genai_types.Part(inline_data=genai_types.Blob(mime_type="image/jpeg", data=image_bytes))
1542
+ ]
1543
+ )
1544
+ ```
1545
+
1546
+ ---
1547
+
1548
+ ## 16. Performance Optimization
1549
+
1550
+ * **Model Selection**: Choose the smallest model that meets requirements (e.g., `gemini-2.5-flash` for simple tasks).
1551
+ * **Instruction Prompt Engineering**: Concise, clear instructions reduce tokens and improve accuracy.
1552
+ * **Tool Use Optimization**:
1553
+ * Design efficient tools (fast API calls, optimize database queries).
1554
+ * Cache tool results (e.g., using `before_tool_callback` or `tool_context.state`).
1555
+ * **State Management**: Store only necessary data in state to avoid large context windows.
1556
+ * **`include_contents='none'`**: For stateless utility agents, saves LLM context window.
1557
+ * **Parallelization**: Use `ParallelAgent` for independent tasks.
1558
+ * **Streaming**: Use `StreamingMode.SSE` or `BIDI` for perceived latency reduction.
1559
+ * **`max_llm_calls`**: Limit LLM calls to prevent runaway agents and control costs.
1560
+
1561
+ ---
1562
+
1563
+ ## 17. General Best Practices & Common Pitfalls
1564
+
1565
+ * **Start Simple**: Begin with `LlmAgent`, mock tools, and `InMemorySessionService`. Gradually add complexity.
1566
+ * **Iterative Development**: Build small features, test, debug, refine.
1567
+ * **Modular Design**: Use agents and tools to encapsulate logic.
1568
+ * **Clear Naming**: Descriptive names for agents, tools, state keys.
1569
+ * **Error Handling**: Implement robust `try...except` blocks in tools and callbacks. Guide LLMs on how to handle tool errors.
1570
+ * **Testing**: Write unit tests for tools/callbacks, integration tests for agent flows (`pytest`, `adk eval`).
1571
+ * **Dependency Management**: Use virtual environments (`venv`) and `requirements.txt`.
1572
+ * **Secrets Management**: Never hardcode API keys. Use `.env` for local dev, environment variables or secret managers (Google Cloud Secret Manager) for production.
1573
+ * **Avoid Infinite Loops**: Especially with `LoopAgent` or complex LLM tool-calling chains. Use `max_iterations`, `max_llm_calls`, and strong instructions.
1574
+ * **Handle `None` & `Optional`**: Always check for `None` or `Optional` values when accessing nested properties (e.g., `event.content and event.content.parts and event.content.parts[0].text`).
1575
+ * **Immutability of Events**: Events are immutable records. If you need to change something *before* it's processed, do so in a `before_*` callback and return a *new* modified object.
1576
+ * **Understand `output_key` vs. direct `state` writes**: `output_key` is for the agent's *final conversational* output. Direct `tool_context.state['key'] = value` is for *any other* data you want to save.
1577
+ * **Example Agents**: Find practical examples and reference implementations in the [ADK Samples repository](https://github.com/google/adk-samples).
1578
+
1579
+
1580
+ ### Testing the output of an agent
1581
+
1582
+ The following script demonstrates how to programmatically test an agent's output. This approach is extremely useful when an LLM or coding agent needs to interact with a work-in-progress agent, as well as for automated testing, debugging, or when you need to integrate agent execution into other workflows:
1583
+ ```python
1584
+ import asyncio
1585
+
1586
+ from google.adk.runners import Runner
1587
+ from google.adk.sessions import InMemorySessionService
1588
+ from {{cookiecutter.agent_directory}}.agent import root_agent
1589
+ from google.genai import types as genai_types
1590
+
1591
+
1592
+ async def main():
1593
+ """Runs the agent with a sample query."""
1594
+ session_service = InMemorySessionService()
1595
+ await session_service.create_session(
1596
+ app_name="{{cookiecutter.agent_directory}}", user_id="test_user", session_id="test_session"
1597
+ )
1598
+ runner = Runner(
1599
+ agent=root_agent, app_name="{{cookiecutter.agent_directory}}", session_service=session_service
1600
+ )
1601
+ query = "I want a recipe for pancakes"
1602
+ async for event in runner.run_async(
1603
+ user_id="test_user",
1604
+ session_id="test_session",
1605
+ new_message=genai_types.Content(
1606
+ role="user",
1607
+ parts=[genai_types.Part.from_text(text=query)]
1608
+ ),
1609
+ ):
1610
+ if event.is_final_response():
1611
+ print(event.content.parts[0].text)
1612
+
1613
+
1614
+ if __name__ == "__main__":
1615
+ asyncio.run(main())
1616
+ ```
1617
+
1618
+ ---
1619
+
1620
+ ## 18. Official API & CLI References
1621
+
1622
+ For detailed specifications of all classes, methods, and commands, refer to the official reference documentation.
1623
+
1624
+ * [Python API Reference](https://github.com/google/adk-docs/tree/main/docs/api-reference/python)
1625
+ * [Java API Reference](https://github.com/google/adk-docs/tree/main/docs/api-reference/java)
1626
+ * [CLI Reference](https://github.com/google/adk-docs/tree/main/docs/api-reference/cli)
1627
+ * [REST API Reference](https://github.com/google/adk-docs/tree/main/docs/api-reference/rest)
1628
+ * [Agent Config YAML Reference](https://github.com/google/adk-docs/tree/main/docs/api-reference/agentconfig)