Compare commits

...

115 Commits

Author SHA1 Message Date
Wei Sun (Jack) 5b999ed6fd chore: Uses pydantic Field for Agent configs, so that the generated AgentConfig.json json schema can carry field description
PiperOrigin-RevId: 797094012
2025-08-19 18:03:47 -07:00
George Weale bb8ebd15f9 chore: Update openai dependency version, based on correct OPENAI release
Bump the minimum required version of the `openai` package to `>=1.100.2` for compatibility with LiteLLM.

PiperOrigin-RevId: 797027214
2025-08-19 14:43:58 -07:00
Google Team Member fef5318a22 docs: add contributing bigtable sample
PiperOrigin-RevId: 797014958
2025-08-19 14:08:55 -07:00
Xiang (Sean) Zhou 018db79d13 fix: Lazy load VertexAiCodeExecutor and ContainerCodeExecutor
VertexAiCodeExecutor and ContainerCodeExecutor request additional dependencies, lazy load them so that when users import other names, they won't get impacted if they don't had those additional dependencies installed.
 Original codes swallow the exception and log a debug log is wrong and awkward, should follow the same style as what we did in https://github.com/google/adk-python/blob/main/src/google/adk/tools/retrieval/__init__.py

PiperOrigin-RevId: 796969332
2025-08-19 12:06:59 -07:00
Google Team Member 77ed1f5f15 feat: Add setdefault method to the ADK State object
This makes the ADK state more pythonic, with the State API being more like a python dict.

PiperOrigin-RevId: 796767559
2025-08-19 01:45:33 -07:00
George Weale 4afc9b2f33 feat: Add env var to suppress experimental warnings
Checked with local wheel and worked as intended. The harness shows suppression works: 0 warnings for all true-like values.

This CL adds ADK_DISABLE_EXPERIMENTAL_WARNING to let the users to suppress warning messages from features decorated with @experimental.

Previously, using experimental features would always trigger a UserWarning. This change creates a way to disable these warnings, which can be good to stop flooding logs.

The warning is suppressed if ADK_DISABLE_EXPERIMENTAL_WARNING is set to a truthy value such as "true", "1", "yes", or "on" (case-insensitive).

Added unit tests to make sure:
Warning suppression for functions and classes when the env var is set.
Case-insensitivity and various truthy values for the env var.
Loading the env var from a .env file.

PiperOrigin-RevId: 796649404
2025-08-18 17:59:13 -07:00
Xuan Yang f8fd6a4f09 chore: add the missing license header for core_callback_config init file
PiperOrigin-RevId: 796641146
2025-08-18 17:29:09 -07:00
Google Team Member a953807cce feat: add Bigtable tools
These tools support basic operations to interact with Bigtable table metadata and query results.

PiperOrigin-RevId: 796571736
2025-08-18 14:17:08 -07:00
Google Team Member fa64545a9d fix: Fix the path for agent card in A2A demo
`AGENT_CARD_WELL_KNOWN_PATH` already contains a leading slash so is not needed in the `agent_card` URL.

PiperOrigin-RevId: 796543208
2025-08-18 13:04:38 -07:00
George Weale 004a0a0f2d fix: litellm-test due to breaking change in dep library of extension extra
PiperOrigin-RevId: 796543071
2025-08-18 13:03:04 -07:00
Google Team Member a117cf0af3 fix: Fix the path for agent card in A2A demo
`AGENT_CARD_WELL_KNOWN_PATH` already contains a leading slash so is not needed in the `agent_card` URL.

PiperOrigin-RevId: 796537920
2025-08-18 12:49:20 -07:00
Wei Sun (Jack) 1fd58cb363 chore(config): Creates yaml_utils.py in utils to allow adk dump yaml in the same style
PiperOrigin-RevId: 796531710
2025-08-18 12:34:09 -07:00
Shangjie Chen f03f167779 chore: Return explict None type for DELETE endpoints
The HTTP response code will become 204 No Content instead of 200.

PiperOrigin-RevId: 796123628
2025-08-17 09:58:40 -07:00
Liang Wu 43f302ce1a chore(config): Add _config suffix to all yaml-based agent examples
Also expand agent folder name to full spelling, e.g. ma --> multi_agent

PiperOrigin-RevId: 795926902
2025-08-16 16:10:43 -07:00
Shangjie Chen ecaa7b4c98 chore: Rename run related method and request to align with the conventions
PiperOrigin-RevId: 795660109
2025-08-15 16:48:01 -07:00
Xiang (Sean) Zhou 279e4fedd0 fix: Using base event's invocation id when merge multiple function response event
fix https://github.com/google/adk-python/issues/1531

PiperOrigin-RevId: 795657473
2025-08-15 16:38:15 -07:00
Liang Wu b3b70035c4 feat: support deploying config agent to Agent Engine in CLI
Both pure config and config with code are successfully deployed.

