You've already forked adk-python
mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e00c52074 | |||
| 58204fb421 | |||
| 565a0e1ecb | |||
| 49da199c02 | |||
| 88a246f308 | |||
| fd46b7a66b |
@@ -8,68 +8,48 @@ assignees: ''
|
||||
---
|
||||
|
||||
## đź”´ Required Information
|
||||
*Please ensure all items in this section are completed to allow for efficient
|
||||
triaging. Requests without complete information may be rejected / deprioritized.
|
||||
If an item is not applicable to you - please mark it as N/A*
|
||||
*Please ensure all items in this section are completed to allow for efficient triaging. Requests without complete information may be rejected / deprioritized. If an item is not applicable to you - please mark it as N/A*
|
||||
|
||||
**Describe the Bug:**
|
||||
**Describe the Bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Steps to Reproduce:**
|
||||
**Steps to Reproduce**
|
||||
Please provide a numbered list of steps to reproduce the behavior:
|
||||
1. Install '...'
|
||||
2. Run '....'
|
||||
3. Open '....'
|
||||
4. Provide error or stacktrace
|
||||
|
||||
**Expected Behavior:**
|
||||
**Expected Behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Observed Behavior:**
|
||||
**Observed Behavior**
|
||||
What actually happened? Include error messages or crash stack traces here.
|
||||
|
||||
**Environment Details:**
|
||||
**Environment Details**
|
||||
* **ADK Library Version:** (e.g., 2.0.1)
|
||||
* **Desktop OS:** (e.g., macOS, Linux, Windows)
|
||||
* **Python Version:**
|
||||
|
||||
- ADK Library Version (pip show google-adk):
|
||||
- Desktop OS:** [e.g., macOS, Linux, Windows]
|
||||
- Python Version (python -V):
|
||||
|
||||
**Model Information:**
|
||||
|
||||
- Are you using LiteLLM: Yes/No
|
||||
- Which model is being used: (e.g., gemini-2.5-pro)
|
||||
**Model Information**
|
||||
* **Are you using LiteLLM:** Yes/No
|
||||
* **Which model is being used:** (e.g., gemini-2.5-pro)
|
||||
|
||||
---
|
||||
|
||||
## 🟡 Optional Information
|
||||
*Providing this information greatly speeds up the resolution process.*
|
||||
|
||||
**Regression:**
|
||||
**Regression**
|
||||
Did this work in a previous version of ADK? If so, which one?
|
||||
|
||||
**Logs:**
|
||||
Please attach relevant logs. Wrap them in code blocks (```) or attach a
|
||||
text file.
|
||||
**Logs**
|
||||
Please attach relevant logs. Wrap them in code blocks (```) or attach a text file.
|
||||
```text
|
||||
// Paste logs here
|
||||
```
|
||||
**Screenshots / Video**
|
||||
If applicable, add screenshots or screen recordings to help explain your problem.
|
||||
|
||||
**Screenshots / Video:**
|
||||
If applicable, add screenshots or screen recordings to help explain
|
||||
your problem.
|
||||
|
||||
**Additional Context:**
|
||||
**Additional Context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
**Minimal Reproduction Code:**
|
||||
Please provide a code snippet or a link to a Gist/repo that isolates the issue.
|
||||
```python
|
||||
// Code snippet here
|
||||
```
|
||||
|
||||
**How often has this issue occurred?:**
|
||||
|
||||
- Always (100%)
|
||||
- Often (50%+)
|
||||
- Intermittently (<50%)
|
||||
- Once / Rare
|
||||
|
||||
@@ -10,39 +10,14 @@ assignees: ''
|
||||
** Please make sure you read the contribution guide and file the issues in the right place. **
|
||||
[Contribution guide.](https://google.github.io/adk-docs/contributing-guide/)
|
||||
|
||||
## đź”´ Required Information
|
||||
*Please ensure all items in this section are completed to allow for efficient
|
||||
triaging. Requests without complete information may be rejected / deprioritized.
|
||||
If an item is not applicable to you - please mark it as N/A*
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
### Is your feature request related to a specific problem?
|
||||
Please describe the problem you are trying to solve. (Ex: "I'm always frustrated
|
||||
when I have to manually handle X...")
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
### Describe the Solution You'd Like
|
||||
A clear and concise description of the feature or API change you want.
|
||||
Be specific about input/outputs if this involves an API change.
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
### Impact on your work
|
||||
How does this feature impact your work and what are you trying to achieve?
|
||||
If this is critical for you, tell us if there is a timeline by when you need
|
||||
this feature.
|
||||
|
||||
### Willingness to contribute
|
||||
Are you interested in implementing this feature yourself or submitting a PR?
|
||||
(Yes/No)
|
||||
|
||||
---
|
||||
|
||||
## 🟡 Recommended Information
|
||||
|
||||
### Describe Alternatives You've Considered
|
||||
A clear and concise description of any alternative solutions or workarounds
|
||||
you've considered and why they didn't work for you.
|
||||
|
||||
### Proposed API / Implementation
|
||||
If you have ideas on how this should look in code, please share a
|
||||
pseudo-code example.
|
||||
|
||||
### Additional Context
|
||||
Add any other context or screenshots about the feature request here.
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
name: Mypy New Error Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
|
||||
jobs:
|
||||
mypy-diff:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.10', '3.11', '3.12', '3.13',]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
|
||||
- name: Generate Baseline (Main)
|
||||
run: |
|
||||
# Switch to main branch to generate baseline
|
||||
git checkout origin/main
|
||||
|
||||
git checkout ${{ github.sha }} -- pyproject.toml
|
||||
|
||||
# Install dependencies for main
|
||||
uv venv .venv
|
||||
source .venv/bin/activate
|
||||
uv sync --all-extras
|
||||
|
||||
# Run mypy, filter for errors only, remove line numbers (file:123: -> file::), and sort
|
||||
# We ignore exit code (|| true) because we expect errors on main
|
||||
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > main_errors.txt || true
|
||||
|
||||
echo "Found $(wc -l < main_errors.txt) errors on main."
|
||||
|
||||
- name: Check PR Branch
|
||||
run: |
|
||||
# Switch back to the PR commit
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
# Re-sync dependencies in case the PR changed them
|
||||
source .venv/bin/activate
|
||||
uv sync --all-extras
|
||||
|
||||
# Run mypy on PR code, apply same processing
|
||||
uv run mypy . | grep "error:" | sed 's/:\([0-9]\+\):/::/g' | sort > pr_errors.txt || true
|
||||
|
||||
echo "Found $(wc -l < pr_errors.txt) errors on PR branch."
|
||||
|
||||
- name: Compare and Fail on New Errors
|
||||
run: |
|
||||
# 'comm -13' suppresses unique lines in file1 (main) and common lines,
|
||||
# leaving only lines unique to file2 (PR) -> The new errors.
|
||||
comm -13 main_errors.txt pr_errors.txt > new_errors.txt
|
||||
|
||||
if [ -s new_errors.txt ]; then
|
||||
echo "::error::The following NEW mypy errors were introduced:"
|
||||
cat new_errors.txt
|
||||
exit 1
|
||||
else
|
||||
echo "Great job! No new mypy errors introduced."
|
||||
fi
|
||||
@@ -1,32 +0,0 @@
|
||||
name: Mypy Type Check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
mypy:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.10', '3.11', '3.12', '3.13',]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v1
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --all-extras
|
||||
|
||||
- name: Run mypy
|
||||
|
||||
run: uv run mypy . --strict
|
||||
-175
@@ -1,180 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [1.24.1](https://github.com/google/adk-python/compare/v1.24.0...v1.24.1) (2026-02-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add back deprecated eval endpoint for web until we migrate([ae993e8](https://github.com/google/adk-python/commit/ae993e884f44db276a4116ebb7a11a2fb586dbfe))
|
||||
* Update eval dialog colors, and fix a2ui component types ([3686a3a](https://github.com/google/adk-python/commit/3686a3a98f46738549cd7a999f3773b7a6fd1182))
|
||||
|
||||
## [1.24.0](https://github.com/google/adk-python/compare/v1.23.0...v1.24.0) (2026-02-04)
|
||||
|
||||
### âš BREAKING CHANGES
|
||||
|
||||
* Breaking: Make credential manager accept `tool_context` instead of `callback_context` ([fe82f3c](https://github.com/google/adk-python/commit/fe82f3cde854e49be13d90b4c02d786d82f8a202))
|
||||
|
||||
### Highlights
|
||||
|
||||
* **[Web]**
|
||||
* **Consolidated Event View**: Replaced the Event tab with a more intuitive "click-to-expand" interaction on message rows, enabling faster debugging within the chat context
|
||||
* **Enhanced Accessibility**: Added full support for arrow-key navigation for a more seamless, keyboard-centric experience
|
||||
* **Rich Developer Tooling**: Introduced detailed tooltips for function calls, providing instant visibility into arguments, responses, and state changes
|
||||
* **A2UI Integration**: Integrated the **A2UI v0.8** standard catalog to automatically render spec-compliant ADK parts as native UI components directly in the chat
|
||||
|
||||
### Features
|
||||
|
||||
* **[Core]**
|
||||
* Allow passthrough of `GOOGLE_CLOUD_LOCATION` for Agent Engine deployments ([004e15c](https://github.com/google/adk-python/commit/004e15ccb7c7f683623f8e7d2e77a9d12558c545))
|
||||
* Add interface for agent optimizers ([4ee125a](https://github.com/google/adk-python/commit/4ee125a03856fdb9ed28245bf7f5917c2d9038db))
|
||||
* Pass event ID as metadata when converted into a message ([85434e2](https://github.com/google/adk-python/commit/85434e293f7bd1e3711f190f84d5a36804e4462b))
|
||||
* Restructure the bug report template as per the intake process ([324796b](https://github.com/google/adk-python/commit/324796b4fe05bec3379bfef67071a29552ef355a))
|
||||
|
||||
* **[Models]**
|
||||
* Mark Vertex calls made from non-Gemini models ([7d58e0d](https://github.com/google/adk-python/commit/7d58e0d2f375bc80bdfac9cffea2926fd2344b8a))
|
||||
|
||||
* **[Evals]**
|
||||
* Allow Vertex AI Client initialization with API Key ([43d6075](https://github.com/google/adk-python/commit/43d6075ea7aa49ddb358732f2219ca9598dd286f))
|
||||
* Remove overall evaluation status calculation from `_CustomMetricEvaluator` and add threshold to custom metric function expected signature ([553e376](https://github.com/google/adk-python/commit/553e376718ceb3d7fb1403231bb720836d71f42c))
|
||||
|
||||
* **[Tools]**
|
||||
* Make OpenAPI tool asynchronous ([9290b96](https://github.com/google/adk-python/commit/9290b966267dc02569786f95aab2a3cb78c7004f))
|
||||
* Implement toolset authentication for `McpToolset`, `OpenAPIToolset`, and other toolsets ([798f65d](https://github.com/google/adk-python/commit/798f65df86b1bbe33d864e30c5b1f9e155e89810))
|
||||
* Add framework support for toolset authentication before `get_tools` calls ([ee873ca](https://github.com/google/adk-python/commit/ee873cae2e2df960910d264a4340ce6c0489eb7a))
|
||||
* Support dynamic configuration for `VertexAiSearchTool` ([585ebfd](https://github.com/google/adk-python/commit/585ebfdac7f1b8007b4e4a7e4258ec5de72c78b1))
|
||||
* Add `get_auth_config` method to toolset to expose authentication requirements ([381d44c](https://github.com/google/adk-python/commit/381d44cab437cac027af181ae627e7b260b7561e))
|
||||
* Add methods in `McpToolset` for users to access MCP resources ([8f7d965](https://github.com/google/adk-python/commit/8f7d9659cfc19034af29952fbca765d012169b38))
|
||||
* Improve error message when failing to get tools from MCP ([3480b3b](https://github.com/google/adk-python/commit/3480b3b82d89de69f77637d7ad034827434df45a))
|
||||
|
||||
* **[Services]**
|
||||
* Improve `asyncio` loop handling and test cleanup ([00aba2d](https://github.com/google/adk-python/commit/00aba2d884d24fb5244d1de84f8dba9cbc3c07e8))
|
||||
|
||||
* **[Live]**
|
||||
* Support running tools in separate threads for live mode ([714c3ad](https://github.com/google/adk-python/commit/714c3ad0477e775fba6696a919a366a293197268))
|
||||
|
||||
* **[Observability]**
|
||||
* Add extra attributes to spans generated with `opentelemetry-instrumentation-google-genai` ([e87a843](https://github.com/google/adk-python/commit/e87a8437fb430e0d4c42c73948e3ba1872040a15))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Ignore `session_db_kwargs` for SQLite session services ([ce07cd8](https://github.com/google/adk-python/commit/ce07cd8144c8498434f68e61ebeb519bf329f778))
|
||||
* Resolve `MutualTLSChannelError` by adding `pyopenssl` dependency ([125bc85](https://github.com/google/adk-python/commit/125bc85ac5e1400bc38f7c681f76fa82626c9911))
|
||||
* Add `update_timestamp_tz` property to `StorageSession` ([666cebe](https://github.com/google/adk-python/commit/666cebe3693d2981fd5fea6e9e4c65e56dcd3f2b))
|
||||
* Do not treat Function Calls and Function Responses as invisible when marked as thoughts ([853a3b0](https://github.com/google/adk-python/commit/853a3b0e143ce27516f0de51e0e0df2af6ecf465))
|
||||
* Add pre-deployment validation for agent module imports (credit to @ppgranger, [2ac468e](https://github.com/google/adk-python/commit/2ac468ea7e30ef30c1324ffc86f67dbf32ab7ede))
|
||||
* Fix cases where `execution_result_delimiters` have `None` type element ([a16e3cc](https://github.com/google/adk-python/commit/a16e3cc67e1cb391228ba78662547672404ae550))
|
||||
* Disable `save_input_blobs_as_artifacts` deprecation warning message for users not setting it ([c34615e](https://github.com/google/adk-python/commit/c34615ecf3c7bbe0f4275f72543774f258c565b4))
|
||||
* Fix agent config path handling in generated deployment script ([8012339](https://github.com/google/adk-python/commit/801233902bbd6c0cca63b6fc8c1b0b2531f3f11e))
|
||||
* Add `pypika>=0.50.0` to `project.toml` to support `crewai` on Python 3.12+ ([e8f7aa3](https://github.com/google/adk-python/commit/e8f7aa3140d2585ac38ebfe31c5b650383499a20))
|
||||
* Update OpenTelemetry dependency versions to relax version constraints for `opentelemetry-api` and `opentelemetry-sdk` ([706a6dd](https://github.com/google/adk-python/commit/706a6dda8144da147bd9fa42ef85bbfa58fec5d3))
|
||||
* Enable `pool_pre_ping` by default for non-SQLite database engines ([da73e71](https://github.com/google/adk-python/commit/da73e718efa9557ed33e2fb579de68fcbcf4c7f0))
|
||||
* Ensure database sessions are always rolled back on errors ([63a8eba](https://github.com/google/adk-python/commit/63a8eba53f2cb07625eb7cd111ff767e8e0030fa))
|
||||
* Reload stale session in `DatabaseSessionService` when storage update time is later than the in-memory session object ([1063fa5](https://github.com/google/adk-python/commit/1063fa532cad59d8e9f7421ce2f523724d49d541))
|
||||
* Make credential key generation stable and prevent cross-user credential leaks ([33012e6](https://github.com/google/adk-python/commit/33012e6dda9ef20c7a1dae66a84717de5d782097))
|
||||
* Change MCP `read_resource` to return original contents ([ecce7e5](https://github.com/google/adk-python/commit/ecce7e54a688a915a1b9d742c39e4684186729be))
|
||||
* Recognize function responses as non-empty parts in LiteLLM ([d0102ec](https://github.com/google/adk-python/commit/d0102ecea331e062190dbb7578a4ef7f4044306e))
|
||||
* Handle HTTP/HTTPS URLs for media files in LiteLLM content conversion ([47221cd](https://github.com/google/adk-python/commit/47221cd5c1e778cd4b92ed8d382c639435f5728c))
|
||||
* Fix Pydantic schema generation error for `ClientSession` ([131fbd3](https://github.com/google/adk-python/commit/131fbd39482980572487a30fea13236d2badd543))
|
||||
* Fix Click’s Wrapping in `adk eval` help message ([3bcd8f7](https://github.com/google/adk-python/commit/3bcd8f7f7a0683f838005bc209f7d39dc93f850b))
|
||||
* Stream errors as simple JSON objects in ADK web server SSE endpoint ([798d005](https://github.com/google/adk-python/commit/798d0053c832e7ed52e2e104f8a14f789ba8b17f))
|
||||
* Remove print debugging artifact ([0d38a36](https://github.com/google/adk-python/commit/0d38a3683f13bc12dc5d181164b6cd5d72fc260c))
|
||||
|
||||
### Improvements
|
||||
|
||||
* Check `will_continue` for streaming function calls ([2220d88](https://github.com/google/adk-python/commit/2220d885cda875144b52338b5becf6e5546f3f51))
|
||||
* Update ADK web, rework events, and add A2UI capabilities ([37e6507](https://github.com/google/adk-python/commit/37e6507ce4d8750100d914eb1a62014350ef1795))
|
||||
* Improve error handling for LiteLLM import in `gemma_llm.py` ([574ec43](https://github.com/google/adk-python/commit/574ec43a175e3bf3a05e73114e8db7196fae7040))
|
||||
* Replace proxy methods with utils implementation ([6ff10b2](https://github.com/google/adk-python/commit/6ff10b23be01c1f7dd79d13ac8c679c079140f76), [f82ceb0](https://github.com/google/adk-python/commit/f82ceb0ce75d3efed7c046835ddac76c28210013))
|
||||
* Replace print statements with logging in ADK evaluation components ([dd8cd27](https://github.com/google/adk-python/commit/dd8cd27b2ce505ecca50cdfbb1469db01c82b0af))
|
||||
* Add sample agent that requires OAuth flow during MCP tool listing, and convert `MCPToolset` to `McpToolset` in unit tests ([2770012](https://github.com/google/adk-python/commit/2770012cecdfc71628a818a75b21faabe828b4e5), [4341839](https://github.com/google/adk-python/commit/43418394202c2d01b0d37f6424bd601148077e27))
|
||||
* Ensure `BigQueryAgentAnalyticsPlugin` is shut down after each test ([c0c98d9](https://github.com/google/adk-python/commit/c0c98d94b3161d6bf9fff731e0abfc985b53e653))
|
||||
* Add ADK logger in `RestApiTool` ([288c2c4](https://github.com/google/adk-python/commit/288c2c448d77c574dafadf7851a49e6ff59fa7f4))
|
||||
* Add GitHub Action check to run `mypy` ([32f9f92](https://github.com/google/adk-python/commit/32f9f92042ab530220ac9d159045c91d311affa7))
|
||||
* Add `unittests.sh` script and update `CONTRIBUTING.md` ([025b42c](https://github.com/google/adk-python/commit/025b42c8361ad2078593e3e7fc5301df88a532c7))
|
||||
* Extract helper function for LLM request building and response processing ([753084f](https://github.com/google/adk-python/commit/753084fd46c9637488f33b0a05b4d270f6e03a39))
|
||||
|
||||
## [1.23.0](https://github.com/google/adk-python/compare/v1.22.1...v1.23.0) (2026-01-22)
|
||||
|
||||
### âš BREAKING CHANGES
|
||||
|
||||
* Breaking: Use OpenTelemetry for BigQuery plugin tracing, replacing custom `ContextVar` implementation ([ab89d12](https://github.com/google/adk-python/commit/ab89d1283430041afb303834749869e9ee331721))
|
||||
|
||||
### Features
|
||||
|
||||
* **[Core]**
|
||||
* Add support to automatically create a session if one does not exist ([8e69a58](https://github.com/google/adk-python/commit/8e69a58df4eadeccbb100b7264bb518a46b61fd7))
|
||||
* Remove `@experimental` decorator from `AgentEngineSandboxCodeExecutor` ([135f763](https://github.com/google/adk-python/commit/135f7633253f6a415302142abc3579b664601d5b))
|
||||
* Add `--disable_features` CLI option to override default feature enable state ([53b67ce](https://github.com/google/adk-python/commit/53b67ce6340f3f3f8c3d732f9f7811e445c76359))
|
||||
* Add `otel_to_cloud` flag to `adk deploy agent_engine` command ([21f63f6](https://github.com/google/adk-python/commit/21f63f66ee424501d9a70806277463ef718ae843))
|
||||
* Add `is_computer_use` field to agent information in `adk-web` server ([5923da7](https://github.com/google/adk-python/commit/5923da786eb1aaef6f0bcbc6adc906cbc8bf9b36))
|
||||
* Allow `thinking_config` in `generate_content_config` ([e162bb8](https://github.com/google/adk-python/commit/e162bb8832a806e2380048e39165bf837455f88c))
|
||||
* Convert A2UI messages between A2A `DataPart` metadata and ADK events ([1133ce2](https://github.com/google/adk-python/commit/1133ce219c5a7a9a85222b03e348ba6b13830c8f))
|
||||
* Add `--enable_features` CLI option to override default feature enable state ([79fcddb](https://github.com/google/adk-python/commit/79fcddb39f71a4c1342e63b4d67832b3eccb2652))
|
||||
|
||||
* **[Tools]**
|
||||
* Add flush mechanism to `BigQueryAgentAnalyticsPlugin` to ensure pending log events are written to BigQuery ([9579bea](https://github.com/google/adk-python/commit/9579bea05d946b3d8b4bfec35e510725dd371224))
|
||||
* Allow Google Search tool to set a different model ([b57a3d4](https://github.com/google/adk-python/commit/b57a3d43e4656f5a3c5db53addff02b67d1fde26))
|
||||
* Support authentication for MCP tool listing ([e3d542a](https://github.com/google/adk-python/commit/e3d542a5ba3d357407f8cd29cfdd722f583c8564) [19315fe](https://github.com/google/adk-python/commit/19315fe557039fa8bf446525a4830b1c9f40cba9))
|
||||
* Use JSON schema for `base_retrieval_tool`, `load_artifacts_tool`, and `load_memory_tool` declarations when the feature is enabled ([69ad605](https://github.com/google/adk-python/commit/69ad605bc4bbe9a4f018127fd3625169ee70488e))
|
||||
* Use JSON schema for `IntegrationConnectorTool` declaration when the feature is enabled ([2ed6865](https://github.com/google/adk-python/commit/2ed686527ac75ff64128ce7d9b1a3befc2b37c64))
|
||||
* Start and close `ClientSession` in a single task in `McpSessionManager` ([cce430d](https://github.com/google/adk-python/commit/cce430da799766686e65f6cae02ba64e916d5c8a))
|
||||
* Use JSON schema for `RestApiTool` declaration when the feature is enabled ([a5f0d33](https://github.com/google/adk-python/commit/a5f0d333d7f26f2966ed511d5d9def7a1933f0c2))
|
||||
|
||||
* **[Evals]**
|
||||
* Update `adk eval` CLI to consume custom metrics by adding `CustomMetricEvaluator` ([ea0934b](https://github.com/google/adk-python/commit/ea0934b9934c1fefd129a1026d6af369f126870e))
|
||||
* Update `EvalConfig` and `EvalMetric` data models to support custom metrics ([6d2f33a](https://github.com/google/adk-python/commit/6d2f33a59cfba358dd758378290125fc2701c411))
|
||||
|
||||
* **[Observability]**
|
||||
* Add minimal `generate_content {model.name}` spans and logs for non-Gemini inference and when `opentelemetry-inference-google-genai` dependency is missing ([935c279](https://github.com/google/adk-python/commit/935c279f8281bde99224f03d936b8abe51cbabfc))
|
||||
|
||||
* **[Integrations]**
|
||||
* Enhance `TraceManager` asynchronous safety, enrich BigQuery plugin logging, and fix serialization ([a4116a6](https://github.com/google/adk-python/commit/a4116a6cbfadc161982af5dabd55a711d79348b7))
|
||||
|
||||
* **[Live]**
|
||||
* Persist user input content to session in live mode ([a04828d](https://github.com/google/adk-python/commit/a04828dd8a848482acbd48acc7da432d0d2cb0aa))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Recursively extract input/output schema for AgentTool ([bf2b56d](https://github.com/google/adk-python/commit/bf2b56de6d0052e40b6d871b2d22c56e9225e145))
|
||||
* Yield buffered `function_call` and `function_response` events during live streaming ([7b25b8f](https://github.com/google/adk-python/commit/7b25b8fb1daf54d7694bf405d545d46d2c012d2b))
|
||||
* Update `authlib` and `mcp` dependency versions ([7955177](https://github.com/google/adk-python/commit/7955177fb28b8e5dc19aae8be94015a7b5d9882a))
|
||||
* Set `LITELLM_MODE` to `PRODUCTION` before importing LiteLLM to prevent implicit `.env` file loading ([215c2f5](https://github.com/google/adk-python/commit/215c2f506e21a3d8c39551b80f6356943ecae320))
|
||||
* Redact sensitive information from URIs in logs ([5257869](https://github.com/google/adk-python/commit/5257869d91a77ebd1381538a85e7fdc3a600da90))
|
||||
* Handle asynchronous driver URLs in the migration tool ([4b29d15](https://github.com/google/adk-python/commit/4b29d15b3e5df65f3503daffa6bc7af85159507b))
|
||||
* Remove custom metadata from A2A response events ([81eaeb5](https://github.com/google/adk-python/commit/81eaeb5eba6d40cde0cf6147d96921ed1bf7bb31))
|
||||
* Handle `None` inferences in eval results ([7d4326c](https://github.com/google/adk-python/commit/7d4326c3606a7ff2ba3c0fdef08d4f6af52ee71e))
|
||||
* Mark all parts of a thought event as thought ([f92d4e3](https://github.com/google/adk-python/commit/f92d4e397f37445fe9032a95ce26646a3a69300b))
|
||||
* Use `json.dumps` for error messages in SSE events ([6ad18cc](https://github.com/google/adk-python/commit/6ad18cc2fc3a3315a0fc240cb51b3283b53116b4))
|
||||
* Use the correct path for config-based agents when deploying to AgentEngine ([83d7bb6](https://github.com/google/adk-python/commit/83d7bb6ef0d952ad04c5d9a61aaf202672c7e17d))
|
||||
* Support Generator and Async Generator tool declarations in JSON schema ([19555e7](https://github.com/google/adk-python/commit/19555e7dce6d60c3b960ca0bc2f928c138ac3cc0) [7c28297](https://github.com/google/adk-python/commit/7c282973ea193841fee79f90b8a91c5e02627ccc))
|
||||
* Prevent stopping event processing on events with `None` content ([ed2c3eb](https://github.com/google/adk-python/commit/ed2c3ebde9cafbb5e2bf375f44db1e77cee9fb24))
|
||||
* Fix `'NoneType'` object is not iterable error ([7db3ce9](https://github.com/google/adk-python/commit/7db3ce9613b1c2c97e6ca3cd8115736516dc1556))
|
||||
* Use canonical tools to find streaming tools and register them by `tool.name` ([ec6abf4](https://github.com/google/adk-python/commit/ec6abf401019c39e8e1a8d1b2c7d5cf5e8c7ac56))
|
||||
* Initialize `self._auth_config` inside `BaseAuthenticatedTool` to access authentication headers in `McpTool` ([d4da1bb](https://github.com/google/adk-python/commit/d4da1bb7330cdb87c1dcbe0b9023148357a6bd07))
|
||||
* Only filter out audio content when sending history ([712b5a3](https://github.com/google/adk-python/commit/712b5a393d44e7b5ce35fc459da98361bae4bb16))
|
||||
* Add finish reason mapping and remove custom file URI handling in LiteLLM ([89bed43](https://github.com/google/adk-python/commit/89bed43f5e0c5ad12dd31c716d372145b7e33e78))
|
||||
* Convert unsupported inline artifact MIME types to text in `LoadArtifactsTool` ([fdc98d5](https://github.com/google/adk-python/commit/fdc98d5c927bfef021e87cf72103892e4c2ac12a))
|
||||
* Pass `log_level` to `uvicorn` in `web` and `api_server` commands ([38d52b2](https://github.com/google/adk-python/commit/38d52b247600fb45a2beeb041c4698e90c00d705))
|
||||
* Use the agent name as the author of the audio event ([ab62b1b](https://github.com/google/adk-python/commit/ab62b1bffd7ad2df5809d430ad1823872b8bd67a))
|
||||
* Handle `NOT_FOUND` error when fetching Vertex AI sessions ([75231a3](https://github.com/google/adk-python/commit/75231a30f1857d930804769caf88bcc20839dd08))
|
||||
* Fix `httpx` client closure during event pagination ([b725045](https://github.com/google/adk-python/commit/b725045e5a1192bc9fd5190cbd2758ab6ff02590))
|
||||
|
||||
### Improvements
|
||||
|
||||
* Add new conversational analytics API toolset ([82fa10b](https://github.com/google/adk-python/commit/82fa10b71e037b565cb407c82e9e908432dab0ff))
|
||||
* Filter out `adk_request_input` event from content list ([295b345](https://github.com/google/adk-python/commit/295b34558774d1f64022009980e3edd8eb79527b))
|
||||
* Always skip executing partial function calls ([d62f9c8](https://github.com/google/adk-python/commit/d62f9c896c301aba3a781e868735e16f946a8862))
|
||||
* Update comments of request confirmation preprocessor ([1699b09](https://github.com/google/adk-python/commit/1699b090edc9e5b13c34f461c8e664187157c5c0))
|
||||
* Fix various typos ([a8f2ddd](https://github.com/google/adk-python/commit/a8f2ddd943301bbf53f49b3a23300ece45803cc0))
|
||||
* Update sample live streaming tools agent to use latest live models ([3dd7e3f](https://github.com/google/adk-python/commit/3dd7e3f1b9be05c28adb061864d84c4202a2d922))
|
||||
* Make the regex to catch CLI reference strict by adding word boundary anchor ([c222a45](https://github.com/google/adk-python/commit/c222a45ef74f7b55c48dc151ba98cd8c30a15c57))
|
||||
* Migrate `ToolboxToolset` to use `toolbox-adk` and align validation ([7dc6adf](https://github.com/google/adk-python/commit/7dc6adf4e563330a09e4cf28d2b1994c24b007d1) [277084e](https://github.com/google/adk-python/commit/277084e31368302e6338b69d456affd35d5fedfe))
|
||||
* Always log API backend when connecting to live model ([7b035aa](https://github.com/google/adk-python/commit/7b035aa9fc43a43489aeffea8f877cd7eaa09f35))
|
||||
* Add a sample BigQuery agent using BigQuery MCP tools ([672b57f](https://github.com/google/adk-python/commit/672b57f1b76580023d1f348de76227291a9c1012))
|
||||
* Add a `DebugLoggingPlugin` to record human-readable debugging logs ([8973618](https://github.com/google/adk-python/commit/8973618b0b0e90c513873e22af272c147efb4904))
|
||||
* Upgrade the sample BigQuery agent model version to `gemini-2.5-flash` ([fd2c0f5](https://github.com/google/adk-python/commit/fd2c0f556b786417a9f6add744827b07e7a06b7d))
|
||||
* Import `migration_runner` lazily within the migrate command ([905604f](https://github.com/google/adk-python/commit/905604faac82aca8ae0935eebea288f82985e9c5))
|
||||
|
||||
|
||||
|
||||
## [1.22.1](https://github.com/google/adk-python/compare/v1.22.0...v1.22.1) (2026-01-09)
|
||||
|
||||
|
||||
@@ -188,18 +188,6 @@ part before or alongside your code PR.
|
||||
pytest ./tests/unittests
|
||||
```
|
||||
|
||||
**Alternatively**, use the included `unittests.sh` script which handles
|
||||
environment setup and restoration automatically:
|
||||
|
||||
```shell
|
||||
./scripts/unittests.sh
|
||||
```
|
||||
|
||||
This script will:
|
||||
- Set up the test environment with minimal dependencies (`test`, `eval`, `a2a`)
|
||||
- Run the unit tests
|
||||
- Restore the full development environment (`--all-extras`)
|
||||
|
||||
6. **Auto-format the code:**
|
||||
|
||||
**NOTE**: We use `isort` and `pyink` for styles. Use the included
|
||||
|
||||
@@ -115,7 +115,7 @@ root_agent = Agent(
|
||||
|
||||
### Define a multi-agent system:
|
||||
|
||||
Define a multi-agent system with coordinator agent, greeter agent, and task execution agent. Then ADK engine and the model will guide the agents to work together to accomplish the task.
|
||||
Define a multi-agent system with coordinator agent, greeter agent, and task execution agent. Then ADK engine and the model will guide the agents works together to accomplish the task.
|
||||
|
||||
```python
|
||||
from google.adk.agents import LlmAgent, BaseAgent
|
||||
|
||||
@@ -57,25 +57,8 @@ from google.adk import Agent
|
||||
from google.adk.agents.loop_agent import LoopAgent
|
||||
from google.adk.agents.readonly_context import ReadonlyContext
|
||||
from google.adk.agents.sequential_agent import SequentialAgent
|
||||
from google.adk.models import Gemini
|
||||
from google.adk.tools.exit_loop_tool import exit_loop
|
||||
from google.adk.tools.tool_context import ToolContext
|
||||
from google.genai import types
|
||||
|
||||
# Retry configuration for handling API rate limits and overload
|
||||
_RETRY_OPTIONS = types.HttpRetryOptions(
|
||||
initial_delay=10,
|
||||
attempts=8,
|
||||
exp_base=2,
|
||||
max_delay=300,
|
||||
http_status_codes=[429, 503],
|
||||
)
|
||||
|
||||
# Use gemini-3-pro-preview for planning and summary (better quality)
|
||||
GEMINI_PRO_WITH_RETRY = Gemini(
|
||||
model="gemini-3-pro-preview",
|
||||
retry_options=_RETRY_OPTIONS,
|
||||
)
|
||||
|
||||
# Maximum number of files per analysis group to avoid context overflow
|
||||
MAX_FILES_PER_GROUP = 5
|
||||
@@ -266,7 +249,7 @@ def get_release_context(tool_context: ToolContext) -> dict[str, Any]:
|
||||
# =============================================================================
|
||||
|
||||
planner_agent = Agent(
|
||||
model=GEMINI_PRO_WITH_RETRY,
|
||||
model="gemini-2.5-pro",
|
||||
name="release_planner",
|
||||
description=(
|
||||
"Plans the analysis by fetching release info and organizing files into"
|
||||
@@ -289,12 +272,10 @@ efficient processing.
|
||||
|
||||
3. Call `get_changed_files_summary` to get the list of changed files WITHOUT
|
||||
the full patches (to save context space).
|
||||
- **IMPORTANT**: Pass these parameters:
|
||||
- `local_repo_path="{LOCAL_REPOS_DIR_PATH}/{CODE_REPO}"` to avoid 300-file limit
|
||||
- `path_filter="src/google/adk/"` to only get ADK source files (reduces token usage)
|
||||
|
||||
4. Further filter the returned files:
|
||||
- **EXCLUDE** test files and `__init__.py` files
|
||||
4. Filter and organize the files:
|
||||
- **INCLUDE** only files in `src/google/adk/` directory
|
||||
- **EXCLUDE** test files, `__init__.py`, and files outside src/
|
||||
- **IMPORTANT**: Do NOT exclude any file just because it has few changes.
|
||||
Even single-line changes to public APIs need documentation updates.
|
||||
- **PRIORITIZE** by importance:
|
||||
@@ -440,7 +421,7 @@ files and finding related documentation that needs updating.
|
||||
|
||||
|
||||
file_group_analyzer = Agent(
|
||||
model=GEMINI_PRO_WITH_RETRY,
|
||||
model="gemini-2.5-pro",
|
||||
name="file_group_analyzer",
|
||||
description=(
|
||||
"Analyzes a group of changed files and generates recommendations."
|
||||
@@ -524,7 +505,7 @@ Present a summary of:
|
||||
|
||||
|
||||
summary_agent = Agent(
|
||||
model=GEMINI_PRO_WITH_RETRY,
|
||||
model="gemini-2.5-pro",
|
||||
name="summary_agent",
|
||||
description="Compiles recommendations and creates the GitHub issue.",
|
||||
instruction=summary_instruction,
|
||||
@@ -559,7 +540,7 @@ analysis_pipeline = SequentialAgent(
|
||||
# =============================================================================
|
||||
|
||||
root_agent = Agent(
|
||||
model=GEMINI_PRO_WITH_RETRY,
|
||||
model="gemini-2.5-pro",
|
||||
name="adk_release_analyzer",
|
||||
description=(
|
||||
"Analyzes ADK Python releases and generates documentation update"
|
||||
|
||||
@@ -600,41 +600,23 @@ def get_file_diff_for_release(
|
||||
|
||||
|
||||
def get_changed_files_summary(
|
||||
repo_owner: str,
|
||||
repo_name: str,
|
||||
start_tag: str,
|
||||
end_tag: str,
|
||||
local_repo_path: Optional[str] = None,
|
||||
path_filter: Optional[str] = None,
|
||||
repo_owner: str, repo_name: str, start_tag: str, end_tag: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Gets a summary of changed files between two releases without patches.
|
||||
|
||||
This function uses local git commands when local_repo_path is provided,
|
||||
which avoids the GitHub API's 300-file limit for large comparisons.
|
||||
Falls back to GitHub API if local_repo_path is not provided or invalid.
|
||||
This is a lighter-weight version of get_changed_files_between_releases
|
||||
that only returns file paths and metadata, without the actual diff content.
|
||||
Use this for planning which files to analyze.
|
||||
|
||||
Args:
|
||||
repo_owner: The name of the repository owner.
|
||||
repo_name: The name of the repository.
|
||||
start_tag: The older tag (base) for the comparison.
|
||||
end_tag: The newer tag (head) for the comparison.
|
||||
local_repo_path: Optional absolute path to local git repo. If provided
|
||||
and valid, uses git diff instead of GitHub API to get complete
|
||||
file list (avoids 300-file limit).
|
||||
path_filter: Optional path prefix to filter files. Only files whose
|
||||
path starts with this prefix will be included. Example:
|
||||
"src/google/adk/" to only include ADK source files.
|
||||
|
||||
Returns:
|
||||
A dictionary containing the status and a summary of changed files.
|
||||
"""
|
||||
# Use local git if valid path is provided (avoids GitHub API 300-file limit)
|
||||
if local_repo_path and os.path.isdir(os.path.join(local_repo_path, ".git")):
|
||||
return _get_changed_files_from_local_git(
|
||||
local_repo_path, start_tag, end_tag, repo_owner, repo_name, path_filter
|
||||
)
|
||||
|
||||
# Fall back to GitHub API (limited to 300 files)
|
||||
url = f"{GITHUB_BASE_URL}/repos/{repo_owner}/{repo_name}/compare/{start_tag}...{end_tag}"
|
||||
|
||||
try:
|
||||
@@ -672,146 +654,8 @@ def get_changed_files_summary(
|
||||
f"https://github.com/{repo_owner}/{repo_name}"
|
||||
f"/compare/{start_tag}...{end_tag}"
|
||||
),
|
||||
"note": (
|
||||
(
|
||||
"Using GitHub API which is limited to 300 files. "
|
||||
"Provide local_repo_path to get complete file list."
|
||||
)
|
||||
if len(formatted_files) >= 300
|
||||
else None
|
||||
),
|
||||
}
|
||||
except requests.exceptions.HTTPError as e:
|
||||
return error_response(f"HTTP Error: {e}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(f"Request Error: {e}")
|
||||
|
||||
|
||||
def _get_changed_files_from_local_git(
|
||||
local_repo_path: str,
|
||||
start_tag: str,
|
||||
end_tag: str,
|
||||
repo_owner: str,
|
||||
repo_name: str,
|
||||
path_filter: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""Gets changed files using local git commands (no file limit).
|
||||
|
||||
Args:
|
||||
local_repo_path: Path to local git repository.
|
||||
start_tag: The older tag (base) for the comparison.
|
||||
end_tag: The newer tag (head) for the comparison.
|
||||
repo_owner: Repository owner for compare URL.
|
||||
repo_name: Repository name for compare URL.
|
||||
path_filter: Optional path prefix to filter files.
|
||||
|
||||
Returns:
|
||||
A dictionary containing the status and a summary of changed files.
|
||||
"""
|
||||
try:
|
||||
# Fetch tags to ensure we have them
|
||||
subprocess.run(
|
||||
["git", "fetch", "--tags"],
|
||||
cwd=local_repo_path,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
# Get list of changed files with their status
|
||||
diff_result = subprocess.run(
|
||||
["git", "diff", "--name-status", f"{start_tag}...{end_tag}"],
|
||||
cwd=local_repo_path,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Get numstat for additions/deletions
|
||||
numstat_result = subprocess.run(
|
||||
["git", "diff", "--numstat", f"{start_tag}...{end_tag}"],
|
||||
cwd=local_repo_path,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
# Parse numstat output (additions, deletions, filename)
|
||||
file_stats: Dict[str, Dict[str, int]] = {}
|
||||
for line in numstat_result.stdout.strip().split("\n"):
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split("\t")
|
||||
if len(parts) >= 3:
|
||||
additions = int(parts[0]) if parts[0] != "-" else 0
|
||||
deletions = int(parts[1]) if parts[1] != "-" else 0
|
||||
filename = parts[2]
|
||||
file_stats[filename] = {
|
||||
"additions": additions,
|
||||
"deletions": deletions,
|
||||
"changes": additions + deletions,
|
||||
}
|
||||
|
||||
# Parse name-status output and combine with numstat
|
||||
status_map = {
|
||||
"A": "added",
|
||||
"D": "removed",
|
||||
"M": "modified",
|
||||
"R": "renamed",
|
||||
"C": "copied",
|
||||
}
|
||||
|
||||
files_by_dir: Dict[str, List[Dict[str, Any]]] = {}
|
||||
formatted_files = []
|
||||
|
||||
for line in diff_result.stdout.strip().split("\n"):
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split("\t")
|
||||
if len(parts) >= 2:
|
||||
status_code = parts[0][0] # First char is the status
|
||||
filename = parts[-1] # Last part is filename (handles renames)
|
||||
|
||||
# Apply path filter if specified
|
||||
if path_filter and not filename.startswith(path_filter):
|
||||
continue
|
||||
|
||||
stats = file_stats.get(
|
||||
filename,
|
||||
{
|
||||
"additions": 0,
|
||||
"deletions": 0,
|
||||
"changes": 0,
|
||||
},
|
||||
)
|
||||
|
||||
file_info = {
|
||||
"relative_path": filename,
|
||||
"status": status_map.get(status_code, "modified"),
|
||||
"additions": stats["additions"],
|
||||
"deletions": stats["deletions"],
|
||||
"changes": stats["changes"],
|
||||
}
|
||||
formatted_files.append(file_info)
|
||||
|
||||
# Group by top-level directory
|
||||
dir_parts = filename.split("/")
|
||||
top_dir = dir_parts[0] if dir_parts else "root"
|
||||
if top_dir not in files_by_dir:
|
||||
files_by_dir[top_dir] = []
|
||||
files_by_dir[top_dir].append(file_info)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"total_files": len(formatted_files),
|
||||
"files": formatted_files,
|
||||
"files_by_directory": files_by_dir,
|
||||
"compare_url": (
|
||||
f"https://github.com/{repo_owner}/{repo_name}"
|
||||
f"/compare/{start_tag}...{end_tag}"
|
||||
),
|
||||
}
|
||||
except subprocess.CalledProcessError as e:
|
||||
return error_response(f"Git command failed: {e.stderr}")
|
||||
except (OSError, ValueError) as e:
|
||||
return error_response(f"Error getting changed files: {e}")
|
||||
|
||||
@@ -96,7 +96,7 @@ def add_comment_to_issue(issue_number: int, comment: str) -> dict[str, any]:
|
||||
comment: comment to add
|
||||
|
||||
Returns:
|
||||
The status of this request, with the applied comment when successful.
|
||||
The the status of this request, with the applied comment when successful.
|
||||
"""
|
||||
print(f"Attempting to add comment '{comment}' to issue #{issue_number}")
|
||||
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/comments"
|
||||
@@ -119,7 +119,7 @@ def list_comments_on_issue(issue_number: int) -> dict[str, any]:
|
||||
issue_number: issue number of the GitHub issue
|
||||
|
||||
Returns:
|
||||
The status of this request, with the list of comments when successful.
|
||||
The the status of this request, with the list of comments when successful.
|
||||
"""
|
||||
print(f"Attempting to list comments on issue #{issue_number}")
|
||||
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/comments"
|
||||
|
||||
@@ -166,7 +166,7 @@ def add_label_to_pr(pr_number: int, label: str) -> dict[str, Any]:
|
||||
label: the label to add
|
||||
|
||||
Returns:
|
||||
The status of this request, with the applied label and response when
|
||||
The the status of this request, with the applied label and response when
|
||||
successful.
|
||||
"""
|
||||
print(f"Attempting to add label '{label}' to PR #{pr_number}")
|
||||
@@ -201,7 +201,7 @@ def add_comment_to_pr(pr_number: int, comment: str) -> dict[str, Any]:
|
||||
comment: the comment to add
|
||||
|
||||
Returns:
|
||||
The status of this request, with the applied comment when successful.
|
||||
The the status of this request, with the applied comment when successful.
|
||||
"""
|
||||
print(f"Attempting to add comment '{comment}' to issue #{pr_number}")
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ def change_issue_type(issue_number: int, issue_type: str) -> dict[str, Any]:
|
||||
issue_type: issue type to assign
|
||||
|
||||
Returns:
|
||||
The status of this request, with the applied issue type when successful.
|
||||
The the status of this request, with the applied issue type when successful.
|
||||
"""
|
||||
print(
|
||||
f"Attempting to change issue type '{issue_type}' to issue #{issue_number}"
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# Data Agent Sample
|
||||
|
||||
This sample agent demonstrates ADK's first-party tools for interacting with
|
||||
Data Agents powered by [Conversational Analytics API](https://docs.cloud.google.com/gemini/docs/conversational-analytics-api/overview).
|
||||
These tools are distributed via
|
||||
the `google.adk.tools.data_agent` module and allow you to list,
|
||||
inspect, and
|
||||
chat with Data Agents using natural language.
|
||||
|
||||
These tools leverage stateful conversations, meaning you can ask follow-up
|
||||
questions in the same session, and the agent will maintain context.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. An active Google Cloud project with BigQuery and Gemini APIs enabled.
|
||||
2. Google Cloud authentication configured for Application Default Credentials:
|
||||
```bash
|
||||
gcloud auth application-default login
|
||||
```
|
||||
3. At least one Data Agent created. You could create data agents via
|
||||
[Conversational API](https://docs.cloud.google.com/gemini/docs/conversational-analytics-api/overview),
|
||||
its
|
||||
[Python SDK](https://docs.cloud.google.com/gemini/docs/conversational-analytics-api/build-agent-sdk),
|
||||
or for BigQuery data
|
||||
[BigQuery Studio](https://docs.cloud.google.com/bigquery/docs/create-data-agents#create_a_data_agent).
|
||||
These agents are created and configured in the Google Cloud console and
|
||||
point to your BigQuery tables or other data sources.
|
||||
4. Follow the official
|
||||
[Setup and prerequisites](https://docs.cloud.google.com/gemini/docs/conversational-analytics-api/overview#setup)
|
||||
guide to enable the API and configure IAM permissions and authentication for
|
||||
your data sources.
|
||||
|
||||
## Tools Used
|
||||
|
||||
* `list_accessible_data_agents`: Lists Data Agents you have permission to
|
||||
access in the configured GCP project.
|
||||
* `get_data_agent_info`: Retrieves details about a specific Data Agent given
|
||||
its full resource name.
|
||||
* `ask_data_agent`: Chats with a specific Data Agent using natural language.
|
||||
|
||||
## How to Run
|
||||
|
||||
1. Navigate to the root of the ADK repository.
|
||||
2. Run the agent using the ADK CLI:
|
||||
```bash
|
||||
adk run --agent-path contributing/samples/data_agent
|
||||
```
|
||||
3. The CLI will prompt you for input. You can ask questions like the examples
|
||||
below.
|
||||
|
||||
## Sample prompts
|
||||
|
||||
* "List accessible data agents."
|
||||
* "Using agent
|
||||
`projects/my-project/locations/global/dataAgents/sales-agent-123`, who were
|
||||
my top 3 customers last quarter?"
|
||||
* "How does that compare to the quarter before?"
|
||||
@@ -1,15 +0,0 @@
|
||||
# Copyright 2026 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
|
||||
@@ -1,84 +0,0 @@
|
||||
# Copyright 2026 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
|
||||
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.auth.auth_credential import AuthCredentialTypes
|
||||
from google.adk.tools.data_agent.config import DataAgentToolConfig
|
||||
from google.adk.tools.data_agent.credentials import DataAgentCredentialsConfig
|
||||
from google.adk.tools.data_agent.data_agent_toolset import DataAgentToolset
|
||||
import google.auth
|
||||
import google.auth.transport.requests
|
||||
|
||||
# Define the desired credential type.
|
||||
# By default use Application Default Credentials (ADC) from the local
|
||||
# environment, which can be set up by following
|
||||
# https://cloud.google.com/docs/authentication/provide-credentials-adc.
|
||||
CREDENTIALS_TYPE = None
|
||||
|
||||
if CREDENTIALS_TYPE == AuthCredentialTypes.OAUTH2:
|
||||
# Initiaze the tools to do interactive OAuth
|
||||
# The environment variables OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET
|
||||
# must be set
|
||||
credentials_config = DataAgentCredentialsConfig(
|
||||
client_id=os.getenv("OAUTH_CLIENT_ID"),
|
||||
client_secret=os.getenv("OAUTH_CLIENT_SECRET"),
|
||||
)
|
||||
elif CREDENTIALS_TYPE == AuthCredentialTypes.SERVICE_ACCOUNT:
|
||||
# Initialize the tools to use the credentials in the service account key.
|
||||
# If this flow is enabled, make sure to replace the file path with your own
|
||||
# service account key file
|
||||
# https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys
|
||||
creds, _ = google.auth.load_credentials_from_file(
|
||||
"service_account_key.json",
|
||||
scopes=["https://www.googleapis.com/auth/cloud-platform"],
|
||||
)
|
||||
creds.refresh(google.auth.transport.requests.Request())
|
||||
credentials_config = DataAgentCredentialsConfig(credentials=creds)
|
||||
else:
|
||||
# Initialize the tools to use the application default credentials.
|
||||
# https://cloud.google.com/docs/authentication/provide-credentials-adc
|
||||
application_default_credentials, _ = google.auth.default()
|
||||
credentials_config = DataAgentCredentialsConfig(
|
||||
credentials=application_default_credentials
|
||||
)
|
||||
|
||||
tool_config = DataAgentToolConfig(
|
||||
max_query_result_rows=100,
|
||||
)
|
||||
da_toolset = DataAgentToolset(
|
||||
credentials_config=credentials_config,
|
||||
data_agent_tool_config=tool_config,
|
||||
tool_filter=[
|
||||
"list_accessible_data_agents",
|
||||
"get_data_agent_info",
|
||||
"ask_data_agent",
|
||||
],
|
||||
)
|
||||
|
||||
root_agent = Agent(
|
||||
name="data_agent",
|
||||
model="gemini-2.0-flash",
|
||||
description="Agent to answer user questions using Data Agents.",
|
||||
instruction=(
|
||||
"## Persona\nYou are a helpful assistant that uses Data Agents"
|
||||
" to answer user questions about their data.\n\n## Tools\n- You can"
|
||||
" list available data agents using `list_accessible_data_agents`.\n-"
|
||||
" You can get information about a specific data agent using"
|
||||
" `get_data_agent_info`.\n- You can chat with a specific data"
|
||||
" agent using `ask_data_agent`.\n"
|
||||
),
|
||||
tools=[da_toolset],
|
||||
)
|
||||
@@ -29,11 +29,6 @@ def concat_number_and_string(num: int, s: str) -> str:
|
||||
return str(num) + ': ' + s
|
||||
|
||||
|
||||
def write_document(document: str) -> dict[str, str]:
|
||||
"""Write a document."""
|
||||
return {'status': 'ok'}
|
||||
|
||||
|
||||
root_agent = Agent(
|
||||
model='gemini-3-pro-preview',
|
||||
name='hello_world_stream_fc_args',
|
||||
@@ -43,14 +38,9 @@ root_agent = Agent(
|
||||
You can use the `concat_number_and_string` tool to concatenate a number and a string.
|
||||
You should always call the concat_number_and_string tool to concatenate a number and a string.
|
||||
You should never concatenate on your own.
|
||||
|
||||
You can use the `write_document` tool to write a document.
|
||||
You should always call the write_document tool to write a document.
|
||||
You should never write a document on your own.
|
||||
""",
|
||||
tools=[
|
||||
concat_number_and_string,
|
||||
write_document,
|
||||
],
|
||||
generate_content_config=types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Copyright 2026 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
|
||||
@@ -1,166 +0,0 @@
|
||||
# Copyright 2026 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.
|
||||
|
||||
"""Sample agent demonstrating MCP progress callback feature.
|
||||
|
||||
This sample shows how to use the progress_callback parameter in McpToolset
|
||||
to receive progress notifications from MCP servers during long-running tool
|
||||
executions.
|
||||
|
||||
There are two ways to use progress callbacks:
|
||||
|
||||
1. Simple callback (shared by all tools):
|
||||
Pass a ProgressFnT callback that receives (progress, total, message).
|
||||
|
||||
2. Factory function (per-tool callbacks with runtime context):
|
||||
Pass a ProgressCallbackFactory that takes (tool_name, callback_context, **kwargs)
|
||||
and returns a ProgressFnT or None. This allows different tools to have different
|
||||
progress handling logic, and the factory can access and modify session state
|
||||
via the CallbackContext. The **kwargs ensures forward compatibility for future
|
||||
parameters.
|
||||
|
||||
IMPORTANT: Progress callbacks only work when the MCP server actually sends
|
||||
progress notifications. Most simple MCP servers (like the filesystem server)
|
||||
do not send progress updates. This sample uses a mock server that demonstrates
|
||||
progress reporting.
|
||||
|
||||
Usage:
|
||||
adk run contributing/samples/mcp_progress_callback_agent
|
||||
|
||||
Then try:
|
||||
"Run the long running task with 5 steps"
|
||||
"Process these items: apple, banana, cherry"
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
from google.adk.agents.callback_context import CallbackContext
|
||||
from google.adk.agents.llm_agent import LlmAgent
|
||||
from google.adk.tools.mcp_tool import McpToolset
|
||||
from google.adk.tools.mcp_tool import StdioConnectionParams
|
||||
from mcp import StdioServerParameters
|
||||
from mcp.shared.session import ProgressFnT
|
||||
|
||||
_current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
_mock_server_path = os.path.join(_current_dir, "mock_progress_server.py")
|
||||
|
||||
|
||||
# Option 1: Simple shared callback
|
||||
async def simple_progress_callback(
|
||||
progress: float,
|
||||
total: float | None,
|
||||
message: str | None,
|
||||
) -> None:
|
||||
"""Handle progress notifications from MCP server.
|
||||
|
||||
This callback is shared by all tools in the toolset.
|
||||
"""
|
||||
if total is not None:
|
||||
percentage = (progress / total) * 100
|
||||
bar_length = 20
|
||||
filled = int(bar_length * progress / total)
|
||||
bar = "=" * filled + "-" * (bar_length - filled)
|
||||
print(f"[{bar}] {percentage:.0f}% ({progress}/{total}) {message or ''}")
|
||||
else:
|
||||
print(f"Progress: {progress} {f'- {message}' if message else ''}")
|
||||
|
||||
|
||||
# Option 2: Factory function for per-tool callbacks with runtime context
|
||||
def progress_callback_factory(
|
||||
tool_name: str,
|
||||
*,
|
||||
callback_context: CallbackContext | None = None,
|
||||
**kwargs: Any,
|
||||
) -> ProgressFnT | None:
|
||||
"""Create a progress callback for a specific tool.
|
||||
|
||||
This factory allows different tools to have different progress handling.
|
||||
It receives a CallbackContext for accessing and modifying runtime information
|
||||
like session state. The **kwargs parameter ensures forward compatibility.
|
||||
|
||||
Args:
|
||||
tool_name: The name of the MCP tool.
|
||||
callback_context: The callback context providing access to session,
|
||||
state, artifacts, and other runtime information. Allows modifying
|
||||
state via ctx.state['key'] = value. May be None if not available.
|
||||
**kwargs: Additional keyword arguments for future extensibility.
|
||||
|
||||
Returns:
|
||||
A progress callback function, or None if no callback is needed.
|
||||
"""
|
||||
# Example: Access session info from context (if available)
|
||||
session_id = "unknown"
|
||||
if callback_context and callback_context.session:
|
||||
session_id = callback_context.session.id
|
||||
|
||||
async def callback(
|
||||
progress: float,
|
||||
total: float | None,
|
||||
message: str | None,
|
||||
) -> None:
|
||||
# Include tool name and session info in the progress output
|
||||
prefix = f"[{tool_name}][session:{session_id}]"
|
||||
if total is not None:
|
||||
percentage = (progress / total) * 100
|
||||
bar_length = 20
|
||||
filled = int(bar_length * progress / total)
|
||||
bar = "=" * filled + "-" * (bar_length - filled)
|
||||
print(f"{prefix} [{bar}] {percentage:.0f}% {message or ''}")
|
||||
# Example: Store progress in state (callback_context allows modification)
|
||||
if callback_context:
|
||||
callback_context.state["last_progress"] = progress
|
||||
callback_context.state["last_total"] = total
|
||||
else:
|
||||
print(
|
||||
f"{prefix} Progress: {progress} {f'- {message}' if message else ''}"
|
||||
)
|
||||
|
||||
return callback
|
||||
|
||||
|
||||
root_agent = LlmAgent(
|
||||
model="gemini-2.5-flash",
|
||||
name="progress_demo_agent",
|
||||
instruction="""\
|
||||
You are a helpful assistant that can run long-running tasks.
|
||||
|
||||
Available tools:
|
||||
- long_running_task: Simulates a task with multiple steps. You can specify
|
||||
the number of steps and delay between them.
|
||||
- process_items: Processes a list of items one by one with progress updates.
|
||||
|
||||
When the user asks you to run a task, use these tools and the progress
|
||||
will be logged automatically.
|
||||
|
||||
Example requests:
|
||||
- "Run a long task with 5 steps"
|
||||
- "Process these items: apple, banana, cherry, date"
|
||||
""",
|
||||
tools=[
|
||||
McpToolset(
|
||||
connection_params=StdioConnectionParams(
|
||||
server_params=StdioServerParameters(
|
||||
command=sys.executable, # Use current Python interpreter
|
||||
args=[_mock_server_path],
|
||||
),
|
||||
timeout=60,
|
||||
),
|
||||
# Use factory function for per-tool callbacks (Option 2)
|
||||
# Or use simple_progress_callback for shared callback (Option 1)
|
||||
progress_callback=progress_callback_factory,
|
||||
)
|
||||
],
|
||||
)
|
||||
@@ -1,161 +0,0 @@
|
||||
# Copyright 2026 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.
|
||||
|
||||
"""Mock MCP server that sends progress notifications.
|
||||
|
||||
This server demonstrates how MCP servers can send progress updates
|
||||
during long-running tool execution.
|
||||
|
||||
Run this server directly:
|
||||
python mock_progress_server.py
|
||||
|
||||
Or use it with the sample agent:
|
||||
See agent_with_mock_server.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from mcp.server import Server
|
||||
from mcp.server.stdio import stdio_server
|
||||
from mcp.types import TextContent
|
||||
from mcp.types import Tool
|
||||
|
||||
server = Server("mock-progress-server")
|
||||
|
||||
|
||||
@server.list_tools()
|
||||
async def list_tools() -> list[Tool]:
|
||||
"""List available tools."""
|
||||
return [
|
||||
Tool(
|
||||
name="long_running_task",
|
||||
description=(
|
||||
"A simulated long-running task that reports progress. "
|
||||
"Use this to test progress callback functionality."
|
||||
),
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"steps": {
|
||||
"type": "integer",
|
||||
"description": "Number of steps to simulate (default: 5)",
|
||||
"default": 5,
|
||||
},
|
||||
"delay": {
|
||||
"type": "number",
|
||||
"description": (
|
||||
"Delay in seconds between steps (default: 0.5)"
|
||||
),
|
||||
"default": 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
Tool(
|
||||
name="process_items",
|
||||
description="Process a list of items with progress reporting.",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "List of items to process",
|
||||
},
|
||||
},
|
||||
"required": ["items"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@server.call_tool()
|
||||
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
||||
"""Handle tool calls with progress reporting."""
|
||||
ctx = server.request_context
|
||||
|
||||
if name == "long_running_task":
|
||||
steps = arguments.get("steps", 5)
|
||||
delay = arguments.get("delay", 0.5)
|
||||
|
||||
# Get progress token from request metadata
|
||||
progress_token = None
|
||||
if ctx.meta and hasattr(ctx.meta, "progressToken"):
|
||||
progress_token = ctx.meta.progressToken
|
||||
|
||||
for i in range(steps):
|
||||
# Simulate work
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
# Send progress notification if client supports it
|
||||
if progress_token is not None:
|
||||
await ctx.session.send_progress_notification(
|
||||
progress_token=progress_token,
|
||||
progress=i + 1,
|
||||
total=steps,
|
||||
message=f"Completed step {i + 1} of {steps}",
|
||||
)
|
||||
|
||||
return [
|
||||
TextContent(
|
||||
type="text",
|
||||
text=f"Successfully completed {steps} steps!",
|
||||
)
|
||||
]
|
||||
|
||||
elif name == "process_items":
|
||||
items = arguments.get("items", [])
|
||||
total = len(items)
|
||||
|
||||
progress_token = None
|
||||
if ctx.meta and hasattr(ctx.meta, "progressToken"):
|
||||
progress_token = ctx.meta.progressToken
|
||||
|
||||
results = []
|
||||
for i, item in enumerate(items):
|
||||
# Simulate processing
|
||||
await asyncio.sleep(0.3)
|
||||
results.append(f"Processed: {item}")
|
||||
|
||||
# Send progress
|
||||
if progress_token is not None:
|
||||
await ctx.session.send_progress_notification(
|
||||
progress_token=progress_token,
|
||||
progress=i + 1,
|
||||
total=total,
|
||||
message=f"Processing item: {item}",
|
||||
)
|
||||
|
||||
return [
|
||||
TextContent(
|
||||
type="text",
|
||||
text="\n".join(results),
|
||||
)
|
||||
]
|
||||
|
||||
return [TextContent(type="text", text=f"Unknown tool: {name}")]
|
||||
|
||||
|
||||
async def main():
|
||||
"""Run the MCP server."""
|
||||
async with stdio_server() as (read_stream, write_stream):
|
||||
await server.run(
|
||||
read_stream,
|
||||
write_stream,
|
||||
server.create_initialization_options(),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -1,47 +0,0 @@
|
||||
# MCP Toolset OAuth Authentication Sample
|
||||
|
||||
This sample demonstrates the toolset authentication feature where OAuth credentials are required for both tool listing and tool calling.
|
||||
|
||||
## Overview
|
||||
|
||||
The toolset authentication flow works in two phases:
|
||||
|
||||
1. **Phase 1**: When the agent tries to get tools from the MCP server without credentials, the toolset signals "authentication required" and returns an auth request event.
|
||||
|
||||
2. **Phase 2**: After the user provides OAuth credentials, the agent can successfully list and call tools.
|
||||
|
||||
## Files
|
||||
|
||||
- `oauth_mcp_server.py` - MCP server that requires Bearer token authentication
|
||||
- `agent.py` - Agent configuration with OAuth-protected MCP toolset
|
||||
- `main.py` - Test script demonstrating the two-phase auth flow
|
||||
|
||||
## Running the Sample
|
||||
|
||||
1. Start the MCP server in one terminal:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=src python contributing/samples/mcp_toolset_auth/oauth_mcp_server.py
|
||||
```
|
||||
|
||||
2. Run the test script in another terminal:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=src python contributing/samples/mcp_toolset_auth/main.py
|
||||
```
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
1. First invocation yields an `adk_request_credential` function call
|
||||
2. The credential ID is `_adk_toolset_auth_McpToolset` to indicate toolset auth
|
||||
3. After providing the access token, the agent can list and call tools
|
||||
|
||||
## Testing with ADK Web UI
|
||||
|
||||
You can also test with the ADK web UI:
|
||||
|
||||
```bash
|
||||
adk web contributing/samples/mcp_toolset_auth
|
||||
```
|
||||
|
||||
Note: The web UI will display the auth request and you'll need to manually provide credentials.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user