Compare commits

...

48 Commits

Author SHA1 Message Date
Claude a5e6f5853c fix(sessions): use UTC consistently in append_event for all DB backends
The append_event method had inconsistent timezone handling: SQLite
converted event.timestamp to UTC before stripping tzinfo, while all
other backends (including PostgreSQL) used datetime.fromtimestamp()
which produces naive datetimes in the server's local timezone.

On non-UTC servers, this caused PostgreSQL to store update_time values
offset by hours from SQLite, leading to incorrect staleness checks.

Now all backends first convert to UTC, then strip tzinfo only for
SQLite and PostgreSQL (which require naive datetimes).

https://claude.ai/code/session_01TNMxZwEdKgsQJvWtJhzQiQ
2026-02-11 07:19:50 +00:00
Anmol Jaiswal 758d337c76 fix(sessions): use async iteration for VertexAiSessionService.list_sessions pagination
Merge https://github.com/google/adk-python/pull/4435

### Link to Issue or Description of Change

- Closes: #4302

**Problem:**

`VertexAiSessionService.list_sessions()` only returns the first ~100 sessions. The `sessions_iterator` from `api_client.agent_engines.sessions.list()` is an `AsyncPager` — it implements `__aiter__`/`__anext__` for fetching subsequent pages, but the code uses a plain `for` loop which only calls `__iter__`/`__next__`, so it never fetches beyond the first page.

**Solution:**

Changed `for api_session in sessions_iterator` to `async for api_session in sessions_iterator` so the `AsyncPager` actually paginates. Updated the test mock to return an `AsyncIterableList` (supports both sync and async iteration) instead of a bare list, so the tests properly simulate real `AsyncPager` behaviour.

### Testing Plan

**Unit Tests:**

```
$ pytest tests/unittests/sessions/
115 passed, 1 warning in 2.25s
```

The existing `test_list_sessions`, `test_list_sessions_with_pagination`, and `test_list_sessions_all_users` all continue to pass with the updated mock.

Co-authored-by: Liang Wu <wuliang@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4435 from anmolg1997:fix/vertex-ai-session-service-pagination 14c71b607ecbf2215f4b9ba6eb4b0ff6b9eaf740
PiperOrigin-RevId: 868466166
2026-02-10 21:18:51 -08:00
Google Team Member 3cf43e3842 feat: Enhance google credentials config to support externally passed access token
PiperOrigin-RevId: 868390961
2026-02-10 17:21:38 -08:00
Kathy Wu 4aa475145f fix: Fix event loop closed bug in McpSessionManager
Sessions were being erroneously cached and reused across different asyncio event loops, causing "Event loop is closed" in environments with transient loops. This updates the session caching to be loop-aware: before reusing a cached session, check that the stored loop matches the current loop. Also, if session is disconnected and loops do not match, discard the cached entry without calling aclose().

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 868380746
2026-02-10 16:50:53 -08:00
Xiang (Sean) Zhou 7110336788 refactor: Replace check of instance for LlmAgent with hasAttribute check
Co-authored-by: Xiang (Sean) Zhou <seanzhougoogle@google.com>
PiperOrigin-RevId: 868370272
2026-02-10 16:27:20 -08:00
Google Team Member 0abf4cd2c7 feat: Add a demo simple prompt optimizer for the optimization interface
PiperOrigin-RevId: 868367793
2026-02-10 16:21:11 -08:00
Edwin Kim 40c15d0595 feat(cli): Add --auto_create_session flag to adk api_server CLI
Merge https://github.com/google/adk-python/pull/4288

**Please ensure you have read the [contribution guide](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) before creating a pull request.**

### Link to Issue or Description of Change

**1. Link to an existing issue (if applicable):**

- Closes: #4274

**2. Or, if no issue exists, describe the change:**

N/A - Issue exists

### Testing Plan

_Please describe the tests that you ran to verify your changes. This is required
for all PRs that are not small documentation or typo fixes._

**Unit Tests:**

- [X] I have added or updated unit tests for my change.
- [X] All unit tests pass locally.

$ pytest tests/unittests/cli/ -v

============================= test session starts ==============================
platform darwin -- Python 3.11.14, pytest-9.0.2, pluggy-1.6.0
collected 246 items
...
====================== 246 passed, 147 warnings in 21.38s ======================

**Manual End-to-End (E2E) Tests:**

1. Verify CLI flag is recognized:
$ adk api_server --help | grep auto_create_session --auto_create_session
Automatically create a session if it doesn't exist when calling /run.

2. Start server with flag enabled:
$ adk api_server --auto_create_session

