Compare commits

..

164 Commits

Author SHA1 Message Date
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
Wei Sun (Jack) 0ccbf6f2f8 chore: Bump version and update CHANGELOG for v1.9.0
PiperOrigin-RevId: 789494584
2025-07-31 15:34:18 -07:00
Ankur Sharma a54c7024cf fix: Re-adding eval related changes
Due to reasons that are being investigated, some of the recent changes got unintentionally reverted. We are adding those back in this PR.

PiperOrigin-RevId: 789384063
2025-07-31 10:18:39 -07:00
Shangjie Chen 1cfe6e9ffe chore: Remove unnecessary flags
PiperOrigin-RevId: 789379877
2025-07-31 10:07:39 -07:00
Shangjie Chen 314d6a4f95 fix: Return session state in list_session API endpoint
Resolves https://github.com/google/adk-python/issues/2193
Resolves https://github.com/google/adk-python/issues/781

PiperOrigin-RevId: 789143973
2025-07-30 19:53:46 -07:00
Alejandro Cruzado-Ruiz 247fd2066c chore: replace module import for BaseAgent in local_eval_service
PiperOrigin-RevId: 789136339
2025-07-30 19:19:17 -07:00
Shangjie Chen 7d06fb735e chore: Move create_session log to where the session is actually created
PiperOrigin-RevId: 789094066
2025-07-30 16:46:25 -07:00
Liang Wu d5dcef2cf0 fix(config): forbid extra fields in AgentToolConfig
PiperOrigin-RevId: 789038376
2025-07-30 14:13:48 -07:00
Xuan Yang 6191412b07 fix: keep existing header values while merging tracking headers for llm_request.config.http_options in Gemini.generate_content_async
PiperOrigin-RevId: 789013693
2025-07-30 13:09:56 -07:00
Xuan Yang 3be1bb37d9 fix: use pull_request_target event as the trigger of PR triaging agent
GitHub workflows triggered by `pull_request` events from forked repositories do not have access to secrets by default due to security considerations.

PiperOrigin-RevId: 789011890
2025-07-30 13:05:15 -07:00
Google Team Member 7c9b0a2567 feat: add chat first-party tool
This tool answers questions about structured data in BigQuery using natural language.

PiperOrigin-RevId: 789000987
2025-07-30 12:35:20 -07:00
Liang Wu 0c6086cb15 chore: remove redundant definition for adk deploy gke command
PiperOrigin-RevId: 788758843
2025-07-29 22:47:56 -07:00
hsuyuming 9db5d9a3e8 fix: Unable to acquire impersonated credentials
Merge https://github.com/google/adk-python/pull/2003

add scope "https://www.googleapis.com/auth/cloud-platform" within google.auth.default

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2003 from hsuyuming:fix/issue_2001_support_impersonated_credential 8874a367273aca98460f7f250bfc4690f883ebbe
PiperOrigin-RevId: 788656025
2025-07-29 16:42:25 -07:00
Xiang (Sean) Zhou de6ebddcd2 chore: Replace selcukg with genquan
PiperOrigin-RevId: 788590913
2025-07-29 13:48:54 -07:00
Liang Wu bcac9ba44c feat(config): add --type flag to adk create to allow starting with config
Updated the `adk create` default model version to gemini-2.5-flash.

PiperOrigin-RevId: 788589859
2025-07-29 13:45:11 -07:00
Xiang (Sean) Zhou 2f73cfde18 chore: Fix the long running test cases
The test test_token_exchange_not_supported was slow because of an incorrect monkeypatch target. The test was patching google.adk.auth.auth_handler.AUTHLIB_AVAILABLE, but the actual OAuth2 exchange logic uses a different AUTHLIB_AVAILABLE variable in google.adk.auth.exchanger.oauth2_credential_exchanger.
What was happening:
Test set auth_handler.AUTHLIB_AVAILABLE = False
AuthHandler.exchange_auth_token() called OAuth2CredentialExchanger.exchange()
But oauth2_credential_exchanger.AUTHLIB_AVAILABLE was still True
The exchanger attempted real OAuth2 token exchange with client.fetch_token()
This made actual network calls to OAuth2 endpoints, causing timeouts and delays

PiperOrigin-RevId: 788576949
2025-07-29 13:14:28 -07:00
Xuan Yang ec8dd5721a fix: merge tracking headers even when llm_request.config.http_options is not set in Gemini.generate_content_async
PiperOrigin-RevId: 788568620
2025-07-29 12:52:32 -07:00
Xuan Yang 646eb42533 chore: add Github workflow config for the ADK PR triaging agent
PiperOrigin-RevId: 788519884
2025-07-29 10:49:35 -07:00
Google Team Member bf72426af2 fix: runner was expecting Event object instead of Content object when using early exist feature
PiperOrigin-RevId: 788516645
2025-07-29 10:41:19 -07:00
Holt Skinner 9c0721beaa fix: Update agent_card_builder to follow grammar rules
Merge https://github.com/google/adk-python/pull/2226

Fixes #2223

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2226 from holtskinner:a2a-fixes ff556224e4071a8287a9ced19f645f0edd9916ef
PiperOrigin-RevId: 788512608
2025-07-29 10:32:32 -07:00
Xuan Yang 5eff66a132 chore: create an initial prototype agent to triage pull requests
This agent will post a comment if the PR is not following our contribution guides or add a label and reviewer for the PR if it passes the guide check.

PiperOrigin-RevId: 788511767
2025-07-29 10:29:35 -07:00
Google Team Member 282d67f253 fix: import cli's artifact dependencies directly
PiperOrigin-RevId: 788488501
2025-07-29 09:34:19 -07:00
Xiang (Sean) Zhou 3432b22172 fix: Copy the original function call args before passing it to callback or tools to avoid being modified
PiperOrigin-RevId: 788462897
2025-07-29 08:20:48 -07:00
Yifan Wang af35e2673f chore: WIP endpoint
PiperOrigin-RevId: 788232652
2025-07-28 18:06:03 -07:00
Xuan Yang f68d4d5cd0 chore: add the missing license header for a2a/__init__.py
PiperOrigin-RevId: 788227196
2025-07-28 17:50:26 -07:00
Google Team Member 16e8419e32 fix: restore bigquery sample agent to runnable form
A previous change of import paths had rendered the agent not-runnable out of the box. This change fixes that.

PiperOrigin-RevId: 788221276
2025-07-28 17:31:50 -07:00
Xiang (Sean) Zhou 0c855877c5 docs: Update documents about the information of viber coding
PiperOrigin-RevId: 788217734
2025-07-28 17:18:53 -07:00
Yeesian Ng f29ab5db05 feat: Respect the .ae_ignore file when deploying to agent engine
PiperOrigin-RevId: 788052720
2025-07-28 10:01:54 -07:00
Liang Wu f1889ae440 feat(config): support ADK built-in and custom tools in config
PiperOrigin-RevId: 787735915
2025-07-27 11:14:04 -07:00
Ankur Sharma c69dcf8779 feat: Added an Fast API new endpoint to serve eval metric info
This endpoint could be used by ADK Web to dynamically know:
- What are the available eval metrics in an App
- A description of those metrics
- A value range supported by those metrics

We also update the metric registry to make it mandatory to supply these details. The goal is to improve usability and interpretability of the eval metrics.

PiperOrigin-RevId: 787277695
2025-07-25 16:25:20 -07:00
Wei Sun (Jack) ec7d9b0ff6 chore(config): Moves agent configs to separate python files
PiperOrigin-RevId: 787245794
2025-07-25 14:40:49 -07:00
Yeesian Ng 6419a2aa9b fix: Switch from agent_engine_name to agent_engine_id for updating instances
PiperOrigin-RevId: 787179405
2025-07-25 11:24:10 -07:00
Yifan Wang b83b0a6eec chore: experiment endpoint
PiperOrigin-RevId: 787164869
2025-07-25 10:44:09 -07:00
Wei Sun (Jack) a3ff21eb0b feat(config): Adds CustomAgentConfig to support user-defined agents in config
PiperOrigin-RevId: 787148485
2025-07-25 09:56:10 -07:00
qieqieplus 1778490e64 fix: Fix unsafe_local_code_executor for import scope
Merge https://github.com/google/adk-python/pull/869

How to reproduce the error:

```
from google.adk.code_executors import UnsafeLocalCodeExecutor
from google.adk.code_executors.code_execution_utils import CodeExecutionInput

result = UnsafeLocalCodeExecutor().execute_code(
    invocation_context=None,
    code_execution_input=CodeExecutionInput(
        code='''
import math

def pi():
    return math.pi

print(pi())
'''
    )
)

print(result)
```

output:
```
CodeExecutionResult(stdout='', stderr="name 'math' is not defined", output_files=[])
```
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/869 from qieqieplus:main 63f557bbd3b7aa5c2801f5cc9e022d3364177308
PiperOrigin-RevId: 787145189
2025-07-25 09:45:34 -07:00
Vicente Ferrara a858d79b3a feat: cli funcionality to deploy an Agent to a running GKE cluster
Merge https://github.com/google/adk-python/pull/1607