PiperOrigin-RevId: 795645102
2025-08-15 16:01:50 -07:00
Dan Liebling 22f34e9d2c fix: avoid crash when there is no candidates_token_count, which is Optional
PiperOrigin-RevId: 795643665
2025-08-15 15:56:05 -07:00
Liang Wu ba6e85eb3f docs(config): fix core_callback example
PiperOrigin-RevId: 795619488
2025-08-15 14:44:53 -07:00
Terrence Ryan c84350345a feat: adding build image to deploy cloud_run options (#2502)
* feat: adding build image to deploy cloud_run options

Gives the ability for a user to set the build image for the deployment step to Cloud Run.  Currently it is hard coded to python:3.11-slim, and this is still the default, but this allows that value to be overriden.

* fix: applied formatting scripts

testing:

Added tests to ensure the behavior of the cli remains consistent with when used or omitted.

* chore: next time run the formatter before you commit.

---------

Co-authored-by: Ivan Cheung <ivans.mailbox@gmail.com>
2025-08-15 11:36:44 -07:00
Shangjie Chen a2b7909fc3 fix: Fix the packaging version comparison logic in adk cli
Resolves https://github.com/google/adk-python/issues/2503

PiperOrigin-RevId: 795519711
2025-08-15 10:16:45 -07:00
Google Team Member b66054dd0d fix: Add Spanner admin scope to Spanner tool default Oauth scopes
PiperOrigin-RevId: 795519063
2025-08-15 10:15:15 -07:00
Wei Sun (Jack) 8a9a271141 fix(config): Fixes SequentialAgent.config_type type hint
Without ClassVar, it will cause pydantic to generate warning.

PiperOrigin-RevId: 795518646
2025-08-15 10:13:39 -07:00
Xiang (Sean) Zhou a2832d5ac7 feat: Support custom tool_name_prefix in auto-generated GoogleApiToolset
PiperOrigin-RevId: 795508179
2025-08-15 09:44:16 -07:00
Wei Sun (Jack) 1328e6ef62 docs(config): Adds a minimal sample to demo how to use Agent Config to create a multi-agent setup
PiperOrigin-RevId: 795501478
2025-08-15 09:22:52 -07:00
Wei Sun (Jack) cd357bf5ae fix: Fixes the host in the ansi bracket of adk web
localhost cannot always open Web UI, since we only bind 127.0.0.1.

PiperOrigin-RevId: 795484904
2025-08-15 08:26:01 -07:00
Google Team Member a27927dc81 fix: Add spanner tool name prefix
PiperOrigin-RevId: 795339631
2025-08-14 22:14:18 -07:00
Liang Wu 6c217bad82 chore: update models in samples/ folder to be gemini 2.0+
Gemini 1.5 is obsolete and not accessible to new projects.

PiperOrigin-RevId: 795330977
2025-08-14 21:36:23 -07:00
Xuan Yang c32cb6eef9 chore: remove the "one commit" requirement from the contributing guide
PiperOrigin-RevId: 795217167
2025-08-14 15:13:19 -07:00
Hangfei Lin 80052700f6 chore: Bump version to 1.11.0
release for 1.11.0

PiperOrigin-RevId: 795195869
2025-08-14 14:19:15 -07:00
Google Team Member c8059428a2 chore: add contributing spanner sample
PiperOrigin-RevId: 795154839
2025-08-14 12:41:28 -07:00
Xuan Yang e63e2a7106 fix: add the missing required tool parameters for Anthropic models
Fixes #1692

PiperOrigin-RevId: 795125801
2025-08-14 11:31:00 -07:00
Wei Sun (Jack) 9ba8eec220 feat(tracing): Adds more OpenTelemetry convention attributes: gen_ai.request.max_tokens, gen_ai.request.top_p and gen_ai.response.finish_reasons
Fixes #1234

PiperOrigin-RevId: 795082815
2025-08-14 09:52:50 -07:00
Kacper Jawoszek 9cfe43334a fix: Uncomment OTel tracing in base_llm_flow.py
It was mistakenly commented out in the previous change.

PiperOrigin-RevId: 795048873
2025-08-14 08:20:07 -07:00
Xiang (Sean) Zhou 52284b1bae fix: A2A RPC URL got overriden by host and port param of adk api server
PiperOrigin-RevId: 794708721
2025-08-13 13:20:26 -07:00
George Weale a74d3344bc chore: Added upper version bounds to dependencies in "pyproject.toml"
This change keeps dependencies to their major versions, but for the pre 1.0.0 releases pinned to minor releases as they could have breaking changes.

PyYAML: Version 7.0 is in development and could have breaking changes

absolufy-imports: The package is archived and no longer maintained.

anyio: Follows SemVer, so version 5.0 could have breaking changes.

authlib: Follows a SemVer-like pattern, so version 2.0 could have breaking changes.

click: A mature library, version 9.0 is the expected boundary for breaking changes.

fastapi: As a pre-1.0 library, the next minor release could have breaking changes.

google-api-python-client: Although in maintenance, version 3.0 could still have breaking changes.

google-cloud-aiplatform: Follows SemVer, so breaking changes are expected in version 2.0.

google-cloud-secret-manager: A stable Google library, version 3.0 could lead to breaking changes.

google-cloud-speech: A stable Google library, version 3.0 could lead to breaking changes.

google-cloud-storage: A stable Google library.

google-genai: As an official Google SDK, version 2.0 is the expected boundary for breaking changes.

graphviz: As a pre-1.0 library, the next minor release could have breaking changes.

mcp: As an SDK, version 2.0 is the boundary for potential breaking changes.

opentelemetry-api: Follows SemVer; version 2.0 could have breaking changes.

opentelemetry-exporter-gcp-trace: It's tied to the v1 OpenTelemetry API, so version 2.0 would likely be a breaking change.

opentelemetry-sdk: It's coupled to the v1 API, so version 2.0 would likely be a breaking change.

pydantic: This stops upgrades to the incompatible version 3.0 after its major 2.0 rewrite.

python-dateutil: Follows to SemVer, making version 3.0 the boundary for potential breaking changes.

python-dotenv: Locks to stable version 1.0 major release.

requests: As a more mature library, version 3.0 is boundary for breaking changes.

sqlalchemy: This locks the dependency to the stable version 2.0 API after its major rewrite.

starlette: As a pre-1.0 library, the next minor release could have breaking changes.

tenacity: This is a mature library, version 9.0 is boundary for breaking changes.

typing-extensions: Major versions are tied to large typing changes in Python itself.

tzlocal: The library has a history of introducing breaking API changes between major versions.

uvicorn: As a pre-1.0 library, the next minor release could have breaking changes.

watchdog: As a stable library, version 7.0 could have breaking changes.

websockets: Follows SemVer, so version 16.0 is the boundary for breaking changes.
PiperOrigin-RevId: 794677571
2025-08-13 12:03:47 -07:00
George Weale ddf2e2194b chore: Update python-version in .github/workflows/python-unit-tests.yml to ["3.9", "3.10", "3.11", "3.12", "3.13"]
Verified with uv on Python 3.12 and 3.13 using the same ignores as CI.
3.12:
uv python install 3.12 && uv venv --python 3.12 .venv && source .venv/bin/activate
uv sync --extra test --extra eval --extra a2a
python -m pytest tests/unittests --ignore=tests/unittests/artifacts/test_artifact_service.py --ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
3.13: repeated the above with 3.13 (separate env)
Result: All unit tests passed

PiperOrigin-RevId: 794669437
2025-08-13 11:43:24 -07:00
Kacper Jawoszek a30c63c593 fix: aclose all async generators to fix OTel tracing context
See https://github.com/google/adk-python/issues/1670#issuecomment-3115891100

PiperOrigin-RevId: 794659547
2025-08-13 11:18:26 -07:00
Wei Sun (Jack) c5af44cfc0 docs(config): Fixes tool_functions, which is a config-based sample for using tools
PiperOrigin-RevId: 794652291
2025-08-13 11:01:52 -07:00
Google Team Member c52f956433 chore: Update comment to reference "Streamable HTTP Client"
Corrects a typo in the `StreamableHTTPConnectionParams` docstring, changing "SSE" to "Streamable HTTP" to accurately reflect the referenced client.

PiperOrigin-RevId: 794424727
2025-08-12 23:45:23 -07:00
Xuan Yang 585141e0b7 fix: Use PreciseTimestamp for create and update time in database session service to improve precision
PiperOrigin-RevId: 794422113
2025-08-12 23:36:53 -07:00
Google Team Member 114db93d70 ADK changes
PiperOrigin-RevId: 794403729
2025-08-12 22:29:23 -07:00
Hangfei Lin e2518dc371 fix: Ignore AsyncGenerator return types in function declarations
For Vertex model backend, we send response back. This doesn't work for streaming tools that the return type is AsyncGenerator. So the fix here is to ignore the return type when it's AsyncGenerator.

We can't distinguish streaming vs non-streaming tool with AsyncGenerator though as LiveRequestQueue is optional in streaming tool.

Adds an `ignore_response` option to `build_function_declaration` to skip including the return type in the function declaration. This is enabled for tools that return `AsyncGenerator`, as the model does not yet support understanding these return types, while streaming tools can still handle them. Also, removes redundant return statements in `_get_mandatory_params`.

PiperOrigin-RevId: 794392846
2025-08-12 21:45:52 -07:00
Xiang (Sean) Zhou 8c65967cdc fix: Make all subclass of BaseToolset to call parent constructor
So that all member field are created / initialized in the base toolset.

PiperOrigin-RevId: 794388671
2025-08-12 21:32:24 -07:00
Xiang (Sean) Zhou ebd726f1f5 feat: Support adding prefix to tool names returned by toolset
This is to address the name conflict issue of tools returned by different toolset. Mainly it's to give each toolset a namespace.

We have a flag `add_tool_name_prefix` to decide whether to apply this behavior
We have a `tool_name_prefix` to let client specify a custom prefix, if not set , toolset name will be used as prefix.

PiperOrigin-RevId: 794306796
2025-08-12 16:17:53 -07:00
Goldy 54680edf3c fix: path parameter extraction for complex Google API endpoints
Merge https://github.com/google/adk-python/pull/1815

fix: path parameter extraction for complex Google API endpoints

- Fix GoogleApiToOpenApiConverter to handle path parameters in complex endpoints like /v1/documents/{documentId}:batchUpdate
- Use Google Discovery Document 'location' field
- Add comprehensive test suite for Google Docs batchUpdate functionality
- Verify parameter location handling for complex endpoint patterns
- Test schema validation for BatchUpdateDocumentRequest/Response

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1815 from goldylocks87:fix-issue-1814-path-parameter-extraction af5508ec6975b1ccbc34931a0041e422ee259c16
PiperOrigin-RevId: 794301898
2025-08-12 16:02:45 -07:00
Shangjie Chen bb3735c9ca chore: Remove logging that contains full event data from DatabaseSessionService
Resolves https://github.com/google/adk-python/issues/2153

PiperOrigin-RevId: 794288546
2025-08-12 15:19:52 -07:00
Xuan Yang a09a5e67aa chore: add the missing env variables in discussion_answering.yml
PiperOrigin-RevId: 794285985
2025-08-12 15:12:03 -07:00
Google Team Member 7e0880869b feat: Expose print_detailed_results param to AgentEvaluator.evaluate
Currently `print_detailed_results` is available only in `AgentEvaluator.evaluate_eval_set` while the adk-samples data science agent uses `AgentEvaluator.evaluate` https://github.com/google/adk-samples/blob/c230c3ddc16a3f9fc7edff409b567bdd65ebd9da/python/agents/data-science/eval/test_eval.py#L32.

PiperOrigin-RevId: 794262781
2025-08-12 14:07:17 -07:00
Google Team Member 1fc8d20ae8 feat: add Spanner first-party toolset (breaking change to BigQueryTool, consolidating into generic GoogleTool)
Spanner toolset support basic operations to interact with Spanner table metadata and query results.

Consolidate BigQueryTool into generic GoogleTool, so that BigQueryToolset and SpannerToolset can share.

PiperOrigin-RevId: 794259782
2025-08-12 13:59:37 -07:00
Google Team Member 10e3dfab1a feat: remove load_dotenv() in feature_decorator.py
PiperOrigin-RevId: 794249376
2025-08-12 13:35:49 -07:00
Xuan Yang 5fba1963c3 chore: add Gemini API docs as a new datastore for the ADK Answering Agent
PiperOrigin-RevId: 794247007
2025-08-12 13:30:00 -07:00
Xuan Yang 7d2cb654f0 chore: add the missing license header for some sample agents' files
PiperOrigin-RevId: 794165986
2025-08-12 10:24:36 -07:00
Xiang (Sean) Zhou 88f759a941 fix: docstring concatenation in 3.13
The issue was caused by a breaking change in Python 3.13's inspect.cleandoc() function that made it more conservative about whitespace handling:

Root Cause:

- Python 3.12-: inspect.cleandoc() used line.lstrip() - strips all whitespace (spaces, tabs, etc.)
- Python 3.13+: inspect.cleandoc() uses line.lstrip(' ') - strips only space characters

PiperOrigin-RevId: 793921360
2025-08-11 21:26:25 -07:00
Wei Sun (Jack) e295feb4c6 docs: Add workflow_triage sample for multi-agent request orchestration
Demonstrates intelligent triage system with root planning agent and parallel
execution agents.

Use session state to store the execution plan and coordinate with other specialized agents.

Check out README.md for more details.

PiperOrigin-RevId: 793884758
2025-08-11 19:05:53 -07:00
Liang Wu d87feb8ddb docs(config): add examples for config agents
PiperOrigin-RevId: 793871778
2025-08-11 18:09:55 -07:00
Shangjie Chen 88114d7c73 chore: Add docstring to clarify the behavior of preload memory tool
PiperOrigin-RevId: 793840979
2025-08-11 16:33:49 -07:00
Xiang (Sean) Zhou d0b3b5d857 chore: add experimental messages for a2a related API
PiperOrigin-RevId: 793812544
2025-08-11 15:09:08 -07:00
Wei Sun (Jack) d674178a05 chore: Fixes generate_image sample
PiperOrigin-RevId: 793725452
2025-08-11 11:15:06 -07:00
Wei Sun (Jack) dc26aad663 docs: Adds pypi badge to README.md
PiperOrigin-RevId: 793713600
2025-08-11 10:47:57 -07:00
Shangjie Chen 7f12387eb1 chore: Make all FastAPI endpoints async
PiperOrigin-RevId: 792886431
2025-08-08 21:58:34 -07:00
Eugen-Bleck 8f937b5175 docs: update StreamableHTTPConnectionParams docstring to remove SSE references (#1456)
Co-authored-by: Terrence Ryan <tpryan@google.com>
Fixes: google/adk-docs#475
2025-08-08 20:42:43 -07:00
Shangjie Chen c323de5c69 chore: Group FastAPI endpoints with tags
PiperOrigin-RevId: 792816574
2025-08-08 17:20:46 -07:00
Liang Wu b4f1ebea31 chore(config): replace @working_in_progress with @experimental for config agent feature
PiperOrigin-RevId: 792803076
2025-08-08 16:32:50 -07:00
Google Team Member 944e39ec2a chore: allow implementations to skip defining a close method on Toolset
PiperOrigin-RevId: 792760747
2025-08-08 14:22:17 -07:00
Xiang (Sean) Zhou 9478a31bf2 fix: Lazy load retrieval tools and prompt users to install extensions if import failed
PiperOrigin-RevId: 792701550
2025-08-08 11:37:47 -07:00
Xiang (Sean) Zhou f2005a2026 chore: Add sample agent to test support of output_schema and tools at the same time for gemini model
PiperOrigin-RevId: 792694074
2025-08-08 11:16:31 -07:00
Xiang (Sean) Zhou af635674b5 feat: Support both output_schema and tools at the same time in LlmAgent
1. Allow developers to specify output schema and tools together.
2. If both are specified, do the following:
  2.1 Do not set output schema on the model config
  2.2 Add a special tool called set_model_response(result)
  2.3 `result` has the same schema as the requested output_schema
  2.4 Instruct the model to use set_model_response() to output its final result, rather than output text directly.
  2.5 When the set_model_response() is called, ADK will extract its content and put it in a text part, so the client would treat it as the model response.

PiperOrigin-RevId: 792686011
2025-08-08 10:55:22 -07:00
Xiang (Sean) Zhou b4ce3b12d1 fix: incorrect logic in LlmRequest.append_tools and make BaseTool to call it
PiperOrigin-RevId: 792642882
2025-08-08 08:53:57 -07:00
Google Team Member 98a5730115 fix: incorrect logic in LlmRequest.append_tools and make BaseTool to call it
PiperOrigin-RevId: 792518526
2025-08-08 01:29:47 -07:00
Xiang (Sean) Zhou 4b2a8e3186 fix: incorrect logic in LlmRequest.append_tools and make BaseTool to call it
PiperOrigin-RevId: 792474565
2025-08-07 22:53:54 -07:00
Sam Hatfield e4d54b66b3 fix: Creates an InMemoryMemoryService within the EvaluationGenerator
Merge https://github.com/google/adk-python/pull/2263

Addresses #2084

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2263 from sjhatfield:main 8d6fca48437f151c34b2766ea4813a777bafcabd
PiperOrigin-RevId: 792336301
2025-08-07 15:40:42 -07:00
Xuan Yang 5900273455 chore: add Github workflow config for uploading ADK docs to knowledge store
PiperOrigin-RevId: 792272706
2025-08-07 12:52:28 -07:00
Xuan Yang b5a8bad170 chore: update ADK Answering agent to reference doc site instead of adk-docs repo
PiperOrigin-RevId: 792259386
2025-08-07 12:17:09 -07:00
Shangjie Chen 20c30d5819 chore: Bump version number to 1.10.0
PiperOrigin-RevId: 792206610
2025-08-07 10:05:01 -07:00
Yeesian Ng 83e5df7862 fix: Set the agent_framework when initializing module-based agent engine
PiperOrigin-RevId: 792170095
2025-08-07 08:27:15 -07:00
Google Team Member 25b2806301 fix: accommodate for open api schema that do not have any 'properties'
PiperOrigin-RevId: 792028582
2025-08-07 00:30:50 -07:00
Xuan Yang f6a022cda3 chore: only run ADK Answering Agent automatically when Q&A discussion is created
PiperOrigin-RevId: 792025646
2025-08-07 00:19:30 -07:00
Liang Wu e0a8355219 chore(config): add the public URL of JSON schema file to template
PiperOrigin-RevId: 791983175
2025-08-06 21:50:20 -07:00
Liang Wu d9ce2e691c feat(config): implement config and from_config for MCPToolset
The connection_params argument in the constructor is split into four arguments in the config class because some of them have identical fields. In order to identify which is which, a separate name is more convenient.

PiperOrigin-RevId: 791965995
2025-08-06 20:45:58 -07:00
Liang Wu dc193f7969 fix(config): fix adk create --type=config
Previously click didn't convert the input into the enum type.

PiperOrigin-RevId: 791922529
2025-08-06 18:10:21 -07:00
Xuan Yang 6277dae749 chore: add a disclaimer for the response from the answering agent
PiperOrigin-RevId: 791915465
2025-08-06 17:49:08 -07:00
Liang Wu ef837015f3 refactor(config): move BaseToolConfig to a separate file
PiperOrigin-RevId: 791841562
2025-08-06 14:18:20 -07:00
Google Team Member 54cc849de7 feat: Add metadata field to ADK BaseTool
PiperOrigin-RevId: 791790030
2025-08-06 12:11:42 -07:00
Liang Wu e73d71d324 feat(config): implement config and from_config for ExampleTool
Only list[Example] is supported in config. BaseExampleProvider will need to be used in code.

PiperOrigin-RevId: 791763913
2025-08-06 11:05:54 -07:00
Xiang (Sean) Zhou e528749a1c fix: lazy import VertexAiRagRetrieval
original codes try to eagerly import VertexAiRagRetrieval while it doesn't want to raise error if client try to import other names in this package and dependencies of VertexAiRagRetrieval is missing. so it swallow the import error which doesn't make sense, given vertex sdk is a must have for VertexAiRagRetrieval, we should fail fast.

this fix achieve the same purpose but fail fast if client try to import  VertexAiRagRetrieval from this package and miss certain dependencies (e.g. vertex sdk)

PiperOrigin-RevId: 791759776
2025-08-06 10:54:57 -07:00
Liang Wu 1686cc57c2 feat(config): implement configs and from_config() for CrewaiTool and LangchainTool
PiperOrigin-RevId: 791742964
2025-08-06 10:19:12 -07:00
Wei Sun (Jack) 53803522b6 refactor(config): Makes BaseAgent.from_config a final method and let sub-class to optionally override _parse_config to update kwargs if needed
This ensures that the pydantic hooks (e.g. model_validators) are triggered correctly.

PiperOrigin-RevId: 791545704
2025-08-05 23:53:25 -07:00
Liang Wu e3c2bf3062 chore: remove unused Example-related classes
PiperOrigin-RevId: 791538058
2025-08-05 23:26:06 -07:00
Liang Wu 2fff882fb0 feat(config): implement from_config() for BaseTool
PiperOrigin-RevId: 791520708
2025-08-05 22:26:23 -07:00
Xuan Yang a3b31ca950 chore: add the missing name for the ADK Answering Agent workflow
PiperOrigin-RevId: 791413949
2025-08-05 16:24:24 -07:00
Xuan Yang 8dc0c949af chore: add Github workflow config for the ADK Answering agent
PiperOrigin-RevId: 791407331
2025-08-05 16:07:09 -07:00
Hangfei Lin 71fbc9275b feat: Implement Live Session Resumption
Previous implementation doesn't pass the actual handle to server. Now we cache the handle and pass it over when reconnection happens.

To enable:
    run_config = RunConfig(
        session_resumption=types.SessionResumptionConfig(transparent=True)
    )

PiperOrigin-RevId: 791308462
2025-08-05 11:50:54 -07:00
Xiang (Sean) Zhou 423542a43f fix: shared default plugin manager and cost manager instances among multiple invocations
PiperOrigin-RevId: 791303349
2025-08-05 11:38:52 -07:00
Xiang (Sean) Zhou 37dae9b631 chore: Import AGENT_CARD_WELL_KNOWN_PATH from adk instead of from a2a directly
thus let adk handle import problem for a2a, e.g. python version need to be > 3.10 etc.

PiperOrigin-RevId: 791273137
2025-08-05 10:28:37 -07:00
Liang Wu 0e28d64712 feat(tools): create enterprise_web_search_tool as a tool instance
There is no argument for the tool, so just like google_search, we should make it an easy-to-use tool instance.

PiperOrigin-RevId: 791266806
2025-08-05 10:11:37 -07:00
Xiang (Sean) Zhou 6da6c2a44c fix: using async lock for accessing shared object in parallel executions and update tests for testing various type of functions
1. given we are running parallel functions in one event loop (one thread) , we should use async lock instead of thread lock
2. test three kind of functions:
  a. sync function
  b. async function that doesn't yield
  c. async function that yield

PiperOrigin-RevId: 791255012
2025-08-05 09:45:04 -07:00
Wei Sun (Jack) 8ef2177658 test: Fixes adk cli options and method parameters mismatching and adds a unit test for future proof checking
The test will fail if `@option` list and method parameter don't match.

Future proof test for #2328

PiperOrigin-RevId: 791022512
2025-08-04 21:08:57 -07:00
Google Team Member 97318bcd19 fix: correct type annotation
Overridden `supported_models` should be a `classmethod` rather than a `staticmethod`.

PiperOrigin-RevId: 790989895
2025-08-04 19:25:52 -07:00
Xuan Yang 283303032a chore: update the prompt to make the ADK Answering Agent more objective
PiperOrigin-RevId: 790882938
2025-08-04 13:59:59 -07:00
nikkie e369c283b3 fix: typo againt (in adk run --replay help)
Merge https://github.com/google/adk-python/pull/2327

`adk run --help` (adk 1.9.0)

```
  --replay FILE      The json file that contains the initial state of the
                     session and user queries. A new session will be created
                     using this state. And user queries are run againt the
                     newly created session. Users cannot continue to interact
                     with the agent.
```

```
$ git grep againt
src/google/adk/cli/cli_tools_click.py:        " queries are run againt the newly created session. Users cannot"
```

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2327 from ftnext:fix-typo-run-replay-help 77cae65a235d9119810fe3d209910562672713c8
PiperOrigin-RevId: 790872246
2025-08-04 13:32:41 -07:00
Xuan Yang 74589a1db7 chore: make LlmRequest.LiveConnectConfig field default to a factory to avoid sharing a mutable instance
PiperOrigin-RevId: 790854215
2025-08-04 12:43:34 -07:00
Wei Sun (Jack) e41dbccf7f fix(cli): Fixes adk deploy cloud_run cli
Fixes #2328

PiperOrigin-RevId: 790775592
2025-08-04 09:16:26 -07:00
Carol Zheng d620bcb384 fix: Remove thoughts from contents in llm requests
Merge https://github.com/google/adk-python/pull/2320

Fix #843

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2320 from CAROLZXYZXY:cazheng/fix-843 5b4a4b256928cb766a44a3e18d4300b7ee5f779f
PiperOrigin-RevId: 790592793
2025-08-03 22:48:25 -07:00
Xiang (Sean) Zhou 90b9193a20 chore: Add sample agent for testing parallel functions execution
PiperOrigin-RevId: 790208057
2025-08-02 14:53:03 -07:00
Xiang (Sean) Zhou 57cd41f424 feat: Support parallel execution of parallel function calls
PiperOrigin-RevId: 790182046
2025-08-02 12:28:19 -07:00
Divyansh Shukla 7556ebc76a feat: Allow max tokens to be customizable in Claude
PiperOrigin-RevId: 789901925
2025-08-01 14:43:57 -07:00
Wei Sun (Jack) 2bb20411f4 feat(config): Adds BaseAgent.config_type field to indicate the config for the current agent and removes if-else branches against LlmAgent/LoopAgent/... in config_agent_utils::from_config
This makes the logic work with any user-defined agent with user-defined XxxAgentConfig.

PiperOrigin-RevId: 789845354
2025-08-01 12:02:07 -07:00
Xiang (Sean) Zhou 86a44873e9 fix: Annotate response type as None for transfer_to_agent tool and set empty Schema as response schema when tool has no response annotation
1. if a function has no return type annotation, we should treat it as returning any type
2. we use empty schema (with `type` as None) to indicate no type constraints and this is already supported by model server

PiperOrigin-RevId: 789808104
2025-08-01 10:22:28 -07:00
Xiang (Sean) Zhou faadef167e fix: incompatible a2a sdk changes
a. camel case to snake case
b. A2ACardResolver moved to different module

PiperOrigin-RevId: 789807686
2025-08-01 10:20:37 -07:00
Google Team Member bead607364 chore: Hide the ask_data_insights tool until the API is publicly available
PiperOrigin-RevId: 789806535
2025-08-01 10:17:13 -07:00
Xuan Yang 041f04e89c chore: change LlmRequest.config's default value to be types.GenerateContentConfig() instead of None
PiperOrigin-RevId: 789792582
2025-08-01 09:36:20 -07:00
Google Team Member 16a15c8709 docs: fix typos
PiperOrigin-RevId: 789660536
2025-08-01 01:31:41 -07:00
Liang Wu 9656ccc407 feat(config): add GenerateContentConfig to LlmAgentConfig
PiperOrigin-RevId: 789631181
2025-07-31 23:33:36 -07:00
Liang Wu db975dfe2a chore: prevent triggering of _load_from_yaml_config in AgentLoader
PiperOrigin-RevId: 789502695
2025-07-31 15:59:41 -07:00
242 changed files with 16393 additions and 2018 deletions
@@ -0,0 +1,46 @@
name: ADK Answering Agent for Discussions
on:
discussion:
types: [created]
jobs:
agent-answer-questions:
if: github.event.discussion.category.name == 'Q&A'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Authenticate to Google Cloud
id: auth
uses: 'google-github-actions/auth@v2'
with:
credentials_json: '${{ secrets.ADK_GCP_SA_KEY }}'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install google-adk google-cloud-discoveryengine
- name: Run Answering Script
env:
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
ADK_GCP_SA_KEY: ${{ secrets.ADK_GCP_SA_KEY }}
GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
GOOGLE_CLOUD_LOCATION: ${{ secrets.GOOGLE_CLOUD_LOCATION }}
VERTEXAI_DATASTORE_ID: ${{ secrets.VERTEXAI_DATASTORE_ID }}
GEMINI_API_DATASTORE_ID: ${{ secrets.GEMINI_API_DATASTORE_ID }}
GOOGLE_GENAI_USE_VERTEXAI: 1
OWNER: 'google'
REPO: 'adk-python'
INTERACTIVE: 0
DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
PYTHONPATH: contributing/samples
run: python -m adk_answering_agent.main
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- name: Checkout code
@@ -0,0 +1,51 @@
name: Upload ADK Docs to Vertex AI Search
on:
# Runs once per day at 16:00 UTC
schedule:
- cron: '00 16 * * *'
# Manual trigger for testing and fixing
workflow_dispatch:
jobs:
upload-adk-docs-to-vertex-ai-search:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Clone adk-docs repository
run: git clone https://github.com/google/adk-docs.git /tmp/adk-docs
- name: Clone adk-python repository
run: git clone https://github.com/google/adk-python.git /tmp/adk-python
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Authenticate to Google Cloud
id: auth
uses: 'google-github-actions/auth@v2'
with:
credentials_json: '${{ secrets.ADK_GCP_SA_KEY }}'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install google-adk markdown google-cloud-storage google-cloud-discoveryengine
- name: Run Answering Script
env:
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
GOOGLE_CLOUD_LOCATION: ${{ secrets.GOOGLE_CLOUD_LOCATION }}
VERTEXAI_DATASTORE_ID: ${{ secrets.VERTEXAI_DATASTORE_ID }}
GOOGLE_GENAI_USE_VERTEXAI: 1
GCS_BUCKET_NAME: ${{ secrets.GCS_BUCKET_NAME }}
ADK_DOCS_ROOT_PATH: /tmp/adk-docs
ADK_PYTHON_ROOT_PATH: /tmp/adk-python
PYTHONPATH: contributing/samples
run: python -m adk_answering_agent.upload_docs_to_vertex_ai_search
+85
View File
@@ -1,5 +1,90 @@
# Changelog
## [1.11.0](https://github.com/google/adk-python/compare/v1.10.0...v1.11.0) (2025-08-14)
### Features
* [Tools] Support adding prefix to tool names returned by toolset ([ebd726f](https://github.com/google/adk-python/commit/ebd726f1f5e0a76f383192cace4a80a83204325b))
* [Eval] Expose `print_detailed_results` param to `AgentEvaluator.evaluate` ([7e08808](https://github.com/google/adk-python/commit/7e0880869b340e9a5e0d68d6936219e64ab41212))
* [Tools] Add Spanner toolset (breaking change to BigQueryTool, consolidating into generic GoogleTool) ([1fc8d20](https://github.com/google/adk-python/commit/1fc8d20ae88451b7ed764aa86c17c3cdfaffa1cf))
* [Core] Support both output_schema and tools at the same time in LlmAgent([sample](https://github.com/google/adk-python/tree/main/contributing/samples/output_schema_with_tools)) ([af63567](https://github.com/google/adk-python/commit/af635674b5d3c128cf21737056e091646283aeb7))
### Bug Fixes
* A2A RPC URL got overriden by host and port param of adk api server ([52284b1](https://github.com/google/adk-python/commit/52284b1bae561e0d6c93c9d3240a09f210551b97))
* Aclose all async generators to fix OTel tracing context ([a30c63c](https://github.com/google/adk-python/commit/a30c63c5933a770b960b08a6e2f8bf13eece8a22))
* Use PreciseTimestamp for create and update time in database session service to improve precision ([585141e](https://github.com/google/adk-python/commit/585141e0b7dda20abb024c7164073862c8eea7ae))
* Ignore AsyncGenerator return types in function declarations ([e2518dc](https://github.com/google/adk-python/commit/e2518dc371fe77d7b30328d8d6f5f864176edeac))
* Make all subclass of BaseToolset to call parent constructor ([8c65967](https://github.com/google/adk-python/commit/8c65967cdc2dc79fa925ff49a2a8d67c2a248fa9))
* Path parameter extraction for complex Google API endpoints ([54680ed](https://github.com/google/adk-python/commit/54680edf3cac7477c281680ec988c0a207c0915d))
* Docstring concatenation in 3.13 ([88f759a](https://github.com/google/adk-python/commit/88f759a941c95beef0571f36f8e7a34f27971ba8))
* Lazy load retrieval tools and prompt users to install extensions if import failed ([9478a31](https://github.com/google/adk-python/commit/9478a31bf2257f0b668ae7eb91a10863e87c7bed))
* Incorrect logic in LlmRequest.append_tools and make BaseTool to call it ([b4ce3b1](https://github.com/google/adk-python/commit/b4ce3b12d109dd0386f4985fc4b27d5b93787532))
* Creates an InMemoryMemoryService within the EvaluationGenerator ([e4d54b6](https://github.com/google/adk-python/commit/e4d54b66b38ed334ca92c3bb1a83aca01b19e490))
* Uncomment OTel tracing in base_llm_flow.py ([9cfe433](https://github.com/google/adk-python/commit/9cfe43334ae50f814fed663cca7cbe330e663b8c))
### Improvements
* Added upper version bounds to dependencies in "pyproject.toml" ([a74d334](https://github.com/google/adk-python/commit/a74d3344bc19e587c5e9f55f3c90fa9d22c478d8))
* Update python-version in .github/workflows/python-unit-tests.yml to \["3.9", "3.10", "3.11", "3.12", "3.13"] ([ddf2e21](https://github.com/google/adk-python/commit/ddf2e2194b49667c8e91b4a6afde694474674250))
* Update comment to reference "Streamable HTTP Client" ([c52f956](https://github.com/google/adk-python/commit/c52f9564330f0c00d82338cc58df28cb22400b6f))
* Remove logging that contains full event data from DatabaseSessionService ([bb3735c](https://github.com/google/adk-python/commit/bb3735c9cab1baa1af2cc22981af3b3984ddfe15))
* Add the missing env variables in discussion_answering.yml ([a09a5e6](https://github.com/google/adk-python/commit/a09a5e67aa95cf71b51732ab445232dc4815d83d))
* Add Gemini API docs as a new datastore for the ADK Answering Agent ([5fba196](https://github.com/google/adk-python/commit/5fba1963c31eec512558325c480812ccb919a7bb))
* Add the missing license header for some sample agents' files ([7d2cb65](https://github.com/google/adk-python/commit/7d2cb654f0d64728741b5de733e572c44c8a5b04))
* Add docstring to clarify the behavior of preload memory tool ([88114d7](https://github.com/google/adk-python/commit/88114d7c739ca6a1b9bd19d40ed7160e53054a89))
* Add experimental messages for a2a related API ([d0b3b5d](https://github.com/google/adk-python/commit/d0b3b5d857d8105c689bd64204e367102a67eded))
* Fixes generate_image sample ([d674178](https://github.com/google/adk-python/commit/d674178a0535be3769edbf6af5a3d8cd3d47fcd2))
* Make all FastAPI endpoints async ([7f12387](https://github.com/google/adk-python/commit/7f12387eb19b9335a64b80df00609c3c765480e7))
* Group FastAPI endpoints with tags ([c323de5](https://github.com/google/adk-python/commit/c323de5c692223e55372c3797e62d4752835774d))
* Allow implementations to skip defining a close method on Toolset ([944e39e](https://github.com/google/adk-python/commit/944e39ec2a7c9ad7f20c08fd66bf544de94a23d7))
* Add sample agent to test support of output_schema and tools at the same time for gemini model ([f2005a2](https://github.com/google/adk-python/commit/f2005a20267e1ee8581cb79c37aa55dc8e18c0ea))
* Add Github workflow config for uploading ADK docs to knowledge store ([5900273](https://github.com/google/adk-python/commit/59002734559d49a46940db9822b9c5f490220a8c))
* Update ADK Answering agent to reference doc site instead of adk-docs repo ([b5a8bad](https://github.com/google/adk-python/commit/b5a8bad170e271b475385dac440c7983ed207df8))
### Documentation
* Fixes tool_functions, which is a config-based sample for using tools ([c5af44c](https://github.com/google/adk-python/commit/c5af44cfc0224e2f07ddc7a649a8561e7141fcdc))
* Add workflow_triage sample for multi-agent request orchestration ([e295feb](https://github.com/google/adk-python/commit/e295feb4c67cbe8ac4425d9ae230210840378b2e))
* Add examples for config agents ([d87feb8](https://github.com/google/adk-python/commit/d87feb8ddb6a5e402c63bd3c35625160eb94e132))
* Adds pypi badge to README.md ([dc26aad](https://github.com/google/adk-python/commit/dc26aad663b6ae72223cfec9b91eaf73a636402d))
* Update StreamableHTTPConnectionParams docstring to remove SSE references ([8f937b5](https://github.com/google/adk-python/commit/8f937b517548a1ce0569f9698ea55c0a130ef221))
## [1.10.0](https://github.com/google/adk-python/compare/v1.9.0...v1.10.0) (2025-08-07)
### Features
* [Live] Implement Live Session Resumption ([71fbc92](https://github.com/google/adk-python/commit/71fbc9275b3d74700ec410cb4155ba0cb18580b7))
* [Tool] Support parallel execution of parallel function calls ([57cd41f](https://github.com/google/adk-python/commit/57cd41f424b469fb834bb8f2777b5f7be9aa6cdf))
* [Models] Allow max tokens to be customizable in Claude ([7556ebc](https://github.com/google/adk-python/commit/7556ebc76abd3c776922c2803aed831661cf7f82))
* [Tool] Create enterprise_web_search_tool as a tool instance ([0e28d64](https://github.com/google/adk-python/commit/0e28d64712e481cfd3b964be0166f529657024f6))
### Bug Fixes
* Fix shared default plugin manager and cost manager instances among multiple invocations ([423542a](https://github.com/google/adk-python/commit/423542a43fb8316195e9f79d97f87593751bebd3))
* Correct the type annotation in anthropic_llm implementation ([97318bc](https://github.com/google/adk-python/commit/97318bcd199acdacadfe8664da3fbfc3c806cdd2))
* Fix adk deploy cloud_run cli, which was broken in v1.9.0 ([e41dbcc](https://github.com/google/adk-python/commit/e41dbccf7f610e249108f9321f60f71fe2cc10f4))
* Remove thoughts from contents in llm requests from history contents ([d620bcb](https://github.com/google/adk-python/commit/d620bcb384d3068228ea2059fb70274e68e69682))
* Annotate response type as None for transfer_to_agent tool ([86a4487](https://github.com/google/adk-python/commit/86a44873e9b2dfc7e62fa31a9ac3be57c0bbff7b))
* Fix incompatible a2a sdk changes ([faadef1](https://github.com/google/adk-python/commit/faadef167ee8e4dd1faf4da5685a577c3155556e))
* Fix adk cli options and method parameters mismatching ([8ef2177](https://github.com/google/adk-python/commit/8ef2177658fbfc74b1a74b0c3ea8150bae866796))
### Improvements
* Add Github workflow config for the ADK Answering agent ([8dc0c94](https://github.com/google/adk-python/commit/8dc0c949afb9024738ff7ac1b2c19282175c3200))
* Import AGENT_CARD_WELL_KNOWN_PATH from adk instead of from a2a directly ([37dae9b](https://github.com/google/adk-python/commit/37dae9b631db5060770b66fce0e25cf0ffb56948))
* Make `LlmRequest.LiveConnectConfig` field default to a factory ([74589a1](https://github.com/google/adk-python/commit/74589a1db7df65e319d1ad2f0676ee0cf5d6ec1d))
* Update the prompt to make the ADK Answering Agent more objective ([2833030](https://github.com/google/adk-python/commit/283303032a174d51b8d72f14df83c794d66cb605))
* Add sample agent for testing parallel functions execution ([90b9193](https://github.com/google/adk-python/commit/90b9193a20499b8dd7f57d119cda4c534fcfda10))
* Hide the ask_data_insights tool until the API is publicly available ([bead607](https://github.com/google/adk-python/commit/bead607364be7ac8109357c9d3076d9b345e9e8a))
* Change `LlmRequest.config`'s default value to be `types.GenerateContentConfig()` ([041f04e](https://github.com/google/adk-python/commit/041f04e89cee30532facccce4900d10f1b8c69ce))
* Prevent triggering of _load_from_yaml_config in AgentLoader ([db975df](https://github.com/google/adk-python/commit/db975dfe2a09a6d056d02bc03c1247ac10f6da7d))
### Documentation
* Fix typos ([16a15c8](https://github.com/google/adk-python/commit/16a15c8709b47c9bebe7cffe888e8e7e48ec605a))
## [1.9.0](https://github.com/google/adk-python/compare/v1.8.0...v1.9.0) (2025-07-31)
+1 -2
View File
@@ -49,8 +49,7 @@ This project follows
## Requirement for PRs
- Each PR should only have one commit. Please squash it if there are multiple PRs.
- All PRs, other than small documentation or typo fixes, should have a Issue assoicated. If not, please create one.
- All PRs, other than small documentation or typo fixes, should have a Issue associated. If not, please create one.
- Small, focused PRs. Keep changes minimal—one concern per PR.
- For bug fixes or features, please provide logs or screenshot after the fix is applied to help reviewers better understand the fix.
- Please include a `testing plan` section in your PR to talk about how you will test. This will save time for PR review. See `Testing Requirements` section for more details.
+2 -1
View File
@@ -1,6 +1,7 @@
# Agent Development Kit (ADK)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
[![PyPI](https://img.shields.io/pypi/v/google-adk)](https://pypi.org/project/google-adk/)
[![Python Unit Tests](https://github.com/google/adk-python/actions/workflows/python-unit-tests.yml/badge.svg)](https://github.com/google/adk-python/actions/workflows/python-unit-tests.yml)
[![r/agentdevelopmentkit](https://img.shields.io/badge/Reddit-r%2Fagentdevelopmentkit-FF4500?style=flat&logo=reddit&logoColor=white)](https://www.reddit.com/r/agentdevelopmentkit/)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/google/adk-python)
@@ -14,7 +15,7 @@
</h3>
<h3 align="center">
Important Links:
<a href="https://google.github.io/adk-docs/">Docs</a>,
<a href="https://google.github.io/adk-docs/">Docs</a>,
<a href="https://github.com/google/adk-samples">Samples</a>,
<a href="https://github.com/google/adk-java">Java ADK</a> &
<a href="https://github.com/google/adk-web">ADK Web</a>.
+32
View File
@@ -157,12 +157,43 @@ You can extend this sample by:
- Adding audit logging for authentication events
- Implementing multi-tenant OAuth token management
## Deployment to Other Environments
When deploying the remote BigQuery A2A agent to different environments (e.g., Cloud Run, different hosts/ports), you **must** update the `url` field in the agent card JSON file:
### Local Development
```json
{
"url": "http://localhost:8001/a2a/bigquery_agent",
...
}
```
### Cloud Run Example
```json
{
"url": "https://your-bigquery-service-abc123-uc.a.run.app/a2a/bigquery_agent",
...
}
```
### Custom Host/Port Example
```json
{
"url": "https://your-domain.com:9000/a2a/bigquery_agent",
...
}
```
**Important:** The `url` field in `remote_a2a/bigquery_agent/agent.json` must point to the actual RPC endpoint where your remote BigQuery A2A agent is deployed and accessible.
## Troubleshooting
**Connection Issues:**
- Ensure the local ADK web server is running on port 8000
- Ensure the remote A2A server is running on port 8001
- Check that no firewall is blocking localhost connections
- **Verify the `url` field in `remote_a2a/bigquery_agent/agent.json` matches the actual deployed location of your remote A2A server**
- Verify the agent card URL passed to RemoteA2AAgent constructor matches the running A2A server
@@ -182,3 +213,4 @@ You can extend this sample by:
- Check the logs for both the local ADK web server and remote A2A server
- Verify OAuth tokens are properly passed between agents
- Ensure agent instructions are clear about authentication requirements
- **Double-check that the RPC URL in the agent.json file is correct and accessible**
@@ -24,6 +24,6 @@
"tags": ["authentication", "oauth", "security"]
}
],
"url": "http://localhost:8000/a2a/bigquery_agent",
"url": "http://localhost:8001/a2a/bigquery_agent",
"version": "1.0.0"
}
+32
View File
@@ -107,15 +107,47 @@ You can extend this sample by:
- Adding persistent state management
- Integrating with external APIs or databases
## Deployment to Other Environments
When deploying the remote A2A agent to different environments (e.g., Cloud Run, different hosts/ports), you **must** update the `url` field in the agent card JSON file:
### Local Development
```json
{
"url": "http://localhost:8001/a2a/check_prime_agent",
...
}
```
### Cloud Run Example
```json
{
"url": "https://your-service-abc123-uc.a.run.app/a2a/check_prime_agent",
...
}
```
### Custom Host/Port Example
```json
{
"url": "https://your-domain.com:9000/a2a/check_prime_agent",
...
}
```
**Important:** The `url` field in `remote_a2a/check_prime_agent/agent.json` must point to the actual RPC endpoint where your remote A2A agent is deployed and accessible.
## Troubleshooting
**Connection Issues:**
- Ensure the local ADK web server is running on port 8000
- Ensure the remote A2A server is running on port 8001
- Check that no firewall is blocking localhost connections
- **Verify the `url` field in `remote_a2a/check_prime_agent/agent.json` matches the actual deployed location of your remote A2A server**
- Verify the agent card URL passed to RemoteA2AAgent constructor matches the running A2A server
**Agent Not Responding:**
- Check the logs for both the local ADK web server on port 8000 and remote A2A server on port 8001
- Verify the agent instructions are clear and unambiguous
- **Double-check that the RPC URL in the agent.json file is correct and accessible**
@@ -116,18 +116,50 @@ You can extend this sample by:
- Integrating with external approval systems or databases
- Implementing approval timeouts and escalation procedures
## Deployment to Other Environments
When deploying the remote approval A2A agent to different environments (e.g., Cloud Run, different hosts/ports), you **must** update the `url` field in the agent card JSON file:
### Local Development
```json
{
"url": "http://localhost:8001/a2a/human_in_loop",
...
}
```
### Cloud Run Example
```json
{
"url": "https://your-approval-service-abc123-uc.a.run.app/a2a/human_in_loop",
...
}
```
### Custom Host/Port Example
```json
{
"url": "https://your-domain.com:9000/a2a/human_in_loop",
...
}
```
**Important:** The `url` field in `remote_a2a/human_in_loop/agent.json` must point to the actual RPC endpoint where your remote approval A2A agent is deployed and accessible.
## Troubleshooting
**Connection Issues:**
- Ensure the local ADK web server is running on port 8000
- Ensure the remote A2A server is running on port 8001
- Check that no firewall is blocking localhost connections
- **Verify the `url` field in `remote_a2a/human_in_loop/agent.json` matches the actual deployed location of your remote A2A server**
- Verify the agent card URL passed to RemoteA2AAgent constructor matches the running A2A server
**Agent Not Responding:**
- Check the logs for both the local ADK web server on port 8000 and remote A2A server on port 8001
- Verify the agent instructions are clear and unambiguous
- Ensure long-running tool responses are properly formatted with matching IDs
- **Double-check that the RPC URL in the agent.json file is correct and accessible**
**Approval Workflow Issues:**
- Verify that updated tool responses use the same `id` and `name` as the original function call
@@ -24,6 +24,6 @@
"tags": ["expenses", "processing", "employee-services"]
}
],
"url": "http://localhost:8000/a2a/human_in_loop",
"url": "http://localhost:8001/a2a/human_in_loop",
"version": "1.0.0"
}
+1 -1
View File
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
root_agent = RemoteA2aAgent(
+17 -205
View File
@@ -12,18 +12,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any
from adk_answering_agent.gemini_assistant.agent import root_agent as gemini_assistant_agent
from adk_answering_agent.settings import BOT_RESPONSE_LABEL
from adk_answering_agent.settings import IS_INTERACTIVE
from adk_answering_agent.settings import OWNER
from adk_answering_agent.settings import REPO
from adk_answering_agent.settings import VERTEXAI_DATASTORE_ID
from adk_answering_agent.utils import error_response
from adk_answering_agent.utils import run_graphql_query
from adk_answering_agent.tools import add_comment_to_discussion
from adk_answering_agent.tools import add_label_to_discussion
from adk_answering_agent.tools import convert_gcs_links_to_https
from adk_answering_agent.tools import get_discussion_and_comments
from google.adk.agents.llm_agent import Agent
from google.adk.tools.agent_tool import AgentTool
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
import requests
if IS_INTERACTIVE:
APPROVAL_INSTRUCTION = (
@@ -35,191 +36,6 @@ else:
" comment."
)
def get_discussion_and_comments(discussion_number: int) -> dict[str, Any]:
"""Fetches a discussion and its comments using the GitHub GraphQL API.
Args:
discussion_number: The number of the GitHub discussion.
Returns:
A dictionary with the request status and the discussion details.
"""
print(f"Attempting to get discussion #{discussion_number} and its comments")
query = """
query($owner: String!, $repo: String!, $discussionNumber: Int!) {
repository(owner: $owner, name: $repo) {
discussion(number: $discussionNumber) {
id
title
body
createdAt
closed
author {
login
}
# For each discussion, fetch the latest 20 labels.
labels(last: 20) {
nodes {
id
name
}
}
# For each discussion, fetch the latest 100 comments.
comments(last: 100) {
nodes {
id
body
createdAt
author {
login
}
# For each discussion, fetch the latest 50 replies
replies(last: 50) {
nodes {
id
body
createdAt
author {
login
}
}
}
}
}
}
}
}
"""
variables = {
"owner": OWNER,
"repo": REPO,
"discussionNumber": discussion_number,
}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
discussion_data = (
response.get("data", {}).get("repository", {}).get("discussion")
)
if not discussion_data:
return error_response(f"Discussion #{discussion_number} not found.")
return {"status": "success", "discussion": discussion_data}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def add_comment_to_discussion(
discussion_id: str, comment_body: str
) -> dict[str, Any]:
"""Adds a comment to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
comment_body: The content of the comment in Markdown.
Returns:
The status of the request and the new comment's details.
"""
print(f"Adding comment to discussion {discussion_id}")
query = """
mutation($discussionId: ID!, $body: String!) {
addDiscussionComment(input: {discussionId: $discussionId, body: $body}) {
comment {
id
body
createdAt
author {
login
}
}
}
}
"""
variables = {"discussionId": discussion_id, "body": comment_body}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
new_comment = (
response.get("data", {}).get("addDiscussionComment", {}).get("comment")
)
return {"status": "success", "comment": new_comment}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def get_label_id(label_name: str) -> str | None:
"""Helper function to find the GraphQL node ID for a given label name."""
print(f"Finding ID for label '{label_name}'...")
query = """
query($owner: String!, $repo: String!, $labelName: String!) {
repository(owner: $owner, name: $repo) {
label(name: $labelName) {
id
}
}
}
"""
variables = {"owner": OWNER, "repo": REPO, "labelName": label_name}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
print(
f"[Warning] Error from GitHub API response for label '{label_name}':"
f" {response['errors']}"
)
return None
label_info = response["data"].get("repository", {}).get("label")
if label_info:
return label_info.get("id")
print(f"[Warning] Label information for '{label_name}' not found.")
return None
except requests.exceptions.RequestException as e:
print(f"[Warning] Error from GitHub API: {e}")
return None
def add_label_to_discussion(
discussion_id: str, label_name: str
) -> dict[str, Any]:
"""Adds a label to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
label_name: The name of the label to add (e.g., "bug").
Returns:
The status of the request and the label details.
"""
print(
f"Attempting to add label '{label_name}' to discussion {discussion_id}..."
)
# First, get the GraphQL ID of the label by its name
label_id = get_label_id(label_name)
if not label_id:
return error_response(f"Label '{label_name}' not found.")
# Then, perform the mutation to add the label to the discussion
mutation = """
mutation AddLabel($discussionId: ID!, $labelId: ID!) {
addLabelsToLabelable(input: {labelableId: $discussionId, labelIds: [$labelId]}) {
clientMutationId
}
}
"""
variables = {"discussionId": discussion_id, "labelId": label_id}
try:
response = run_graphql_query(mutation, variables)
if "errors" in response:
return error_response(str(response["errors"]))
return {"status": "success", "label_id": label_id, "label_name": label_name}
except requests.exceptions.RequestException as e:
return error_response(str(e))
root_agent = Agent(
model="gemini-2.5-pro",
name="adk_answering_agent",
@@ -238,38 +54,34 @@ root_agent = Agent(
* The latest comment is not from you or other agents (marked as "Response from XXX Agent").
* The latest comment is asking a question or requesting information.
4. Use the `VertexAiSearchTool` to find relevant information before answering.
* If you need infromation about Gemini API, ask the `gemini_assistant` agent to provide the information and references.
* You can call the `gemini_assistant` agent with multiple queries to find all the relevant information.
5. If you can find relevant information, use the `add_comment_to_discussion` tool to add a comment to the discussion.
6. If you post a commment and the discussion does not have a label named {BOT_RESPONSE_LABEL},
add the label {BOT_RESPONSE_LABEL} to the discussion using the `add_label_to_discussion` tool.
6. If you post a comment, add the label {BOT_RESPONSE_LABEL} to the discussion using the `add_label_to_discussion` tool.
IMPORTANT:
* {APPROVAL_INSTRUCTION}
* Your response should be based on the information you found in the document store. Do not invent
information that is not in the document store. Do not invent citations which are not in the document store.
* **Be Objective**: your answer should be based on the facts you found in the document store, do not be misled by user's assumptions or user's understanding of ADK.
* If you can't find the answer or information in the document store, **do not** respond.
* Include a bolded note (e.g. "Response from ADK Answering Agent") in your comment
to indicate this comment was added by an ADK Answering Agent.
* Have an empty line between the note and the rest of your response.
* Inlclude a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>".
* Start with a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>".
* Have a divider line between the TLDR and your detail response.
* Do not respond to any other discussion except the one specified by the user.
* Please include your justification for your decision in your output
to the user who is telling with you.
* If you uses citation from the document store, please provide a footnote
referencing the source document format it as: "[1] URL of the document".
* Replace the "gs://prefix/" part, e.g. "gs://adk-qa-bucket/", to be "https://github.com/google/"
* Add "blob/main/" after the repo name, e.g. "adk-python", "adk-docs", for example:
* If the original URL is "gs://adk-qa-bucket/adk-python/src/google/adk/version.py",
then the citation URL is "https://github.com/google/adk-python/blob/main/src/google/adk/version.py",
* If the original URL is "gs://adk-qa-bucket/adk-docs/docs/index.md",
then the citation URL is "https://github.com/google/adk-docs/blob/main/docs/index.md"
* If the file is a html file, replace the ".html" to be ".md"
referencing the source document format it as: "[1] publicly accessible HTTPS URL of the document".
* You **should always** use the `convert_gcs_links_to_https` tool to convert GCS links (e.g. "gs://...") to HTTPS links.
* **Do not** use the `convert_gcs_links_to_https` tool for non-GCS links.
* Make sure the citation URL is valid. Otherwise do not list this specific citation.
""",
tools=[
VertexAiSearchTool(data_store_id=VERTEXAI_DATASTORE_ID),
AgentTool(gemini_assistant_agent),
get_discussion_and_comments,
add_comment_to_discussion,
add_label_to_discussion,
convert_gcs_links_to_https,
],
)
@@ -0,0 +1,15 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import agent
@@ -0,0 +1,94 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from typing import Any
from typing import Dict
from typing import List
from adk_answering_agent.settings import ADK_GCP_SA_KEY
from adk_answering_agent.settings import GEMINI_API_DATASTORE_ID
from adk_answering_agent.utils import error_response
from google.adk.agents.llm_agent import Agent
from google.api_core.exceptions import GoogleAPICallError
from google.cloud import discoveryengine_v1beta as discoveryengine
from google.oauth2 import service_account
def search_gemini_api_docs(queries: List[str]) -> Dict[str, Any]:
"""Searches Gemini API docs using Vertex AI Search.
Args:
queries: The list of queries to search.
Returns:
A dictionary containing the status of the request and the list of search
results, which contains the title, url and snippets.
"""
try:
adk_gcp_sa_key_info = json.loads(ADK_GCP_SA_KEY)
client = discoveryengine.SearchServiceClient(
credentials=service_account.Credentials.from_service_account_info(
adk_gcp_sa_key_info
)
)
except (TypeError, ValueError) as e:
return error_response(f"Error creating Vertex AI Search client: {e}")
serving_config = f"{GEMINI_API_DATASTORE_ID}/servingConfigs/default_config"
results = []
try:
for query in queries:
request = discoveryengine.SearchRequest(
serving_config=serving_config,
query=query,
page_size=20,
)
response = client.search(request=request)
for item in response.results:
snippets = []
for snippet in item.document.derived_struct_data.get("snippets", []):
snippets.append(snippet.get("snippet"))
results.append({
"title": item.document.derived_struct_data.get("title"),
"url": item.document.derived_struct_data.get("link"),
"snippets": snippets,
})
except GoogleAPICallError as e:
return error_response(f"Error from Vertex AI Search: {e}")
return {"status": "success", "results": results}
root_agent = Agent(
model="gemini-2.5-pro",
name="gemini_assistant",
description="Answer questions about Gemini API.",
instruction="""
You are a helpful assistant that responds to questions about Gemini API based on information
found in the document store. You can access the document store using the `search_gemini_api_docs` tool.
When user asks a question, here are the steps:
1. Use the `search_gemini_api_docs` tool to find relevant information before answering.
* You can call the tool with multiple queries to find all the relevant information.
2. Provide a response based on the information you found in the document store. Reference the source document in the response.
IMPORTANT:
* Your response should be based on the information you found in the document store. Do not invent
information that is not in the document store. Do not invent citations which are not in the document store.
* If you can't find the answer or information in the document store, just respond with "I can't find the answer or information in the document store".
* If you uses citation from the document store, please always provide a footnote referencing the source document format it as: "[1] URL of the document".
""",
tools=[search_gemini_api_docs],
)
@@ -13,6 +13,7 @@
# limitations under the License.
import asyncio
import logging
import time
from adk_answering_agent import agent
@@ -21,11 +22,14 @@ from adk_answering_agent.settings import OWNER
from adk_answering_agent.settings import REPO
from adk_answering_agent.utils import call_agent_async
from adk_answering_agent.utils import parse_number_string
from google.adk.cli.utils import logs
from google.adk.runners import InMemoryRunner
APP_NAME = "adk_answering_app"
USER_ID = "adk_answering_user"
logs.setup_adk_logger(level=logging.DEBUG)
async def main():
runner = InMemoryRunner(
@@ -31,6 +31,9 @@ if not VERTEXAI_DATASTORE_ID:
GOOGLE_CLOUD_PROJECT = os.getenv("GOOGLE_CLOUD_PROJECT")
GCS_BUCKET_NAME = os.getenv("GCS_BUCKET_NAME")
GEMINI_API_DATASTORE_ID = os.getenv("GEMINI_API_DATASTORE_ID")
ADK_GCP_SA_KEY = os.getenv("ADK_GCP_SA_KEY")
ADK_DOCS_ROOT_PATH = os.getenv("ADK_DOCS_ROOT_PATH")
ADK_PYTHON_ROOT_PATH = os.getenv("ADK_PYTHON_ROOT_PATH")
@@ -0,0 +1,230 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any
from typing import Dict
from typing import Optional
from adk_answering_agent.settings import OWNER
from adk_answering_agent.settings import REPO
from adk_answering_agent.utils import convert_gcs_to_https
from adk_answering_agent.utils import error_response
from adk_answering_agent.utils import run_graphql_query
import requests
def get_discussion_and_comments(discussion_number: int) -> dict[str, Any]:
"""Fetches a discussion and its comments using the GitHub GraphQL API.
Args:
discussion_number: The number of the GitHub discussion.
Returns:
A dictionary with the request status and the discussion details.
"""
print(f"Attempting to get discussion #{discussion_number} and its comments")
query = """
query($owner: String!, $repo: String!, $discussionNumber: Int!) {
repository(owner: $owner, name: $repo) {
discussion(number: $discussionNumber) {
id
title
body
createdAt
closed
author {
login
}
# For each discussion, fetch the latest 20 labels.
labels(last: 20) {
nodes {
id
name
}
}
# For each discussion, fetch the latest 100 comments.
comments(last: 100) {
nodes {
id
body
createdAt
author {
login
}
# For each discussion, fetch the latest 50 replies
replies(last: 50) {
nodes {
id
body
createdAt
author {
login
}
}
}
}
}
}
}
}
"""
variables = {
"owner": OWNER,
"repo": REPO,
"discussionNumber": discussion_number,
}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
discussion_data = (
response.get("data", {}).get("repository", {}).get("discussion")
)
if not discussion_data:
return error_response(f"Discussion #{discussion_number} not found.")
return {"status": "success", "discussion": discussion_data}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def add_comment_to_discussion(
discussion_id: str, comment_body: str
) -> dict[str, Any]:
"""Adds a comment to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
comment_body: The content of the comment in Markdown.
Returns:
The status of the request and the new comment's details.
"""
print(f"Adding comment to discussion {discussion_id}")
query = """
mutation($discussionId: ID!, $body: String!) {
addDiscussionComment(input: {discussionId: $discussionId, body: $body}) {
comment {
id
body
createdAt
author {
login
}
}
}
}
"""
if not comment_body.startswith("**Response from ADK Answering Agent"):
comment_body = (
"**Response from ADK Answering Agent (experimental, answer may be"
" inaccurate)**\n\n"
+ comment_body
)
variables = {"discussionId": discussion_id, "body": comment_body}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
new_comment = (
response.get("data", {}).get("addDiscussionComment", {}).get("comment")
)
return {"status": "success", "comment": new_comment}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def get_label_id(label_name: str) -> str | None:
"""Helper function to find the GraphQL node ID for a given label name."""
print(f"Finding ID for label '{label_name}'...")
query = """
query($owner: String!, $repo: String!, $labelName: String!) {
repository(owner: $owner, name: $repo) {
label(name: $labelName) {
id
}
}
}
"""
variables = {"owner": OWNER, "repo": REPO, "labelName": label_name}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
print(
f"[Warning] Error from GitHub API response for label '{label_name}':"
f" {response['errors']}"
)
return None
label_info = response["data"].get("repository", {}).get("label")
if label_info:
return label_info.get("id")
print(f"[Warning] Label information for '{label_name}' not found.")
return None
except requests.exceptions.RequestException as e:
print(f"[Warning] Error from GitHub API: {e}")
return None
def add_label_to_discussion(
discussion_id: str, label_name: str
) -> dict[str, Any]:
"""Adds a label to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
label_name: The name of the label to add (e.g., "bug").
Returns:
The status of the request and the label details.
"""
print(
f"Attempting to add label '{label_name}' to discussion {discussion_id}..."
)
# First, get the GraphQL ID of the label by its name
label_id = get_label_id(label_name)
if not label_id:
return error_response(f"Label '{label_name}' not found.")
# Then, perform the mutation to add the label to the discussion
mutation = """
mutation AddLabel($discussionId: ID!, $labelId: ID!) {
addLabelsToLabelable(input: {labelableId: $discussionId, labelIds: [$labelId]}) {
clientMutationId
}
}
"""
variables = {"discussionId": discussion_id, "labelId": label_id}
try:
response = run_graphql_query(mutation, variables)
if "errors" in response:
return error_response(str(response["errors"]))
return {"status": "success", "label_id": label_id, "label_name": label_name}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def convert_gcs_links_to_https(gcs_uris: list[str]) -> Dict[str, Optional[str]]:
"""Converts GCS files link into publicly accessible HTTPS links.
Args:
gcs_uris: A list of GCS files links, in the format
'gs://bucket_name/prefix/relative_path'.
Returns:
A dictionary mapping the original GCS files links to the converted HTTPS
links. If a GCS link is invalid, the corresponding value in the dictionary
will be None.
"""
return {gcs_uri: convert_gcs_to_https(gcs_uri) for gcs_uri in gcs_uris}
@@ -12,8 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from typing import Any
from typing import Optional
from urllib.parse import urljoin
from adk_answering_agent.settings import GITHUB_GRAPHQL_URL
from adk_answering_agent.settings import GITHUB_TOKEN
@@ -58,6 +61,92 @@ def parse_number_string(number_str: str | None, default_value: int = 0) -> int:
return default_value
def _check_url_exists(url: str) -> bool:
"""Checks if a URL exists and is accessible."""
try:
# Set a timeout to prevent the program from waiting indefinitely.
# allow_redirects=True ensures we correctly handle valid links
# after redirection.
response = requests.head(url, timeout=5, allow_redirects=True)
# Status codes 2xx (Success) or 3xx (Redirection) are considered valid.
return response.ok
except requests.RequestException:
# Catch all possible exceptions from the requests library
# (e.g., connection errors, timeouts).
return False
def _generate_github_url(repo_name: str, relative_path: str) -> str:
"""Generates a standard GitHub URL for a repo file."""
return f"https://github.com/google/{repo_name}/blob/main/{relative_path}"
def convert_gcs_to_https(gcs_uri: str) -> Optional[str]:
"""Converts a GCS file link into a publicly accessible HTTPS link.
Args:
gcs_uri: The Google Cloud Storage link, in the format
'gs://bucket_name/prefix/relative_path'.
Returns:
The converted HTTPS link as a string, or None if the input format is
incorrect.
"""
# Parse the GCS link
if not gcs_uri or not gcs_uri.startswith("gs://"):
print(f"Error: Invalid GCS link format: {gcs_uri}")
return None
try:
# Strip 'gs://' and split by '/', requiring at least 3 parts
# (bucket, prefix, path)
parts = gcs_uri[5:].split("/", 2)
if len(parts) < 3:
raise ValueError(
"GCS link must contain a bucket, prefix, and relative_path."
)
_, prefix, relative_path = parts
except (ValueError, IndexError) as e:
print(f"Error: Failed to parse GCS link '{gcs_uri}': {e}")
return None
# Replace .html with .md
if relative_path.endswith(".html"):
relative_path = relative_path.removesuffix(".html") + ".md"
# Convert the links for adk-docs
if prefix == "adk-docs" and relative_path.startswith("docs/"):
path_after_docs = relative_path[len("docs/") :]
if not path_after_docs.endswith(".md"):
# Use the regular github url
return _generate_github_url(prefix, relative_path)
base_url = "https://google.github.io/adk-docs/"
if os.path.basename(path_after_docs) == "index.md":
# Use the directory path if it is a index file
final_path_segment = os.path.dirname(path_after_docs)
else:
# Otherwise, use the file name without extention
final_path_segment = path_after_docs.removesuffix(".md")
if final_path_segment and not final_path_segment.endswith("/"):
final_path_segment += "/"
potential_url = urljoin(base_url, final_path_segment)
# Check if the generated link exists
if _check_url_exists(potential_url):
return potential_url
else:
# If it doesn't exist, fallback to the regular github url
return _generate_github_url(prefix, relative_path)
# Convert the links for other cases, e.g. adk-python
else:
return _generate_github_url(prefix, relative_path)
async def call_agent_async(
runner: Runner, user_id: str, session_id: str, prompt: str
) -> str:
-10
View File
@@ -25,16 +25,6 @@ distributed via the `google.adk.tools.bigquery` module. These tools include:
Runs a SQL query in BigQuery.
1. `ask_data_insights`
Natural language-in, natural language-out tool that answers questions
about structured data in BigQuery. Provides a one-stop solution for generating
insights from data.
**Note**: This tool requires additional setup in your project. Please refer to
the official [Conversational Analytics API documentation](https://cloud.google.com/gemini/docs/conversational-analytics-api/overview)
for instructions.
## How to use
Set up environment variables in your `.env` file for using

Some files were not shown because too many files have changed in this diff Show More