3. Test /run endpoint without pre-creating session:
$ curl -X POST http://localhost:8000/run \
  -H "Content-Type: application/json" \
  -d '{"app_name": "my_agent", "user_id": "user1", "session_id": "new_session", "new_message": {"role": "user", "parts": [{"text": "Hello"}]}}'

Expected: Session auto-created, request succeeds (no 404 error).

### Checklist

- [X] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [X] I have performed a self-review of my own code.
- [X] I have commented my code, particularly in hard-to-understand areas.
- [X] I have added tests that prove my fix is effective or that my feature works.
- [X] New and existing unit tests pass locally with my changes.
- [X] I have manually tested my changes end-to-end.
- [X] Any dependent changes have been merged and published in downstream modules.

### Additional context
This PR exposes the existing Runner.auto_create_session functionality (added in commit 8e69a58 / ADK v1.23.0) through the adk api_server CLI command.

Files changed (3 files, ~15 lines):

src/google/adk/cli/cli_tools_click.py - Add --auto_create_session CLI option
src/google/adk/cli/fast_api.py - Pass parameter through get_fast_api_app()
src/google/adk/cli/adk_web_server.py - Store and use in _create_runner()

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4288 from ekimcodes:main 3c8d299a88b21789431dbda488befba7ee3ace81
PiperOrigin-RevId: 868361303
2026-02-10 16:06:01 -08:00
Xuan Yang 2010569010 fix: Preserve thought_signature in function call conversions for interactions API integration
Related: https://github.com/google/adk-python/issues/4311

Co-authored-by: Xuan Yang <xygoogle@google.com>
PiperOrigin-RevId: 868340444
2026-02-10 15:14:18 -08:00
Google Team Member 7af1858f46 feat: Update agent simulator by improving prompts and add environment data
PiperOrigin-RevId: 868324749
2026-02-10 14:37:03 -08:00
Sasha Sobran e6da417292 fix: propagate grounding and citation metadata in streaming responses
Co-authored-by: Sasha Sobran <asobran@google.com>
PiperOrigin-RevId: 868324488
2026-02-10 14:36:21 -08:00
Didier Durand 6ee5126d1c docs: fixing a typo
Merge https://github.com/google/adk-python/pull/3975

### Link to Issue or Description of Change

Fixing various typos: see commit diffs for details

**1. Link to an existing issue (if applicable):**

- Closes: N/A
- Related: N/A

**2. Or, if no issue exists, describe the change:**

Fixing various typos: see commit diffs for details

**Problem:**

Improve quality of repo

**Solution:**
Pull this P/R

### Testing Plan

N/A
**Unit Tests:**

- [N/A] I have added or updated unit tests for my change.
- [X] All unit tests pass locally.

**Manual End-to-End (E2E) Tests:**

N/A

### Checklist

- [X] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [X] I have performed a self-review of my own code.
- [N/A] I have commented my code, particularly in hard-to-understand areas.
- [N/A] I have added tests that prove my fix is effective or that my feature works.
- [X] New and existing unit tests pass locally with my changes.
- [N/A] I have manually tested my changes end-to-end.
- [N/A] Any dependent changes have been merged and published in downstream modules.

### Additional context

N/A

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3975 from didier-durand:fix-typos-b ca1cba4e7afe99bb60efffb4de79a2bfe8522ea8
PiperOrigin-RevId: 868308215
2026-02-10 14:01:58 -08:00
George Weale a88e864755 fix: Add post-invocation token-threshold compaction with event retention
Adds optional token_limit and event_retention_size fields to EventsCompactionConfig. When the latest prompt token count meets/exceeds the threshold, ADK compacts older raw events after the invocation and keeps the last N events un-compacted. Updates prompt history building to apply compaction ranges correctly so retained events remain visible.

Close #4146

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 868297968
2026-02-10 13:38:28 -08:00
Liang Wu 25ec2c6b61 feat(web): Add /health and /version endpoints to ADK web server
These endpoints provide basic health checks and version information for the running ADK server, including the ADK version and Python runtime details. The version information will be used to generate ADK conformance test report.

Co-authored-by: Liang Wu <wuliang@google.com>
PiperOrigin-RevId: 868283421
2026-02-10 13:07:21 -08:00
Salman Chishti 2f0fe97729 ci: Upgrade GitHub Actions for Node 24 compatibility
Merge https://github.com/google/adk-python/pull/4426

## Summary

Upgrade GitHub Actions to their latest versions to ensure compatibility with Node 24, as Node 20 will reach end-of-life in April 2026.

## Changes