- Added CLI functionality so that we can deploy and Agent onto a GKE cluster
- Related documentation https://github.com/google/adk-docs/pull/445

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1607 from vicentefb:GkeDeployAgent 42f35d93b0a5df5f6dbeb9ee7f869cde51e2f6eb
PiperOrigin-RevId: 786857789
2025-07-24 15:32:23 -07:00
Lam Nguyen c8f8b4a20a fix: Fix incorrect token count mapping in telemetry
Merge https://github.com/google/adk-python/pull/2109

Fixes #2105

## Problem
  When integrating Google ADK with Langfuse using the @observe
  decorator, the usage details displayed in Langfuse web UI were
  incorrect.

  The root cause was in the telemetry implementation where
  total_token_count was being mapped to gen_ai.usage.output_tokens
  instead of candidates_token_count.

  - Expected mapping:
    - candidates_token_count → completion_tokens (output tokens)
    - prompt_token_count → prompt_tokens (input tokens)

  - Previous incorrect mapping:
    - total_token_count → completion_tokens (wrong!)
    - prompt_token_count → prompt_tokens (correct)

  ## Solution
  Updated trace_call_llm function in telemetry.py to use
  candidates_token_count for output token tracking instead of
  total_token_count, ensuring proper token count reporting to
  observability tools like Langfuse.

  ## Testing plan
  - Updated test expectations in test_telemetry.py
  - Verified telemetry tests pass
  - Manual verification with Langfuse integration

  ## Screenshots
  **Before**

<img width="1187" height="329" alt="Screenshot from 2025-07-22 20-20-33" src="https://github.com/user-attachments/assets/ad5fc957-64a2-4524-bd31-0cebb15a5270" />

  **After**

<img width="1187" height="329" alt="Screenshot from 2025-07-22 20-21-40" src="https://github.com/user-attachments/assets/3920df2a-be75-47e0-9bd0-f961bb72c838" />

 _Notes_: From the screenshot, there's another problem: thoughts_token_count field is not mapped, but this should be another issue imo

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2109 from tl-nguyen:fix-telemetry-token-count-mapping 3d043f558b5f8bcb2c6e0370e2cc4c0ff25d1f4a
PiperOrigin-RevId: 786827802
2025-07-24 14:01:03 -07:00
Shangjie Chen 11037fc133 chore: Filter event with only functions, thought_signatures when adding to memory
PiperOrigin-RevId: 786825628
2025-07-24 13:54:37 -07:00
Yeesian Ng 206a13271e feat: Add a CLI option to update an agent engine instance
PiperOrigin-RevId: 786816663
2025-07-24 13:27:49 -07:00
Xuan Yang 3be0882c63 feat: add -v, --verbose flag to enable DEBUG logging as a shortcut for --log_level DEBUG
PiperOrigin-RevId: 786797394
2025-07-24 12:30:30 -07:00
Alejandro Cruzado-Ruiz e176f03e8f feat: modularize fast_api.py to allow simpler construction of API Server
PiperOrigin-RevId: 786763344
2025-07-24 10:53:13 -07:00
Kavin Kumar B 7206e0a0eb fix: eval module not found exception string
Merge https://github.com/google/adk-python/pull/2148

This PR fixes #2071 exception string from `pip install google-adk[eval]` to `pip install "google-adk[eval]"` which makes it compatible for all the bash, zsh and other terminals

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2148 from kavinkumar807:fix-module-not-found-exception-string-in-eval 914281006a0e162665c0933d0c0ee0c37eb397cf
PiperOrigin-RevId: 786752261
2025-07-24 10:23:03 -07:00
Yeesian Ng fbe6a7b8d3 fix: Add absolutize_imports option when deploying to agent engine
PiperOrigin-RevId: 786749263
2025-07-24 10:15:35 -07:00
Google Team Member bfc203a92f feat: modularize fast_api.py to allow simpler construction of API Server
PiperOrigin-RevId: 786646546
2025-07-24 04:03:19 -07:00
Hangfei Lin 5e8aa15a50 feat: add support for session resumption(only transparent mode) config to run_config
This commit adds support for the session resumption configuration in the run_config.
The SessionResumptionConfig is added to RunConfig to allow the user to set up a configuration for session resumption(only transparent mode for now).

There are two modes of session resumption: manual and transparent. In manual mode, you have to manually bookkeeping the session information and restarts the session which is tricky to do right now. In transparent mode, the server does the bookkeeping for you and no hassle on ADK side. For now, the transparent mode should be enough.

Also, added the relevant unit tests to check that every possible configuration is set properly and the run_config is correctly populated.
This is needed for supporting the new session resumption feature.

PiperOrigin-RevId: 786549455
2025-07-23 21:37:00 -07:00
Che Liu 16392984c5 feat: Expose Gemini RetryOptions to client
google.genai SDK has introduced a new retry_options. This change exposes this configuration
to ADK users

Usage:

```python
root_agent = Agent(
    model=Gemini(
        model='gemini-2.0-flash',
        retry_options=types.HttpRetryOptions(
	    initial_delay=1,
	    attempts=2
	    # ... Retry options from google.genai
	),
	# ...
    ),
```
PiperOrigin-RevId: 786472564
2025-07-23 16:50:09 -07:00
Che Liu 20537e8bfa feat: Add sample plugin for logging
This plugin helps printing all critical events in the console. It is not a replacement
of existing logging in ADK. It rather helps terminal based debugging by showing all logs in the console, and serves as a
simple demo so everyone could develop their own plugins.

PiperOrigin-RevId: 786470637
2025-07-23 16:43:32 -07:00
Che Liu 00afaaf2fc feat: add new callbacks to handle tool and model errors
This CL add new callbacks in plugin system:
- `on_tool_error_callback`
- `on_model_error_callback`

This allow the user to create plugins that can handle errors.

PiperOrigin-RevId: 786469646
2025-07-23 16:40:09 -07:00
Alejandro Cruzado-Ruiz dfc25c17a9 feat: modularize fast_api.py to allow simpler construction of API Server
PiperOrigin-RevId: 786467758
2025-07-23 16:33:54 -07:00
Ariz Chang 32ae882a49 feat: Add camel case converter for agents
PiperOrigin-RevId: 786465205
2025-07-23 16:27:03 -07:00
Ankur Sharma 884c201958 chore: Release 1.8.0
PiperOrigin-RevId: 786462899
2025-07-23 16:19:49 -07:00
Andrew Larimer 70c461686e fix: add space to allow adk deploy cloud_run --a2a
Merge https://github.com/google/adk-python/pull/2138

This missing space leads to an error when deploying to cloud_run that says "No option --a2a/apps/agents"

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2138 from andrewlarimer:fix--add-space-to-allow-adk-deploy-cloud_run---a2a 47831f10e1f7f6c27b5f6b8c102b2f7db4619778
PiperOrigin-RevId: 786459787
2025-07-23 16:09:49 -07:00
Ankur Sharma 1355bd643b feat: Refactored AgentEvaluator and updated it to use LocalEvalService
With this change we ensure that all three eval entry points, web, cli and pytest use the common LocalEvalService.

Updates to web and cli happened in a previous change.

PiperOrigin-RevId: 786445632
2025-07-23 15:27:26 -07:00
Xiang (Sean) Zhou 927c75f0ee chore: Replace imports by importing from actual module instead of from package (__init__.py)
PiperOrigin-RevId: 786342250
2025-07-23 10:49:43 -07:00
Xiang (Sean) Zhou 430b82024f chore: Fixed flaky test_update_credential_with_tokens unittest
PiperOrigin-RevId: 786340983
2025-07-23 10:45:01 -07:00
Xiang (Sean) Zhou 70266abfc2 chore: fix UT failures of test_google_llm.py
Mainly it's due to GenAI sdk changed their header of genai SDK versions, we have UT to verify that ADK or ADK users won't override their headers. Updated the header accordingly in the UT.

PiperOrigin-RevId: 786334741
2025-07-23 10:31:16 -07:00
Holt Skinner a911469616 chore: Update a2a-sdk to 0.2.16
Convert a2a types to use snake_case fields

https://github.com/a2aproject/a2a-python/releases/tag/v0.2.16

PiperOrigin-RevId: 786279179
2025-07-23 07:54:03 -07:00
Michael Timblin ce7253f63f fix: Use correct type for actions parameter in ApplicationIntegrationToolset
Merge https://github.com/google/adk-python/pull/2102

Addresses https://github.com/google/adk-python/issues/2101

I've ran `pytest ./tests/unittests`, and all tests passed

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2102 from manifoldtimblin:fix-type-hint 6d4ab724ff07688158d3d121a78b2c00493a26a7
PiperOrigin-RevId: 786046567
2025-07-22 16:49:45 -07:00
Alejandro Cruzado-Ruiz bda3df2480 feat: Refactor AgentLoader into base class and add InMemory impl alongside existing filesystem impl
PiperOrigin-RevId: 786008518
2025-07-22 14:58:32 -07:00
Ankur Sharma 4ae4c69c32 fix: ModuleNotFound error should be caught when dependencies of LocalEvalService are not installed
Once caught we publish the clarifying message to install the extra.

PiperOrigin-RevId: 785999033
2025-07-22 14:32:02 -07:00
Xiang (Sean) Zhou 32df937ebc chore: Update docstring for is_final_response method
PiperOrigin-RevId: 785983329
2025-07-22 13:50:30 -07:00
Yifan Wang 702e9bf556 chore: update adk web
PiperOrigin-RevId: 785972516
2025-07-22 13:22:34 -07:00
Ankur Sharma ff31f57dc9 fix: Move some API request and responses to DEBUG logging level
Please set --log_level to DEBUG, if you are interested in having those API request and responses in logs.

NOTE: Generally it is not recommended to have DEBUG log level for services that run in a production setting. It is our recommendation to only use DEBUG log level in a debug or development setting.
PiperOrigin-RevId: 785972338
2025-07-22 13:22:18 -07:00
Max Thormé d4f01afc15 fix(comment): fix comment to malicious user cannot obtain another user’s session
Merge https://github.com/google/adk-python/pull/1959

### What

Fix misleading comment.

```diff
- # Make sure a malicious user can obtain a session and events not belonging to them
+ # Make sure a malicious user **cannot** obtain a session or events not belonging to them
```

### Why

The previous wording contradicted the assertion `assert len(session_mismatch.events) == 0`, which verifies that a malicious user **cannot** access another user’s session or events.

### Testing plan

Docs-only change.

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1959 from mthorme:fix-comment-session-mismatch b1f139af340bd240d40ed58f5dea3274c3a3bd83
PiperOrigin-RevId: 785908548
2025-07-22 10:33:57 -07:00
Shangjie Chen f46396fa98 chore: Allow httpoptions override in VertexAiSessionService
PiperOrigin-RevId: 785886180
2025-07-22 09:36:17 -07:00
Google Team Member 13ff009d34 fix: Handle non-json-serializable values in the execute_sql tool
This change takes cares of SQL results containing values that are not json serializable (e.g. datetime, bignumeric) by converting them to their string representation.

PiperOrigin-RevId: 785719997
2025-07-21 23:17:06 -07:00
Jacky Wu 6cc3d9ddd1 chore: follow-up #946 to allow session db kwargs in fast api entrance
Merge https://github.com/google/adk-python/pull/1042

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1042 from Colstuwjx:chore/expose-database-args-in-fastapi 83a20cf400a8a712c57cb3574fdd654ab5d8d4d6
PiperOrigin-RevId: 785714547
2025-07-21 22:52:20 -07:00
Xiang (Sean) Zhou 083dcb4465 feat: Add ComputerUseToolset
PiperOrigin-RevId: 785646071
2025-07-21 18:08:35 -07:00
Xiang (Sean) Zhou b2c2f1bd33 chore: Add an a2a sample agent to demo running the a2a server via unvicorn command and run remote agent as root_agent
PiperOrigin-RevId: 785629271
2025-07-21 17:08:35 -07:00
Xiang (Sean) Zhou a77d68964a feat: Add an to_a2a util to convert adk agent to A2A ASGI application
Users can do :
```
a2a_app = to_a2a(root_agent)
```
then use below command to start a2a server:
```
uvicorn user_module:a2a_app --host localhost --port 8000
```

PiperOrigin-RevId: 785625048
2025-07-21 16:54:53 -07:00
Ankur Sharma d1f182e8e6 feat: Use LocalEvalService to run all evals in cli and web
We update both adk web run eval endpoint and adk eval cli to use the LocalService. The old method is marked as deprecated and will be removed in later PRs.

PiperOrigin-RevId: 785612708
2025-07-21 16:15:11 -07:00
Ariz Chang 0e173d7363 feat: Add camel case converter for agents
PiperOrigin-RevId: 785602954
2025-07-21 15:45:24 -07:00
Xiang (Sean) Zhou 18f5bea411 feat: Add agent card builder
PiperOrigin-RevId: 785565665
2025-07-21 13:59:02 -07:00
Jianfeng Zeng f2caf2eeca fix: Add buffer to the write file option
PiperOrigin-RevId: 785546915
2025-07-21 13:08:29 -07:00
Liang Wu dfee06ac06 feat(config): support input/output schema by fully-qualified code reference
PiperOrigin-RevId: 785541326
2025-07-21 12:53:13 -07:00
Wei Sun (Jack) 2aab1cf98e fix: allows current sub-agent to finish execution before exiting the loop agent due to a sub-agent's escalation. This commit also disables the summarization for exit_loop tool
Fixes #423

Related to #1670

- This avoids the `GeneratorExit` error thrown, which would crash OTel metric collection and cause `Failed to detach context` error.
- This also allows all function  calls are processed when exit_loop is called together with other tools in the same LLmResponse.

A sample agent for testing:

```
from google.adk import Agent
from google.adk.agents.loop_agent import LoopAgent
from google.adk.tools.exit_loop_tool import exit_loop

worker_1 = Agent(
    name='worker_1',
    description='Worker 1',
    instruction="""\
Just say job #1 is done.

If job #1 is said to be done. Call exit_loop tool.""",
    tools=[exit_loop],
)

worker_2 = Agent(
    name='worker_2',
    description='Worker 2',
    instruction="""\
Just say job #2 is done.

If job #2 is said to be done. Call exit_loop tool.""",
    tools=[exit_loop],
)

work_agent = LoopAgent(
    name='work_agent',
    description='Do all work.',
    sub_agents=[worker_1, worker_2],
    max_iterations=5,
)

root_agent = Agent(
    model='gemini-2.0-flash',
    name='hello_world_agent',
    description='hello world agent that can roll a  check prime',
    instruction="""Hand off works to sub agents.""",
    sub_agents=[work_agent],
)
```
PiperOrigin-RevId: 785538101
2025-07-21 12:43:19 -07:00
Xuan Yang 96a0d4b02c chore: undo the workaround which bypassed the setup-uv bug
Bug https://github.com/astral-sh/setup-uv/issues/489 has been fixed.

PiperOrigin-RevId: 785529944
2025-07-21 12:20:02 -07:00
Ankur Sharma 65cb6d6bf3 fix: Check that mean_score is a valid float value
In some cases, Vertex AI evaluation returns nan values for the metrics. That was not handled correctly.

PiperOrigin-RevId: 785514456
2025-07-21 11:36:55 -07:00
Ankur Sharma fc85348f91 fix: add utf-8 encoding to file based reads and writes of eval data
This will help manage encoding consistency between reads and writes.

PiperOrigin-RevId: 785503746
2025-07-21 11:09:45 -07:00
Xiang (Sean) Zhou 9467720919 chore: Remove unused import from hello world sample agent
PiperOrigin-RevId: 785501232
2025-07-21 11:03:03 -07:00
Xiang (Sean) Zhou ee3918e34e chore: Update the error message when A2A is not supported for the installed python version
PiperOrigin-RevId: 785490858
2025-07-21 10:37:33 -07:00
Vasilii Novikov 81e0d4083f feat: make GCS artifact service async under the hood
Merge https://github.com/google/adk-python/pull/1347

Fixes issue https://github.com/google/adk-python/issues/1346

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1347 from condorcet:async_gcs_artifact_storage 3efee5a923b08af606aa5525e31816e0bc7b865d
PiperOrigin-RevId: 785488472
2025-07-21 10:31:41 -07:00
Dana K. Williams 2486349268 docs: Fix missing toolbox-core dependency and improve installation guide
Merge https://github.com/google/adk-python/pull/1195

## Summary
Updated the Toolbox Agent documentation to address a critical missing dependency that prevents the agent from running successfully.

## Changes Made
- **Added missing dependency**: Documented that `toolbox-core` must be installed via `pip install toolbox-core`
- **Improved documentation structure**: Added clear section numbering and better organization
- **Enhanced readability**: Fixed grammar, capitalization, and formatting throughout
- **Added Prerequisites section**: Set clear expectations before installation begins
- **Clarified optional steps**: Made it clearer when database creation can be skipped

## Problem Solved
The original documentation was missing a crucial step - installing the `toolbox-core` package. Without this dependency, users encounter an `ImportError: No module named 'toolbox-core'` when trying to use the `ToolboxToolset` class in ADK. This fix ensures users can successfully set up and run the agent without encountering import errors.