| Action | Old Version(s) | New Version | Release | Files |
|--------|---------------|-------------|---------|-------|
| `actions/checkout` | [`v4`](https://github.com/actions/checkout/releases/tag/v4) | [`v6`](https://github.com/actions/checkout/releases/tag/v6) | [Release](https://github.com/actions/checkout/releases/tag/v6) | mypy-new-errors.yml, mypy.yml |
| `actions/setup-python` | [`v5`](https://github.com/actions/setup-python/releases/tag/v5) | [`v6`](https://github.com/actions/setup-python/releases/tag/v6) | [Release](https://github.com/actions/setup-python/releases/tag/v6) | mypy-new-errors.yml, mypy.yml |

## Context

Per [GitHub's announcement](https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/), Node 20 is being deprecated and runners will begin using Node 24 by default starting March 4th, 2026.

### Why this matters

- **Node 20 EOL**: April 2026
- **Node 24 default**: March 4th, 2026
- **Action**: Update to latest action versions that support Node 24

### Security Note

Actions that were previously pinned to commit SHAs remain pinned to SHAs (updated to the latest release SHA) to maintain the security benefits of immutable references.

### Testing

These changes only affect CI/CD workflow configurations and should not impact application functionality. The workflows should be tested by running them on a branch before merging.

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4426 from salmanmkc:upgrade-github-actions-node24 a574f92c72502ae60531163da60f7820e01380f3
PiperOrigin-RevId: 868281419
2026-02-10 13:02:24 -08:00
Salman Chishti f5702d70bf ci: Upgrade GitHub Actions to latest versions
Merge https://github.com/google/adk-python/pull/4427

## Summary

Upgrade GitHub Actions to their latest versions for improved features, bug fixes, and security updates.

## Changes

| Action | Old Version(s) | New Version | Release | Files |
|--------|---------------|-------------|---------|-------|
| `astral-sh/setup-uv` | [`v1`](https://github.com/astral-sh/setup-uv/releases/tag/v1), [`v5`](https://github.com/astral-sh/setup-uv/releases/tag/v5), [`v6`](https://github.com/astral-sh/setup-uv/releases/tag/v6) | [`v7`](https://github.com/astral-sh/setup-uv/releases/tag/v7) | [Release](https://github.com/astral-sh/setup-uv/releases/tag/v7) | mypy-new-errors.yml, mypy.yml, python-unit-tests.yml |
| `webfactory/ssh-agent` | [`v0.9.0`](https://github.com/webfactory/ssh-agent/releases/tag/v0.9.0) | [`v0.9.1`](https://github.com/webfactory/ssh-agent/releases/tag/v0.9.1) | [Release](https://github.com/webfactory/ssh-agent/releases/tag/v0) | analyze-releases-for-adk-docs-updates.yml |

## Why upgrade?

Keeping GitHub Actions up to date ensures:
- **Security**: Latest security patches and fixes
- **Features**: Access to new functionality and improvements
- **Compatibility**: Better support for current GitHub features
- **Performance**: Optimizations and efficiency improvements

### Security Note

Actions that were previously pinned to commit SHAs remain pinned to SHAs (updated to the latest release SHA) to maintain the security benefits of immutable references.

### Testing

These changes only affect CI/CD workflow configurations and should not impact application functionality. The workflows should be tested by running them on a branch before merging.

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4427 from salmanmkc:upgrade-github-actions-node24-general 4aacbae5378233559880ff155e4f478e484c694b
PiperOrigin-RevId: 868263909
2026-02-10 12:20:03 -08:00
George Weale 59e88972ae feat: add add_events_to_memory facade for event-delta
Adds BaseMemoryService.add_events_to_memory(session, events=..., custom_metadata=...) and CallbackContext.add_events_to_memory(events=..., custom_metadata=...) so callers can add memories from an explicit subset of ADK events.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 868261578
2026-02-10 12:14:52 -08:00
Google Team Member de79bf12b5 feat: log exception details before re-raising in MCP session execution
Adds a logger.exception call to capture traceback and error details when an exception occurs during the execution of a coroutine within an MCP session, before re-raising it as a ConnectionError.

PiperOrigin-RevId: 868253547
2026-02-10 11:56:38 -08:00
Didier Durand 80ff067c6b docs: fixing typo in multiple files
Merge https://github.com/google/adk-python/pull/3944

### Link to Issue or Description of Change

**1. Link to an existing issue (if applicable):** N/A

**2. Or, if no issue exists, describe the change:** fixing various typos in multiple files: see commit diffs for details

**Problem:**

Discovered typos while reading ADK repo

**Solution:**

Submitted this PR to fix them

### Testing Plan

N/A: changes only in comments, .md and docstrings.

**Unit Tests:**

- [N/A ] I have added or updated unit tests for my change.
- [X] All unit tests pass locally.

_Please include a summary of passed `pytest` results._

**Manual End-to-End (E2E) Tests:**

N/A

### Checklist

- [X] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [X] I have performed a self-review of my own code.
- [N/A] I have commented my code, particularly in hard-to-understand areas.
- [N/A] I have added tests that prove my fix is effective or that my feature works.
- [X] New and existing unit tests pass locally with my changes.
- [N/A] I have manually tested my changes end-to-end.
- [N/A] Any dependent changes have been merged and published in downstream modules.

### Additional context

N/A

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3944 from didier-durand:fix-typos-a 02378a488d9a87ac9b6b7397fe9ad7c393faf16a
PiperOrigin-RevId: 868245940
2026-02-10 11:38:22 -08:00
sarojrout e0b9712a49 fix: Add endpoints to get/list artifact version metadata
This change introduces new FastAPI endpoints in adk_web_server.py and corresponding client methods in adk_web_server_client.py to allow fetching metadata for artifact versions without downloading the artifact content

Close #3710

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 868217569
2026-02-10 10:40:54 -08:00
George Weale 7c7d25a4a6 fix: Support escaped curly braces in instruction templates
Close #3527

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 868199186
2026-02-10 10:04:39 -08:00
Kathy Wu ec660ed4f0 chore: Add experimental tag to SkillToolset
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 867816959
2026-02-09 16:07:35 -08:00
Filipe Caixeta 19b607684f fix: Strip timezone for PostgreSQL timestamps in DatabaseSessionService
Merge https://github.com/google/adk-python/pull/4365

## Summary
- Fixes `DataError` when using PostgreSQL with `asyncpg` for session storage
- PostgreSQL's default `TIMESTAMP` type is `WITHOUT TIME ZONE`, which cannot accept timezone-aware datetime objects
- The existing code handled this for SQLite but not PostgreSQL - this fix applies the same timezone stripping

## Error
When creating a session with PostgreSQL + asyncpg, the following error occurs:

```
sqlalchemy.dialects.postgresql.asyncpg.Error: <class 'asyncpg.exceptions.DataError'>:
invalid input for query argument $5: datetime.datetime(2026, 2, 3, 21, 32, 50, 353909,
tzinfo=datetime.timezone.utc) (can't subtract offset-naive and offset-aware datetimes)
```

During the INSERT:
```sql
INSERT INTO sessions (app_name, user_id, id, state, create_time, update_time)
VALUES ($1, $2, $3, $4, $5, $6)
```

Where `$5` and `$6` are timezone-aware datetimes being inserted into `TIMESTAMP WITHOUT TIME ZONE` columns.

## Root Cause
Commit 1063fa53 changed from database-generated timestamps (`func.now()`) to explicit Python datetimes (`datetime.now(timezone.utc)`). The SQLite case was handled by stripping the timezone, but PostgreSQL was overlooked.

## Test plan
- [x] Verified fix resolves the error when creating sessions with PostgreSQL + asyncpg
- [ ] Existing unit tests pass

Fixes regression from #1733

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4365 from filipecaixeta:fix-postgresql-timestamp-timezone 9d788ba99e7167a53962d93e59a80f78af091ca9
PiperOrigin-RevId: 867800330
2026-02-09 15:27:42 -08:00
Kathy Wu 8d0279251c feat: Add SkillToolset to adk
Currently supports load skill and load skill resource, scripts support coming later.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 867756231
2026-02-09 13:46:49 -08:00
George Weale f50847460f fix: Per-session locking and row-level locking in DatabaseSessionService.append_event
This change introduces an in-process `asyncio.Lock` per session to serialize `append_event` calls for the same session ID within a single process. For supported database dialects (MySQL, PostgreSQL, MariaDB), it also uses `SELECT ... FOR UPDATE` to acquire row-level locks on the session, app state, and user state records, preventing race conditions across different processes or database connections. A new test case verifies that concurrent updates to stale session objects correctly merge all state changes.

Close #1049

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 867752676
2026-02-09 13:38:38 -08:00
Benson Wang 32ee07df01 fix: prompt token may be None in streaming mode
Merge https://github.com/google/adk-python/pull/3462

**Please ensure you have read the [contribution guide](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) before creating a pull request.**

### Link to Issue or Description of Change

**1. Link to an existing issue (if applicable):**

- Closes: #_issue_number_
- Related: #_issue_number_

**2. Or, if no issue exists, describe the change:**

**Problem:**
When using adk in streaming mode, `usage_metadata.prompt_token_count` may be `None` which will emit log
```Invalid type NoneType for attribute 'gen_ai.usage.input_tokens' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types```

**Solution:**
Skip setting span attribute if prompt token count is None

**Unit Tests:**

- [x] All unit tests pass locally.

_Please include a summary of passed `pytest` results._

### Checklist

- [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly in hard-to-understand areas.
- [x] I have added tests that prove my fix is effective or that my feature works.
- [x] New and existing unit tests pass locally with my changes.
- [x] I have manually tested my changes end-to-end.
- [x] Any dependent changes have been merged and published in downstream modules.

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3462 from wsa-2002:prompt-token-count-may-be-none-in-streaming-mode 94666862f70ed2577d5c55485e67f6da36a57bc6
PiperOrigin-RevId: 867693355
2026-02-09 11:24:22 -08:00
Liang Wu 43c437e38b feat(conformance): add report generation to adk conformance test command
Added `generate_report` and `report_dir` CLI args to the command.

Co-authored-by: Liang Wu <wuliang@google.com>
PiperOrigin-RevId: 867689055
2026-02-09 11:15:11 -08:00
George Weale d2dba27134 fix: Pass invocation_id from /run endpoint to Runner.run_async
Close #3290

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 867684592
2026-02-09 11:15:00 -08:00
George Weale 663cb75b32 fix: Conditionally preserve function call IDs in LLM requests
Function call and response IDs generated by ADK are now preserved in the LLM request contents when the agent is using a Gemini model with `use_interactions_api` enabled

Close #4381

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 867675945
2026-02-09 10:46:55 -08:00
George Weale 64a44c2897 fix: Migrate VertexAiMemoryBankService to use the async Vertex AI client
This change updates the VertexAiMemoryBankService to utilize the asynchronous interface provided by `vertexai.Client().aio`. This involves:
-   Retrieving the async client via `_get_api_client().aio`.
-   Awaiting calls to `generate` and `retrieve`.
-   Using `async for` to iterate over the results of the `retrieve` method, as it now returns an async iterator

Close #4386

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 867675311
2026-02-09 10:45:15 -08:00
George Weale 0758f877b1 chore: remove bare excepts
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 867666149
2026-02-09 10:25:03 -08:00
George Weale fd8a9e3962 fix: Handle list values in Gemini schema sanitization
The schema sanitization utility now recursively processes list items, ensuring that properties with list values (e.g., "required") are correctly handled and not altered.

Close #4363

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 867663267
2026-02-09 10:20:08 -08:00
Dinesh Thumma 6bc70a6bab fix(mcp): used logger to log instead of print
Merge https://github.com/google/adk-python/pull/4324

**Please ensure you have read the [contribution guide](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) before creating a pull request.**

### Link to Issue or Description of Change

**1. Link to an existing issue (if applicable):**

- Closes: #4320

**2. Or, if no issue exists, describe the change:**

**Problem:**
 Was using print instead of logger for warning message

**Solution:*
Refactored

### Testing Plan

**Unit Tests:**

- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.

_Please include a summary of passed `pytest` results._

**Manual End-to-End (E2E) Tests:**

### Checklist

- [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly in hard-to-understand areas.
- [x] I have added tests that prove my fix is effective or that my feature works.
- [x] New and existing unit tests pass locally with my changes.
- [x] I have manually tested my changes end-to-end.
- [ ] Any dependent changes have been merged and published in downstream modules.

### Additional context

_Add any other context or screenshots about the feature request here._

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4324 from DineshThumma9:logger_in_mcp_session_clean 5eaa9bdc8c3c6697e75b0e876f043d496dd8ee95
PiperOrigin-RevId: 867601662
2026-02-09 07:48:36 -08:00
Wei Sun (Jack) a2e43aaf19 chore(version): Limits sphinx under 9 for docs
Co-authored-by: Wei Sun (Jack) <weisun@google.com>
PiperOrigin-RevId: 866569793
2026-02-06 12:34:07 -08:00
Kathy Wu e25227da5e feat: Add a load MCP resource tool
If the user specifies use_mcp_resources=True in their MCPToolset, the agent will be able to load resources with the load_mcp_resource_tool.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 866539602
2026-02-06 11:18:32 -08:00
Kathy Wu c7362100eb feat: Add models.py and prompt.py to adk/skills to use in skill toolset
Also redefined schemas in models.py to be pydantic.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 866270203
2026-02-05 22:06:58 -08:00
Google Team Member 483c5bab94 ADK changes
PiperOrigin-RevId: 866173091
2026-02-05 16:55:06 -08:00
Google Team Member 0b9cbd2d42 feat: Add experimental agent tool simulator
PiperOrigin-RevId: 866160711
2026-02-05 16:21:48 -08:00
Matthew Chan 781f605a1e feat: add base_url option to Gemini LLM class
PiperOrigin-RevId: 866146209
2026-02-05 15:44:00 -08:00
Kacper Jawoszek d9e8e9cf32 fix: otel_to_cloud flag help text points at Cloud Run instead of Agent Engine
Co-authored-by: Kacper Jawoszek <jawoszek@google.com>
PiperOrigin-RevId: 866122815
2026-02-05 14:49:02 -08:00
Wei Sun (Jack) 93a085ad87 chore(version): Bumps version to 1.24.1 patch
Co-authored-by: Wei Sun (Jack) <weisun@google.com>
PiperOrigin-RevId: 866107525
2026-02-05 14:13:02 -08:00
Google Team Member 6645aa07fd feat: Add experimental agent tool simulator
PiperOrigin-RevId: 866100611
2026-02-05 13:57:57 -08:00
Yifan Wang 3686a3a98f chore: update adk web files, updated eval dialog colors, and fixed a2ui component types
Co-authored-by: Yifan Wang <wanyif@google.com>
PiperOrigin-RevId: 866057812
2026-02-05 12:16:54 -08:00
Yifan Wang ae993e884f fix: adding back deprecated eval endpoint for web until we migrate
Co-authored-by: Yifan Wang <wanyif@google.com>
PiperOrigin-RevId: 866049699
2026-02-05 11:58:04 -08:00
George Weale bb89466623 chore: Improve type hints and handle None values in ADK utils
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 866025998
2026-02-05 11:04:46 -08:00
Xuan Yang adbc37fea1 feat: Add progress_callback support to MCPTool and MCPToolset
Fixes: https://github.com/google/adk-python/issues/3811

Co-authored-by: Xuan Yang <xygoogle@google.com>
PiperOrigin-RevId: 866025995
2026-02-05 11:04:36 -08:00
George Weale 9b112e2d13 fix: Refactor context filtering to better handle multi-turn invocations
The definition of an "invocation" for context filtering has been updated. An invocation now starts with a user message and can include multiple model turns (like the tool calls and responses) until the next user message. The filtering logic has been rewritten to identify invocation start points based on human user messages

Close #4296

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 866023290
2026-02-05 10:57:56 -08:00
Google Team Member a08bf62b95 feat(otel): add extra attributes to span generated with opentelemetry-instrumentation-google-genai
PiperOrigin-RevId: 865825792
2026-02-05 01:58:30 -08:00
Liang Wu e752bbb756 chore: Remove unused tzlocal dependency and logging
The `tzlocal` library and the logging of the local timezone were not used in the `DatabaseSessionService` logic.

Co-authored-by: Liang Wu <wuliang@google.com>
PiperOrigin-RevId: 865677320
2026-02-04 18:49:55 -08:00
133 changed files with 8051 additions and 579 deletions
@@ -24,7 +24,7 @@ jobs:
python-version: '3.11'
- name: Load adk-bot SSH Private Key
uses: webfactory/ssh-agent@v0.9.0
uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.ADK_BOT_SSH_PRIVATE_KEY }}
+3 -3
View File
@@ -15,17 +15,17 @@ jobs:
python-version: ['3.10', '3.11', '3.12', '3.13',]
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v7
- name: Generate Baseline (Main)
run: |
+3 -3
View File
@@ -14,13 +14,13 @@ jobs:
python-version: ['3.10', '3.11', '3.12', '3.13',]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v1
uses: astral-sh/setup-uv@v7
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
- name: Install dependencies
run: |
+7
View File
@@ -1,5 +1,12 @@
# 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
+33
View File
@@ -119,6 +119,39 @@ type.
1. Set `CREDENTIALS_TYPE=AuthCredentialTypes.OAUTH2` in `agent.py` and run the agent
### With Agent Engine and Gemini Enterprise
This mode is useful when you deploy the agent to Vertex AI Agent Engine and
want to make it available in Gemini Enterprise, allowing the agent to access
BigQuery on behalf of the end-user. This setup uses OAuth 2.0 managed by
Gemini Enterprise.
1. Create an Authorization resource in Gemini Enterprise by following the guide at
[Register and manage ADK agents hosted on Vertex AI Agent Engine](https://docs.cloud.google.com/gemini/enterprise/docs/register-and-manage-an-adk-agent) to:
* Create OAuth 2.0 credentials in your Google Cloud project.
* Create an Authorization resource in Gemini Enterprise, linking it to your
OAuth 2.0 credentials. When creating this resource, you will define a
unique identifier (`AUTH_ID`).
2. Prepare the sample agent for consuming the access token provided by Gemini
Enterprise and deploy to Vertex AI Agent Engine.
* Set `CREDENTIALS_TYPE=AuthCredentialTypes.HTTP` in `agent.py`. This
configures the agent to use access tokens provided by Gemini Enterprise and
provided by Agent Engine via the tool context.
* Replace `AUTH_ID` in `agent.py` with your authorization resource identifier
from step 1.
* [Deploy your agent to Vertex AI Agent Engine](https://google.github.io/adk-docs/deploy/agent-engine/).
3. [Register your deployed agent with Gemini Enterprise](https://docs.cloud.google.com/gemini/enterprise/docs/register-and-manage-an-adk-agent#register-an-adk-agent), attaching the
Authorization resource `AUTH_ID`. When this agent is invoked through Gemini
Enterprise, an access token obtained using these OAuth credentials will be
passed to the agent and made available in the ADK `tool_context` under the key
`AUTH_ID`, which `agent.py` is configured to use.
Once registered, users interacting with your agent via Gemini Enterprise will
go through an OAuth consent flow, and Agent Engine will provide the agent with
the necessary access tokens to call BigQuery APIs on their behalf.
## Sample prompts
* which weather datasets exist in bigquery public data?
+11
View File
@@ -56,6 +56,17 @@ elif CREDENTIALS_TYPE == AuthCredentialTypes.SERVICE_ACCOUNT:
# https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys
creds, _ = google.auth.load_credentials_from_file("service_account_key.json")
credentials_config = BigQueryCredentialsConfig(credentials=creds)
elif CREDENTIALS_TYPE == AuthCredentialTypes.HTTP:
# Initialize the tools to use the externally provided access token. One such
# use case is creating an authorization resource `AUTH_ID` in Gemini
# Enterprise and using it to register an ADK agent deployed to Vertex AI
# Agent Engine with Gemini Enterprise. See for more details:
# https://docs.cloud.google.com/gemini/enterprise/docs/register-and-manage-an-adk-agent.
# This access token will be passed to the agent via the tool context, with
# the key `AUTH_ID`.
credentials_config = BigQueryCredentialsConfig(
external_access_token_key="AUTH_ID"
)
else:
# Initialize the tools to use the application default credentials.
# https://cloud.google.com/docs/authentication/provide-credentials-adc
+1 -1
View File
@@ -159,7 +159,7 @@ def _adk_agent(
class _UserAgent(base_agent.BaseAgent):
"""An agent that wraps the provided environment and simulates an user."""
"""An agent that wraps the provided environment and simulates a user."""
env: Env
+1 -1
View File
@@ -103,7 +103,7 @@ class _ADKAgent(tool_calling_agent.ToolCallingAgent):
max_num_steps: The maximum number of steps to run the agent.
Returns:
The result of the solve.
The result of the solve function.
Raises:
- ValueError: If the LLM inference failed.
@@ -0,0 +1,15 @@
# 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
@@ -0,0 +1,166 @@
# 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,
)
],
)
@@ -0,0 +1,161 @@
# 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())
@@ -52,6 +52,7 @@ Allowed directory: {_allowed_path}
'get_file_info',
'list_allowed_directories',
],
use_mcp_resources=True,
)
],
)
@@ -13,6 +13,7 @@
# limitations under the License.
import asyncio
import json
import os
from pathlib import Path
import sys
@@ -45,6 +46,24 @@ def get_cwd() -> str:
return str(Path.cwd())
# Add a resource for testing with JSON data
@mcp.resource(
name="sample_data",
uri="file:///sample_data.json",
mime_type="application/json",
)
def sample_data() -> str:
data = {
"users": [
{"id": 1, "name": "Alice", "role": "admin"},
{"id": 2, "name": "Bob", "role": "user"},
{"id": 3, "name": "Charlie", "role": "user"},
],
"settings": {"theme": "dark", "notifications": True},
}
return json.dumps(data, indent=2)
# Graceful shutdown handler
async def shutdown(signal, loop):
"""Cleanup tasks tied to the service's shutdown."""
@@ -0,0 +1,15 @@
# 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
@@ -0,0 +1,54 @@
# 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.
"""Example agent demonstrating the use of SkillToolset."""
import inspect
from google.adk import Agent
from google.adk.skills import models
from google.adk.tools import skill_toolset
greeting_skill = models.Skill(
frontmatter=models.Frontmatter(
name="greeting-skill",
description=(
"A friendly greeting skill that can say hello to a specific person."
),
),
instructions=(
"Step 1: Read the 'references/hello_world.txt' file to understand how"
" to greet the user. Step 2: Return a greeting based on the reference."
),
resources=models.Resources(
references={
"hello_world.txt": "Hello! 👋👋👋 So glad to have you here! ✨✨✨",
"example.md": "This is an example reference.",
},
),
)
my_skill_toolset = skill_toolset.SkillToolset(skills=[greeting_skill])
root_agent = Agent(
model="gemini-2.5-flash",
name="skill_user_agent",
description="An agent that can use specialized skills.",
instruction=(
"You are a helpful assistant that can leverage skills to perform tasks."
),
tools=[
my_skill_toolset,
],
)
+1 -2
View File
@@ -143,7 +143,7 @@ docs = [
"autodoc_pydantic",
"furo",
"myst-parser",
"sphinx",
"sphinx<9.0.0",
"sphinx-autodoc-typehints",
"sphinx-rtd-theme",
]
@@ -219,7 +219,6 @@ asyncio_mode = "auto"
python_version = "3.10"
exclude = ["tests/", "contributing/samples/"]
plugins = ["pydantic.mypy"]
# Start with non-strict mode, and swtich to strict mode later.
strict = true
disable_error_code = ["import-not-found", "import-untyped", "unused-ignore"]
follow_imports = "skip"
+4 -2
View File
@@ -59,7 +59,9 @@ def _to_a2a_context_id(app_name: str, user_id: str, session_id: str) -> str:
)
def _from_a2a_context_id(context_id: str) -> tuple[str, str, str]:
def _from_a2a_context_id(
context_id: str | None,
) -> tuple[str, str, str] | tuple[None, None, None]:
"""Converts an A2A context id to app name, user id and session id.
if context_id is None, return None, None, None
if context_id is not None, but not in the format of
@@ -69,7 +71,7 @@ def _from_a2a_context_id(context_id: str) -> tuple[str, str, str]:
context_id: The A2A context id.
Returns:
The app name, user id and session id.
The app name, user id and session id, or (None, None, None) if invalid.
"""
if not context_id:
return None, None, None
+32
View File
@@ -14,6 +14,8 @@
from __future__ import annotations
from collections.abc import Mapping
from collections.abc import Sequence
from typing import Any
from typing import Optional
from typing import TYPE_CHECKING
@@ -28,6 +30,7 @@ if TYPE_CHECKING:
from ..artifacts.base_artifact_service import ArtifactVersion
from ..auth.auth_credential import AuthCredential
from ..auth.auth_tool import AuthConfig
from ..events.event import Event
from ..events.event_actions import EventActions
from ..sessions.state import State
from .invocation_context import InvocationContext
@@ -219,3 +222,32 @@ class CallbackContext(ReadonlyContext):
await self._invocation_context.memory_service.add_session_to_memory(
self._invocation_context.session
)
async def add_events_to_memory(
self,
*,
events: Sequence[Event],
custom_metadata: Mapping[str, object] | None = None,
) -> None:
"""Adds an explicit list of events to the memory service.
Uses this callback's current session identifiers as memory scope.
Args:
events: Explicit events to add to memory.
custom_metadata: Optional standard metadata for memory generation.
Raises:
ValueError: If memory service is not available.
"""
if self._invocation_context.memory_service is None:
raise ValueError(
"Cannot add events to memory: memory service is not available."
)
await self._invocation_context.memory_service.add_events_to_memory(
app_name=self._invocation_context.session.app_name,
user_id=self._invocation_context.session.user_id,
session_id=self._invocation_context.session.id,
events=events,
custom_metadata=custom_metadata,
)
+2 -2
View File
@@ -469,7 +469,7 @@ class LlmAgent(BaseAgent):
self.__maybe_save_output_to_state(event)
yield event
if ctx.should_pause_invocation(event):
# Do not pause immediately, wait until the long running tool call is
# Do not pause immediately, wait until the long-running tool call is
# executed.
should_pause = True
if should_pause:
@@ -479,7 +479,7 @@ class LlmAgent(BaseAgent):
events = ctx._get_events(current_invocation=True, current_branch=True)
if events and any(ctx.should_pause_invocation(e) for e in events[-2:]):
return
# Only yield an end state if the last event is no longer a long running
# Only yield an end state if the last event is no longer a long-running
# tool call.
ctx.set_agent_state(self.name, end_of_agent=True)
yield self._create_agent_state_event(ctx)

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