## Testing
- Verified the installation steps work correctly with the added dependency
- Confirmed the agent runs successfully after following the updated documentation

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1195 from designcomputer:patch-1 b90c71fe95aa09a3dca069e91f14791f557ab2e3
PiperOrigin-RevId: 785487495
2025-07-21 10:29:33 -07:00
Xiang (Sean) Zhou 3643b4ae19 feat: Allow toolset to process llm_request before tools returned by it
PiperOrigin-RevId: 785480813
2025-07-21 10:11:40 -07:00
Xiang (Sean) Zhou cec400ada3 chore: Autoformat history_management agent codes
PiperOrigin-RevId: 785003632
2025-07-19 17:51:54 -07:00
Google Team Member d2461ecccb refactor: only import some module when needed and add follow_symlink=True when serve static files
PiperOrigin-RevId: 784956132
2025-07-19 12:54:05 -07:00
Calvin Giles ffe2bdbe4c feat: Add support for vertex gemini model optimizer
Merge https://github.com/google/adk-python/pull/1130

This enables the use of the `model-optimizer-*` family of models in vertex, as per the [documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/vertex-ai-model-optimizer#using-vertex-ai-model-optimizer).

To use this, ensure your location is set to `global` and pass a model optimizer model to an agent:

```python
root_agent = Agent(
    model="model-optimizer-exp-04-09",
    name="fast_and_slow_agent",
    instruction="Answer any question the user gives you - easy or hard.",
    generate_content_config=types.GenerateContentConfig(
        temperature=0.01,
        model_selection_config=ModelSelectionConfig(
            feature_selection_preference=FeatureSelectionPreference.BALANCED
            # Options: PRIORITIZE_QUALITY, BALANCED, PRIORITIZE_COST
        )
    ),
)
```
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1130 from calvingiles:feat-model-optimizer 1a76bfa22420edb07d83415dcea6dd0114084e8e
PiperOrigin-RevId: 784921913
2025-07-19 09:05:17 -07:00
Calvin Giles 67284fc466 feat: History Management Sample
Merge https://github.com/google/adk-python/pull/891

This creates a sample relating to discussion #826 - how to manage context windows.

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/891 from calvingiles:history-management-sample 2827817bea8d96ea0eee7e3ba84c14bd1fe4286d
PiperOrigin-RevId: 784920438
2025-07-19 08:57:11 -07:00
Hangfei Lin 0ec69d05a4 feat: Enhance LangchainTool to accept more forms of functions
Now the LangchainTool can wrap:

* Langchain StructuredTool (sync and async).
* Langchain @Tool (sync and async).

This enhance the flexibility for user and enables async functionalities.

PiperOrigin-RevId: 784728061
2025-07-18 15:56:17 -07:00
Hangfei Lin f1e0bc0b18 chore: remove pr-commit-check
With this mode, the PR commit can be squashed before copybara. So we can delete the pr-commit-check.yml.

PiperOrigin-RevId: 784665025
2025-07-18 12:26:46 -07:00
Liang Wu 5edc493da9 chore: allow "from google.adk.tools import AgentTool"
PiperOrigin-RevId: 784606041
2025-07-18 09:30:40 -07:00
Copybara-Service 3568c9291d Merge pull request #547 from jeffreyrubi:fix/missing-path-level-parameters
PiperOrigin-RevId: 784415343
2025-07-17 20:27:46 -07:00
Copybara-Service d0a330cd15 Merge pull request #2020 from thiagosalvatore:main
PiperOrigin-RevId: 784393522
2025-07-17 18:50:46 -07:00
seanzhou1023 637fa410d8 Merge branch 'main' into main 2025-07-17 18:23:32 -07:00
Sean Zhou 6f016609e8 fix: support path level parameters for open_api_spec_parser
autoformat the changes
2025-07-17 18:09:40 -07:00
Hangfei Lin bb1b1c695f Merge branch 'main' into fix/missing-path-level-parameters 2025-07-17 17:46:27 -07:00
Wei Sun (Jack) bb4ff2cc3d chore: fixes formatting in adk_project_overview_and_architecture.md
PiperOrigin-RevId: 784371131
2025-07-17 17:21:14 -07:00
Wei Sun (Jack) b1f4aebb25 chore: lint fixings in vertex_ai_memory_bank.py
* Adds type hints;
* Switches to lazy evaluation in logs.

PiperOrigin-RevId: 784353566
2025-07-17 16:21:49 -07:00
Shangjie Chen 2e778049d0 feat: Support passing fully qualified agent engine resource name when constructing session service and memory service
Resolves https://github.com/google/adk-python/issues/1760

PiperOrigin-RevId: 784353411
2025-07-17 16:19:55 -07:00
Ankur Sharma 36e45cdab3 feat: Enable FinalResponseMatchV2 metric as an experiment
PiperOrigin-RevId: 784346859
2025-07-17 15:59:47 -07:00
Xuan Yang 35de210d4e chore: add a script to upload ADK docs for the ADK Answering Agent
PiperOrigin-RevId: 784343501
2025-07-17 15:49:44 -07:00
Xuan Yang bbe1c9dc66 fix: specify version into the uv installation action to bypass the setup-uv bug
https://github.com/astral-sh/setup-uv/issues/489

PiperOrigin-RevId: 784339143
2025-07-17 15:35:15 -07:00
Thiago Salvatore 9ad4350c88 Merge branch 'main' of github.com:thiagosalvatore/adk-python 2025-07-17 18:21:59 -03:00
Thiago Salvatore 2f8bb91e6b add docstring 2025-07-17 18:21:40 -03:00
Thiago Salvatore 3f01c8c999 Merge branch 'main' into main 2025-07-17 18:20:37 -03:00
Thiago Salvatore b5850e0757 reformat file structure 2025-07-17 18:17:09 -03:00
Thiago Salvatore 53df35ee58 fix(schema to dict): fix serialization of tools with nested schema 2025-07-17 18:16:17 -03:00
Xuan Yang 6e68c2d7f3 chore: update ADK Triage Agent to set issue type
It will change bug report to "Bug" type and feature request to "Feature" type.

PiperOrigin-RevId: 784280674
2025-07-17 12:51:41 -07:00
Xuan Yang 8ada46a18e chore: remove the redundant service.bucket setting in mock_gcs_artifact_service
PiperOrigin-RevId: 784253138
2025-07-17 11:29:32 -07:00
Xuan Yang 1c4c887bec fix: use the same word extractor for query and event contents in InMemoryMemoryService
PiperOrigin-RevId: 784236637
2025-07-17 10:43:01 -07:00
Xuan Yang 78697aa6af chore: add to_session method in StorageSession for readability
PiperOrigin-RevId: 784232578
2025-07-17 10:32:18 -07:00
Ankur Sharma b17d8b6e36 fix: Raise NotFoundError in list_eval_sets function when app_name doesn't exist
PiperOrigin-RevId: 784216832
2025-07-17 09:53:26 -07:00
Xiang (Sean) Zhou 377b5a9b78 fix: Add response schema for agent tool function declaration even when it's return None
PiperOrigin-RevId: 784216811
2025-07-17 09:51:34 -07:00
Xiang (Sean) Zhou 33ac8380ad fix: Set response schema for function that returns None
PiperOrigin-RevId: 784053725
2025-07-16 23:59:45 -07:00
Jianfeng Zeng 31fa5d91bd feat: Update builder/save endpoint to accept files as input. Write the agent yaml file to the agent folder
PiperOrigin-RevId: 783963934
2025-07-16 17:55:55 -07:00
Xuan Yang b705b35977 fix: update documentation owner's Github username for the ADK Triage Agent
PiperOrigin-RevId: 783951115
2025-07-16 17:10:25 -07:00
Shangjie Chen eccb484985 chore: Update label name for bot triaged issues
Also assign agent engine related issue to yeesian as poc

PiperOrigin-RevId: 783941809
2025-07-16 16:39:25 -07:00
Hangfei Lin aabfde56e4 Merge branch 'main' into fix/missing-path-level-parameters 2025-05-30 11:33:24 -07:00
Jeffrey Mak f2b9e72f82 Merge branch 'main' into fix/missing-path-level-parameters 2025-05-17 16:57:00 -04:00
Jeffrey Mak 3263a97999 Merge branch 'main' into fix/missing-path-level-parameters 2025-05-14 10:57:06 -04:00
Jeffrey Mak 36866935a3 Merge branch 'main' into fix/missing-path-level-parameters 2025-05-09 19:21:46 -04:00
kmak de238eeab1 fix: unittest for path-level parameters case 2025-05-09 19:20:59 -04:00
Jeffrey Mak 84579cab56 Merge branch 'main' into fix/missing-path-level-parameters 2025-05-04 08:51:14 -04:00
kmak 34b001292a fix: support path level parameters for open_api_spec_parser 2025-05-04 08:50:02 -04:00
309 changed files with 22639 additions and 3273 deletions
@@ -0,0 +1,44 @@
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
- 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
OWNER: 'google'
REPO: 'adk-python'
INTERACTIVE: 0
DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
PYTHONPATH: contributing/samples
run: python -m adk_answering_agent.main
-62
View File
@@ -1,62 +0,0 @@
# .github/workflows/pr-commit-check.yml
# This GitHub Action workflow checks if a pull request has more than one commit.
# If it does, it fails the check and instructs the user to squash their commits.
name: 'PR Commit Check'
# This workflow runs on pull request events.
# It's configured to run on any pull request that is opened or synchronized (new commits pushed).
on:
pull_request:
types: [opened, synchronize]
# Defines the jobs that will run as part of the workflow.
jobs:
check-commit-count:
# The type of runner that the job will run on. 'ubuntu-latest' is a good default.
runs-on: ubuntu-latest
# The steps that will be executed as part of the job.
steps:
# Step 1: Check out the code
# This action checks out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
- name: Checkout Code
uses: actions/checkout@v4
with:
# We need to fetch all commits to accurately count them.
# '0' means fetch all history for all branches and tags.
fetch-depth: 0
# Step 2: Count the commits in the pull request
# This step runs a script to get the number of commits in the PR.
- name: Count Commits
id: count_commits
# We use `git rev-list --count` to count the commits.
# ${{ github.event.pull_request.base.sha }} is the commit SHA of the base branch.
# ${{ github.event.pull_request.head.sha }} is the commit SHA of the head branch (the PR branch).
# The '..' syntax gives us the list of commits in the head branch that are not in the base branch.
# The output of the command (the count) is stored in a step output variable named 'count'.
run: |
count=$(git rev-list --count ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }})
echo "commit_count=$count" >> $GITHUB_OUTPUT
# Step 3: Check if the commit count is greater than 1
# This step uses the output from the previous step to decide whether to pass or fail.
- name: Check Commit Count
# This step only runs if the 'commit_count' output from the 'count_commits' step is greater than 1.
if: steps.count_commits.outputs.commit_count > 1
# If the condition is met, the workflow will exit with a failure status.
run: |
echo "This pull request has ${{ steps.count_commits.outputs.commit_count }} commits."
echo "Please squash them into a single commit before merging."
echo "You can use git rebase -i HEAD~N"
echo "...where N is the number of commits you want to squash together. The PR check conveniently tells you this number! For example, if the check says you have 3 commits, you would run: git rebase -i HEAD~3."
echo "Because you have rewritten the commit history, you must use the --force flag to update the pull request: git push --force"
exit 1
# Step 4: Success message
# This step runs if the commit count is not greater than 1 (i.e., it's 1).
- name: Success
if: steps.count_commits.outputs.commit_count <= 1
run: |
echo "This pull request has a single commit. Great job!"
+38
View File
@@ -0,0 +1,38 @@
name: ADK Pull Request Triaging Agent
on:
pull_request_target:
types: [opened, reopened, edited]
jobs:
agent-triage-pull-request:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests google-adk
- name: Run Triaging Script
env:
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
GOOGLE_GENAI_USE_VERTEXAI: 0
OWNER: 'google'
REPO: 'adk-python'
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
INTERACTIVE: ${{ vars.PR_TRIAGE_INTERACTIVE }}
PYTHONPATH: contributing/samples
run: python -m adk_pr_triaging_agent.main
+113
View File
@@ -1,5 +1,118 @@
# Changelog
## [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)
### Features
* [CLI] Add `-v`, `--verbose` flag to enable DEBUG logging as a shortcut for `--log_level DEBUG` ([3be0882](https://github.com/google/adk-python/commit/3be0882c63bf9b185c34bcd17e03769b39f0e1c5))
* [CLI] Add a CLI option to update an agent engine instance ([206a132](https://github.com/google/adk-python/commit/206a13271e5f1bb0bb8114b3bb82f6ec3f030cd7))
* [CLI] Modularize fast_api.py to allow simpler construction of API Server ([bfc203a](https://github.com/google/adk-python/commit/bfc203a92fdfbc4abaf776e76dca50e7ca59127b), [dfc25c1](https://github.com/google/adk-python/commit/dfc25c17a98aaad81e1e2f140db83d17cd78f393), [e176f03](https://github.com/google/adk-python/commit/e176f03e8fe13049187abd0f14e63afca9ccff01))
* [CLI] Refactor AgentLoader into base class and add InMemory impl alongside existing filesystem impl ([bda3df2](https://github.com/google/adk-python/commit/bda3df24802d0456711a5cd05544aea54a13398d))
* [CLI] Respect the .ae_ignore file when deploying to agent engine ([f29ab5d](https://github.com/google/adk-python/commit/f29ab5db0563a343d6b8b437a12557c89b7fc98b))
* [Core] Add new callbacks to handle tool and model errors ([00afaaf](https://github.com/google/adk-python/commit/00afaaf2fc18fba85709754fb1037bb47f647243))
* [Core] Add sample plugin for logging ([20537e8](https://github.com/google/adk-python/commit/20537e8bfa31220d07662dad731b4432799e1802))
* [Core] Expose Gemini RetryOptions to client ([1639298](https://github.com/google/adk-python/commit/16392984c51b02999200bd4f1d6781d5ec9054de))
* [Evals] Added an Fast API new endpoint to serve eval metric info ([c69dcf8](https://github.com/google/adk-python/commit/c69dcf87795c4fa2ad280b804c9b0bd3fa9bf06f))
* [Evals] Refactored AgentEvaluator and updated it to use LocalEvalService ([1355bd6](https://github.com/google/adk-python/commit/1355bd643ba8f7fd63bcd6a7284cc48e325d138e))
### Bug Fixes
* Add absolutize_imports option when deploying to agent engine ([fbe6a7b](https://github.com/google/adk-python/commit/fbe6a7b8d3a431a1d1400702fa534c3180741eb3))
* Add space to allow adk deploy cloud_run --a2a ([70c4616](https://github.com/google/adk-python/commit/70c461686ec2c60fcbaa384a3f1ea2528646abba))
* Copy the original function call args before passing it to callback or tools to avoid being modified ([3432b22](https://github.com/google/adk-python/commit/3432b221727b52af2682d5bf3534d533a50325ef))
* Eval module not found exception string ([7206e0a](https://github.com/google/adk-python/commit/7206e0a0eb546a66d47fb411f3fa813301c56f42))
* Fix incorrect token count mapping in telemetry ([c8f8b4a](https://github.com/google/adk-python/commit/c8f8b4a20a886a17ce29abd1cfac2858858f907d))
* Import cli's artifact dependencies directly ([282d67f](https://github.com/google/adk-python/commit/282d67f253935af56fae32428124a385f812c67d))
* Keep existing header values while merging tracking headers for `llm_request.config.http_options` in `Gemini.generate_content_async` ([6191412](https://github.com/google/adk-python/commit/6191412b07c3b5b5a58cf7714e475f63e89be847))
* Merge tracking headers even when `llm_request.config.http_options` is not set in `Gemini.generate_content_async` ([ec8dd57](https://github.com/google/adk-python/commit/ec8dd5721aa151cfc033cc3aad4733df002ae9cb))
* Restore bigquery sample agent to runnable form ([16e8419](https://github.com/google/adk-python/commit/16e8419e32b54298f782ba56827e5139effd8780))
* Return session state in list_session API endpoint ([314d6a4](https://github.com/google/adk-python/commit/314d6a4f95c6d37c7da3afbc7253570564623322))
* Runner was expecting Event object instead of Content object when using early exist feature ([bf72426](https://github.com/google/adk-python/commit/bf72426af2bfd5c2e21c410005842e48b773deb3))
* Unable to acquire impersonated credentials ([9db5d9a](https://github.com/google/adk-python/commit/9db5d9a3e87d363c1bac0f3d8e45e42bd5380d3e))
* Update `agent_card_builder` to follow grammar rules ([9c0721b](https://github.com/google/adk-python/commit/9c0721beaa526a4437671e6cc70915073be835e3)), closes [#2223](https://github.com/google/adk-python/issues/2223)
* Use correct type for actions parameter in ApplicationIntegrationToolset ([ce7253f](https://github.com/google/adk-python/commit/ce7253f63ff8e78bccc7805bd84831f08990b881))
### Documentation
* Update documents about the information of vibe coding ([0c85587](https://github.com/google/adk-python/commit/0c855877c57775ad5dad930594f9f071164676da))
## [1.8.0](https://github.com/google/adk-python/compare/v1.7.0...v1.8.0) (2025-07-23)
### Features
* [Core]Add agent card builder ([18f5bea](https://github.com/google/adk-python/commit/18f5bea411b3b76474ff31bfb2f62742825b45e5))
* [Core]Add an to_a2a util to convert adk agent to A2A ASGI application ([a77d689](https://github.com/google/adk-python/commit/a77d68964a1c6b7659d6117d57fa59e43399e0c2))
* [Core]Add camel case converter for agents ([0e173d7](https://github.com/google/adk-python/commit/0e173d736334f8c6c171b3144ac6ee5b7125c846))
* [Evals]Use LocalEvalService to run all evals in cli and web ([d1f182e](https://github.com/google/adk-python/commit/d1f182e8e68c4a5a4141592f3f6d2ceeada78887))
* [Evals]Enable FinalResponseMatchV2 metric as an experiment ([36e45cd](https://github.com/google/adk-python/commit/36e45cdab3bbfb653eee3f9ed875b59bcd525ea1))
* [Models]Add support for `model-optimizer-*` family of models in vertex ([ffe2bdb](https://github.com/google/adk-python/commit/ffe2bdbe4c2ea86cc7924eb36e8e3bb5528c0016))
* [Services]Added a sample for History Management ([67284fc](https://github.com/google/adk-python/commit/67284fc46667b8c2946762bc9234a8453d48a43c))
* [Services]Support passing fully qualified agent engine resource name when constructing session service and memory service ([2e77804](https://github.com/google/adk-python/commit/2e778049d0a675e458f4e
35fe4104ca1298dbfcf))
* [Tools]Add ComputerUseToolset ([083dcb4](https://github.com/google/adk-python/commit/083dcb44650eb0e6b70219ede731f2fa78ea7d28))
* [Tools]Allow toolset to process llm_request before tools returned by it ([3643b4a](https://github.com/google/adk-python/commit/3643b4ae196fd9e38e52d5dc9d1cd43ea0733d36))
* [Tools]Support input/output schema by fully-qualified code reference ([dfee06a](https://github.com/google/adk-python/commit/dfee06ac067ea909251d6fb016f8331065d430e9))
* [Tools]Enhance LangchainTool to accept more forms of functions ([0ec69d0](https://github.com/google/adk-python/commit/0ec69d05a4016adb72abf9c94f2e9ff4bdd1848c))
### Bug Fixes
* **Attention**: Logging level for some API requests and responses was moved from `INFO` to `DEBUG` ([ff31f57](https://github.com/google/adk-python/commit/ff31f57dc95149f8f309f83f2ec983ef40f1122c))
* Please set `--log_level=DEBUG`, if you are interested in having those API request and responses in logs.
* Add buffer to the write file option ([f2caf2e](https://github.com/google/adk-python/commit/f2caf2eecaf0336495fb42a2166b1b79e57d82d8))
* Allow current sub-agent to finish execution before exiting the loop agent due to a sub-agent's escalation. ([2aab1cf](https://github.com/google/adk-python/commit/2aab1cf98e1d0e8454764b549fac21475a633409))
* Check that `mean_score` is a valid float value ([65cb6d6](https://github.com/google/adk-python/commit/65cb6d6bf3278e6c3529938a7b932e3ef6d6c2ae))
* Handle non-json-serializable values in the `execute_sql` tool ([13ff009](https://github.com/google/adk-python/commit/13ff009d34836a80f107cb43a632df15f7c215e4))
* Raise `NotFoundError` in `list_eval_sets` function when app_name doesn't exist ([b17d8b6](https://github.com/google/adk-python/commit/b17d8b6e362a5b2a1b6a2dd0cff5e27a71c27925))
* Fixed serialization of tools with nested schema ([53df35e](https://github.com/google/adk-python/commit/53df35ee58599e9816bd4b9c42ff48457505e599))
* Set response schema for function tools that returns `None` ([33ac838](https://github.com/google/adk-python/commit/33ac8380adfff46ed8a7d518ae6f27345027c074))
* Support path level parameters for open_api_spec_parser ([6f01660](https://github.com/google/adk-python/commit/6f016609e889bb0947877f478de0c5729cfcd0c3))
* Use correct type for actions parameter in ApplicationIntegrationToolset ([ce7253f](https://github.com/google/adk-python/commit/ce7253f63ff8e78bccc7805bd84831f08990b881))
* Use the same word extractor for query and event contents in InMemoryMemoryService ([1c4c887](https://github.com/google/adk-python/commit/1c4c887bec9326aad2593f016540160d95d03f33))
### Documentation
* Fix missing toolbox-core dependency and improve installation guide ([2486349](https://github.com/google/adk-python/commit/24863492689f36e3c7370be40486555801858bac))
## 1.7.0 (2025-07-16)
### Features
+4
View File
@@ -210,3 +210,7 @@ All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
# Vibe Coding
If you want to contribute by leveraging viber coding, the AGENTS.md (https://github.com/google/adk-python/tree/main/AGENTS.md) could be used as context to your LLM.
+4
View File
@@ -138,6 +138,10 @@ We welcome contributions from the community! Whether it's bug reports, feature r
- [General contribution guideline and flow](https://google.github.io/adk-docs/contributing-guide/).
- Then if you want to contribute code, please read [Code Contributing Guidelines](./CONTRIBUTING.md) to get started.
## Vibe Coding
If you are to develop agent via vibe coding the [llms.txt](./llms.txt) and the [llms-full.txt](./llms-full.txt) can be used as context to LLM. While the former one is a summarized one and the later one has the full information in case your LLM has big enough context window.
## 📄 License
This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details.
@@ -28,20 +28,22 @@ Google Agent Development Kit (ADK) for Python
Adhere to this structure for compatibility with ADK tooling.
my_adk_project/ \
└── src/ \
└── my_app/ \
├── agents/ \
├── my_agent/ \
```
my_adk_project/
└── src/
└── my_app/
├── agents/
│ ├── my_agent/
│ │ ├── __init__.py # Must contain: from. import agent \
│ │ └── agent.py # Must contain: root_agent = Agent(...) \
│ └── another_agent/ \
│ ├── __init__.py \
│ └── another_agent/
│ ├── __init__.py
│ └── agent.py\
```
agent.py: Must define the agent and assign it to a variable named root_agent. This is how ADK's tools find it.
__init__.py: In each agent directory, it must contain from. import agent to make the agent discoverable.
`__init__.py`: In each agent directory, it must contain from. import agent to make the agent discoverable.
## Local Development & Debugging
@@ -108,4 +110,3 @@ Test Cases: Create JSON files with input and a reference (expected tool calls an
Metrics: tool_trajectory_avg_score (does it use tools correctly?) and response_match_score (is the final answer good?).
Run via: adk web (UI), pytest (for CI/CD), or adk eval (CLI).
+2 -2
View File
@@ -13,11 +13,11 @@
# limitations under the License.
from google.adk.agents import Agent
from google.adk.agents.llm_agent import Agent
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.adk.tools.langchain_tool import LangchainTool
from langchain_community.tools import YouTubeSearchTool
from langchain_community.tools.youtube.search import YouTubeSearchTool
# Instantiate the tool
langchain_yt_tool = YouTubeSearchTool()
+1 -1
View File
@@ -14,7 +14,7 @@
import random
from google.adk.agents import Agent
from google.adk.agents.llm_agent import Agent
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.adk.tools.example_tool import ExampleTool
@@ -13,7 +13,7 @@
# limitations under the License.
from google.adk import Agent
from google.adk.agents.llm_agent import Agent
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.genai import types
@@ -15,8 +15,8 @@
from typing import Any
from google.adk import Agent
from google.adk.tools import ToolContext
from google.adk.tools.long_running_tool import LongRunningFunctionTool
from google.adk.tools.tool_context import ToolContext
from google.genai import types
+123
View File
@@ -0,0 +1,123 @@
# A2A Root Sample Agent
This sample demonstrates how to use a **remote Agent-to-Agent (A2A) agent as the root agent** in the Agent Development Kit (ADK). This is a simplified approach where the main agent is actually a remote A2A service, also showcasing how to run remote agents using uvicorn command.
## Overview
The A2A Root sample consists of:
- **Root Agent** (`agent.py`): A remote A2A agent proxy as root agent that talks to a remote a2a agent running on a separate server
- **Remote Hello World Agent** (`remote_a2a/hello_world/agent.py`): The actual agent implementation that handles dice rolling and prime number checking running on remote server
## Architecture
```
┌─────────────────┐ ┌────────────────────┐
│ Root Agent │───▶│ Remote Hello │
│ (RemoteA2aAgent)│ │ World Agent │
│ (localhost:8000)│ │ (localhost:8001) │
└─────────────────┘ └────────────────────┘
```
## Key Features
### 1. **Remote A2A as Root Agent**
- The `root_agent` is a `RemoteA2aAgent` that connects to a remote A2A service
- Demonstrates how to use remote agents as the primary agent instead of local agents
- Shows the flexibility of the A2A architecture for distributed agent deployment
### 2. **Uvicorn Server Deployment**
- The remote agent is served using uvicorn, a lightweight ASGI server
- Demonstrates a simple way to deploy A2A agents without using the ADK CLI
- Shows how to expose A2A agents as standalone web services
### 3. **Agent Functionality**
- **Dice Rolling**: Can roll dice with configurable number of sides
- **Prime Number Checking**: Can check if numbers are prime
- **State Management**: Maintains roll history in tool context
- **Parallel Tool Execution**: Can use multiple tools in parallel
### 4. **Simple Deployment Pattern**
- Uses the `to_a2a()` utility to convert a standard ADK agent to an A2A service
- Minimal configuration required for remote agent deployment
## Setup and Usage
### Prerequisites
1. **Start the Remote A2A Agent server**:
```bash
# Start the remote agent using uvicorn
uvicorn contributing.samples.a2a_root.remote_a2a.hello_world.agent:a2a_app --host localhost --port 8001
```
2. **Run the Main Agent**:
```bash
# In a separate terminal, run the adk web server
adk web contributing/samples/
```
### Example Interactions
Once both services are running, you can interact with the root agent:
**Simple Dice Rolling:**
```
User: Roll a 6-sided die
Bot: I rolled a 4 for you.
```
**Prime Number Checking:**
```
User: Is 7 a prime number?
Bot: Yes, 7 is a prime number.
```
**Combined Operations:**
```
User: Roll a 10-sided die and check if it's prime
Bot: I rolled an 8 for you.
Bot: 8 is not a prime number.
```
**Multiple Rolls with Prime Checking:**
```
User: Roll a die 3 times and check which results are prime
Bot: I rolled a 3 for you.
Bot: I rolled a 7 for you.
Bot: I rolled a 4 for you.
Bot: 3, 7 are prime numbers.
```
## Code Structure
### Root Agent (`agent.py`)
- **`root_agent`**: A `RemoteA2aAgent` that connects to the remote A2A service
- **Agent Card URL**: Points to the well-known agent card endpoint on the remote server
### Remote Hello World Agent (`remote_a2a/hello_world/agent.py`)
- **`roll_die(sides: int)`**: Function tool for rolling dice with state management
- **`check_prime(nums: list[int])`**: Async function for prime number checking
- **`root_agent`**: The main agent with comprehensive instructions
- **`a2a_app`**: The A2A application created using `to_a2a()` utility
## Troubleshooting
**Connection Issues:**
- Ensure the uvicorn server is running on port 8001
- Check that no firewall is blocking localhost connections
- Verify the agent card URL in the root agent configuration
- Check uvicorn logs for any startup errors
**Agent Not Responding:**
- Check the uvicorn server logs for errors
- Verify the agent instructions are clear and unambiguous
- Ensure the A2A app is properly configured with the correct port
**Uvicorn Issues:**
- Make sure the module path is correct: `contributing.samples.a2a_root.remote_a2a.hello_world.agent:a2a_app`
- Check that all dependencies are installed
+24
View File
@@ -0,0 +1,24 @@
# 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 google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
root_agent = RemoteA2aAgent(
name="hello_world_agent",
description=(
"Helpful assistant that can roll dice and check if numbers are prime."
),
agent_card=f"http://localhost:8001/{AGENT_CARD_WELL_KNOWN_PATH}",
)
@@ -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,111 @@
# 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 random
from google.adk import Agent
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from google.adk.tools.tool_context import ToolContext
from google.genai import types
def roll_die(sides: int, tool_context: ToolContext) -> int:
"""Roll a die and return the rolled result.
Args:
sides: The integer number of sides the die has.
tool_context: the tool context
Returns:
An integer of the result of rolling the die.
"""
result = random.randint(1, sides)
if not 'rolls' in tool_context.state:
tool_context.state['rolls'] = []
tool_context.state['rolls'] = tool_context.state['rolls'] + [result]
return result
async def check_prime(nums: list[int]) -> str:
"""Check if a given list of numbers are prime.
Args:
nums: The list of numbers to check.
Returns:
A str indicating which number is prime.
"""
primes = set()
for number in nums:
number = int(number)
if number <= 1:
continue
is_prime = True
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
is_prime = False
break
if is_prime:
primes.add(number)
return (
'No prime numbers found.'
if not primes
else f"{', '.join(str(num) for num in primes)} are prime numbers."
)
root_agent = Agent(
model='gemini-2.0-flash',
name='hello_world_agent',
description=(
'hello world agent that can roll a dice of 8 sides and check prime'
' numbers.'
),
instruction="""
You roll dice and answer questions about the outcome of the dice rolls.
You can roll dice of different sizes.
You can use multiple tools in parallel by calling functions in parallel(in one request and in one round).
It is ok to discuss previous dice roles, and comment on the dice rolls.
When you are asked to roll a die, you must call the roll_die tool with the number of sides. Be sure to pass in an integer. Do not pass in a string.
You should never roll a die on your own.
When checking prime numbers, call the check_prime tool with a list of integers. Be sure to pass in a list of integers. You should never pass in a string.
You should not check prime numbers before calling the tool.
When you are asked to roll a die and check prime numbers, you should always make the following two function calls:
1. You should first call the roll_die tool to get a roll. Wait for the function response before calling the check_prime tool.
2. After you get the function response from roll_die tool, you should call the check_prime tool with the roll_die result.
2.1 If user asks you to check primes based on previous rolls, make sure you include the previous rolls in the list.
3. When you respond, you must include the roll_die result from step 1.
You should always perform the previous 3 steps when asking for a roll and checking prime numbers.
You should not rely on the previous history on prime results.
""",
tools=[
roll_die,
check_prime,
],
# planner=BuiltInPlanner(
# thinking_config=types.ThinkingConfig(
# include_thoughts=True,
# ),
# ),
generate_content_config=types.GenerateContentConfig(
safety_settings=[
types.SafetySetting( # avoid false alarm about rolling dice.
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.OFF,
),
]
),
)
a2a_app = to_a2a(root_agent, port=8001)
@@ -2,7 +2,11 @@
The ADK Answering Agent is a Python-based agent designed to help answer questions in GitHub discussions for the `google/adk-python` repository. It uses a large language model to analyze open discussions, retrieve information from document store, generate response, and post a comment in the github discussion.
This agent can be operated in three distinct modes: an interactive mode for local use, a batch script mode for oncall use, or as a fully automated GitHub Actions workflow (TBD).
This agent can be operated in three distinct modes:
- An interactive mode for local use.
- A batch script mode for oncall use.
- A fully automated GitHub Actions workflow (TBD).
---
@@ -50,6 +54,15 @@ The `main.py` is reserved for the Github Workflow. The detailed setup for the au
---
## Update the Knowledge Base
The `upload_docs_to_vertex_ai_search.py` is a script to upload ADK related docs to Vertex AI Search datastore to update the knowledge base. It can be executed with the following command in your terminal:
```bash
export PYTHONPATH=contributing/samples # If not already exported
python -m adk_answering_agent.upload_docs_to_vertex_ai_search
```
## Setup and Configuration
Whether running in interactive or workflow mode, the agent requires the following setup.
@@ -59,7 +72,7 @@ The agent requires the following Python libraries.
```bash
pip install --upgrade pip
pip install google-adk requests
pip install google-adk
```
The agent also requires gcloud login:
@@ -68,6 +81,12 @@ The agent also requires gcloud login:
gcloud auth application-default login
```
The upload script requires the following additional Python libraries.
```bash
pip install google-cloud-storage google-cloud-discoveryengine
```
### Environment Variables
The following environment variables are required for the agent to connect to the necessary services.
@@ -75,9 +94,15 @@ The following environment variables are required for the agent to connect to the
* `GOOGLE_GENAI_USE_VERTEXAI=TRUE`: **(Required)** Use Google Vertex AI for the authentication.
* `GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID`: **(Required)** The Google Cloud project ID.
* `GOOGLE_CLOUD_LOCATION=LOCATION`: **(Required)** The Google Cloud region.
* `VERTEXAI_DATASTORE_ID=YOUR_DATASTORE_ID`: **(Required)** The Vertex AI datastore ID for the document store (i.e. knowledge base).
* `VERTEXAI_DATASTORE_ID=YOUR_DATASTORE_ID`: **(Required)** The full Vertex AI datastore ID for the document store (i.e. knowledge base), with the format of `projects/{project_number}/locations/{location}/collections/{collection}/dataStores/{datastore_id}`.
* `OWNER`: The GitHub organization or username that owns the repository (e.g., `google`). Needed for both modes.
* `REPO`: The name of the GitHub repository (e.g., `adk-python`). Needed for both modes.
* `INTERACTIVE`: Controls the agent's interaction mode. For the automated workflow, this is set to `0`. For interactive mode, it should be set to `1` or left unset.
The following environment variables are required to upload the docs to update the knowledge base.
* `GCS_BUCKET_NAME=YOUR_GCS_BUCKET_NAME`: **(Required)** The name of the GCS bucket to store the documents.
* `ADK_DOCS_ROOT_PATH=YOUR_ADK_DOCS_ROOT_PATH`: **(Required)** Path to the root of the downloaded adk-docs repo.
* `ADK_PYTHON_ROOT_PATH=YOUR_ADK_PYTHON_ROOT_PATH`: **(Required)** Path to the root of the downloaded adk-python repo.
For local execution in interactive mode, you can place these variables in a `.env` file in the project's root directory. For the GitHub workflow, they should be configured as repository secrets.
@@ -21,8 +21,8 @@ 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 google.adk.agents import Agent
from google.adk.tools import VertexAiSearchTool
from google.adk.agents.llm_agent import Agent
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
import requests
if IS_INTERACTIVE:
@@ -137,6 +137,12 @@ def add_comment_to_discussion(
}
}
"""
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)
@@ -247,10 +253,8 @@ root_agent = Agent(
* {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>".
* 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.
@@ -29,9 +29,14 @@ VERTEXAI_DATASTORE_ID = os.getenv("VERTEXAI_DATASTORE_ID")
if not VERTEXAI_DATASTORE_ID:
raise ValueError("VERTEXAI_DATASTORE_ID environment variable not set")
GOOGLE_CLOUD_PROJECT = os.getenv("GOOGLE_CLOUD_PROJECT")
GCS_BUCKET_NAME = os.getenv("GCS_BUCKET_NAME")
ADK_DOCS_ROOT_PATH = os.getenv("ADK_DOCS_ROOT_PATH")
ADK_PYTHON_ROOT_PATH = os.getenv("ADK_PYTHON_ROOT_PATH")
OWNER = os.getenv("OWNER", "google")
REPO = os.getenv("REPO", "adk-python")
BOT_RESPONSE_LABEL = os.getenv("BOT_RESPONSE_LABEL", "bot_responded")
BOT_RESPONSE_LABEL = os.getenv("BOT_RESPONSE_LABEL", "bot responded")
DISCUSSION_NUMBER = os.getenv("DISCUSSION_NUMBER")
IS_INTERACTIVE = os.getenv("INTERACTIVE", "1").lower() in ["true", "1"]
@@ -0,0 +1,222 @@
# 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 os
import sys
from adk_answering_agent.settings import ADK_DOCS_ROOT_PATH
from adk_answering_agent.settings import ADK_PYTHON_ROOT_PATH
from adk_answering_agent.settings import GCS_BUCKET_NAME
from adk_answering_agent.settings import GOOGLE_CLOUD_PROJECT
from adk_answering_agent.settings import VERTEXAI_DATASTORE_ID
from google.api_core.exceptions import GoogleAPICallError
from google.cloud import discoveryengine_v1beta as discoveryengine
from google.cloud import storage
import markdown
GCS_PREFIX_TO_ROOT_PATH = {
"adk-docs": ADK_DOCS_ROOT_PATH,
"adk-python": ADK_PYTHON_ROOT_PATH,
}
def cleanup_gcs_prefix(project_id: str, bucket_name: str, prefix: str) -> bool:
"""Delete all the objects with the given prefix in the bucket."""
print(f"Start cleaning up GCS: gs://{bucket_name}/{prefix}...")
try:
storage_client = storage.Client(project=project_id)
bucket = storage_client.bucket(bucket_name)
blobs = list(bucket.list_blobs(prefix=prefix))
if not blobs:
print("GCS target location is already empty, no need to clean up.")
return True
bucket.delete_blobs(blobs)
print(f"Successfully deleted {len(blobs)} objects.")
return True
except GoogleAPICallError as e:
print(f"[ERROR] Failed to clean up GCS: {e}", file=sys.stderr)
return False
def upload_directory_to_gcs(
source_directory: str, project_id: str, bucket_name: str, prefix: str
) -> bool:
"""Upload the whole directory into GCS."""
print(
f"Start uploading directory {source_directory} to GCS:"
f" gs://{bucket_name}/{prefix}..."
)
if not os.path.isdir(source_directory):
print(f"[Error] {source_directory} is not a directory or does not exist.")
return False
storage_client = storage.Client(project=project_id)
bucket = storage_client.bucket(bucket_name)
file_count = 0
for root, dirs, files in os.walk(source_directory):
# Modify the 'dirs' list in-place to prevent os.walk from descending
# into hidden directories.
dirs[:] = [d for d in dirs if not d.startswith(".")]
# Keep only .md and .py files.
files = [f for f in files if f.endswith(".md") or f.endswith(".py")]
for filename in files:
local_path = os.path.join(root, filename)
relative_path = os.path.relpath(local_path, source_directory)
gcs_path = os.path.join(prefix, relative_path)
try:
content_type = None
if filename.lower().endswith(".md"):
# Vertex AI search doesn't recognize text/markdown,
# convert it to html and use text/html instead
content_type = "text/html"
with open(local_path, "r", encoding="utf-8") as f:
md_content = f.read()
html_content = markdown.markdown(
md_content, output_format="html5", encoding="utf-8"
)
if not html_content:
print(" - Skipped empty file: " + local_path)
continue
gcs_path = gcs_path.removesuffix(".md") + ".html"
bucket.blob(gcs_path).upload_from_string(
html_content, content_type=content_type
)
else: # Python files
bucket.blob(gcs_path).upload_from_filename(
local_path, content_type=content_type
)
type_msg = (
f"(type {content_type})" if content_type else "(type auto-detect)"
)
print(
f" - Uploaded {type_msg}: {local_path} ->"
f" gs://{bucket_name}/{gcs_path}"
)
file_count += 1
except GoogleAPICallError as e:
print(
f"[ERROR] Error uploading file {local_path}: {e}", file=sys.stderr
)
return False
print(f"Sucessfully uploaded {file_count} files to GCS.")
return True
def import_from_gcs_to_vertex_ai(
full_datastore_id: str,
gcs_bucket: str,
) -> bool:
"""Triggers a bulk import task from a GCS folder to Vertex AI Search."""
print(f"Triggering FULL SYNC import from gs://{gcs_bucket}/**...")
try:
client = discoveryengine.DocumentServiceClient()
gcs_uri = f"gs://{gcs_bucket}/**"
request = discoveryengine.ImportDocumentsRequest(
# parent has the format of
# "projects/{project_number}/locations/{location}/collections/{collection}/dataStores/{datastore_id}/branches/default_branch"
parent=full_datastore_id + "/branches/default_branch",
# Specify the GCS source and use "content" for unstructed data.
gcs_source=discoveryengine.GcsSource(
input_uris=[gcs_uri], data_schema="content"
),
reconciliation_mode=discoveryengine.ImportDocumentsRequest.ReconciliationMode.FULL,
)
operation = client.import_documents(request=request)
print(
"Successfully started full sync import operation."
f"Operation Name: {operation.operation.name}"
)
return True
except GoogleAPICallError as e:
print(f"[ERROR] Error triggering import: {e}", file=sys.stderr)
return False
def main():
# Check required environment variables.
if not GOOGLE_CLOUD_PROJECT:
print(
"[ERROR] GOOGLE_CLOUD_PROJECT environment variable not set. Exiting...",
file=sys.stderr,
)
return 1
if not GCS_BUCKET_NAME:
print(
"[ERROR] GCS_BUCKET_NAME environment variable not set. Exiting...",
file=sys.stderr,
)
return 1
if not VERTEXAI_DATASTORE_ID:
print(
"[ERROR] VERTEXAI_DATASTORE_ID environment variable not set."
" Exiting...",
file=sys.stderr,
)
return 1
if not ADK_DOCS_ROOT_PATH:
print(
"[ERROR] ADK_DOCS_ROOT_PATH environment variable not set. Exiting...",
file=sys.stderr,
)
return 1
if not ADK_PYTHON_ROOT_PATH:
print(
"[ERROR] ADK_PYTHON_ROOT_PATH environment variable not set. Exiting...",
file=sys.stderr,
)
return 1
for gcs_prefix in GCS_PREFIX_TO_ROOT_PATH:
# 1. Cleanup the GSC for a clean start.
if not cleanup_gcs_prefix(
GOOGLE_CLOUD_PROJECT, GCS_BUCKET_NAME, gcs_prefix
):
print("[ERROR] Failed to clean up GCS. Exiting...", file=sys.stderr)
return 1
# 2. Upload the docs to GCS.
if not upload_directory_to_gcs(
GCS_PREFIX_TO_ROOT_PATH[gcs_prefix],
GOOGLE_CLOUD_PROJECT,
GCS_BUCKET_NAME,
gcs_prefix,
):
print("[ERROR] Failed to upload docs to GCS. Exiting...", file=sys.stderr)
return 1
# 3. Import the docs from GCS to Vertex AI Search.
if not import_from_gcs_to_vertex_ai(VERTEXAI_DATASTORE_ID, GCS_BUCKET_NAME):
print(
"[ERROR] Failed to import docs from GCS to Vertex AI Search."
" Exiting...",
file=sys.stderr,
)
return 1
print("--- Sync task has been successfully initiated ---")
return 0
if __name__ == "__main__":
sys.exit(main())
+1 -1
View File
@@ -20,7 +20,7 @@ import time
import agent
from google.adk.agents.run_config import RunConfig
from google.adk.runners import InMemoryRunner
from google.adk.sessions import Session
from google.adk.sessions.session import Session
from google.genai import types

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