The `can_use_output_schema_with_tools` function now checks if a model is a LiteLlm instance by inspecting its type's Method Resolution Order, rather than directly importing `LiteLlm`
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 882253446
This change adds logic to extract and re-embed the `thought_signature` field associated with function calls in Gemini models when converting between LiteLLM's ChatCompletionMessageToolCall and ADK's types.Part
Close#4650
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 882212223
The _update_type_string function now recursively processes "properties" at any level of the schema, ensuring that all "type" fields within nested objects are correctly lowercased. This improves handling of complex
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 882050939
The flow for integrating a new auth method will be as follows. The ADK framework contributor will
1. extend the `AuthScheme` to create their own within `adk/auth/auth_scheme.py`
2. implement `BaseAuthProvider` within their dedicated directory in `adk/integrations/auth`
3. do the static registration of the new scheme and provider with AuthProviderRegistry of CredentialManager.
PiperOrigin-RevId: 881775983
The classes `BaseSamplingResult` and `BaseAgentWithScores` are renamed to `SamplingResult` and `AgentWithScores`, respectively. The corresponding TypeVars are renamed to `SamplingResultT` and `AgentWithScoresT` to avoid naming conflicts. Imports across ADK are updated to reflect these changes.
These changes were made to better align with the naming philosophy of ADK.
Co-authored-by: Keyur Joshi <keyurj@google.com>
PiperOrigin-RevId: 881635593
**1. Link to an existing issue (if applicable):**
- Closes: #_issue_number_
- Related: #_issue_number_
**2. Or, if no issue exists, describe the change:**
**Problem:**
- Currently, the ADK doesn't expose telemetry for reasoning tokens limit, reasoning tokens and system instruction tokens.
- In addition to this, the OpenTelemetry semantic conventions for Generative AI do not yet formally include usage fields for `reasoning_tokens_limit`, `reasoning_tokens`, and `system_instruction_tokens`.
- Setting these natively under the standard `gen_ai.usage.*` namespace risks colliding with future official OTel specifications if determining the structure or naming changes prior to stabilization.
**Solution:**
Namespace these telemetry attributes as experimental by adding the `experimental.` prefix to their keys in telemetry/tracing.py.
(For example, changing them to `gen_ai.usage.experimental.reasoning_tokens`).
This safely scopes these usage metrics until they are officially standardized by the OTel community.
### 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._
All existing tests across `google-adk` pass correctly.
**Manual End-to-End (E2E) Tests:**
N/A - This is purely a key rename for OpenTelemetry exports and does not negatively impact functional framework logic.
### 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
None
Co-authored-by: Achuth Narayan Rajagopal <achuthr@google.com>
PiperOrigin-RevId: 881568099
This change updates the LiteLLM integration to correctly process responses with a "length" finish reason. Specifically, it:
- Maps "length" to types.FinishReason.MAX_TOKENS.
- Checks for truncated JSON arguments within tool calls when the finish reason is "length" and reports an error if parsing fails.
Close#4482
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 881514246
Merge https://github.com/google/adk-python/pull/4693
### Link to Issue or Description of Change
**1. Link to an existing issue:**
- Closes: #4673
- Related: #3562, PR #3662
**Problem:**
When `EventsCompactionConfig` is configured on an `App`, the compaction mechanism correctly summarizes old events, but `Runner._get_or_create_session` still calls `get_session()` **without any `GetSessionConfig`**, loading the **full event history** on every invocation.
This means compaction only reduces the LLM context window — it does nothing to reduce the session loading overhead. As reported in #4673, real-world sessions with ~4,800 events take 70+ seconds to load via `get_session` even though compaction summaries exist.
**Solution:**
Add a `get_session_config` field to `RunConfig` and thread it through all Runner entry points so the session service can filter events during loading:
- **`RunConfig.get_session_config`**: New optional `GetSessionConfig` field that users can set to control `num_recent_events` or `after_timestamp`.
- **`_get_or_create_session`**: Updated to accept and forward `get_session_config` to `session_service.get_session()`.
- **All entry points updated**: `run_async`, `run_live`, `rewind_async`, and `run_debug` all pass the config through.
This subsumes the approach in stale PR #3662 (open since Dec 2025 with unaddressed review feedback) while also addressing the reviewer's requested changes (pass config in `rewind_async`, initialize in `run_debug`, add comprehensive tests).
**Usage:**
```python
from google.adk.agents.run_config import RunConfig
from google.adk.sessions.base_session_service import GetSessionConfig
# Only load the 50 most recent events — sufficient when compaction is active
run_config = RunConfig(
get_session_config=GetSessionConfig(num_recent_events=50),
)
async for event in runner.run_async(
user_id=user_id,
session_id=session_id,
new_message=message,
run_config=run_config,
):
...
```
### Testing Plan
**Unit Tests:**
- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.
5 new tests added covering all entry points:
- `test_run_async_passes_get_session_config` — verifies `run_async` forwards config
- `test_run_live_passes_get_session_config` — verifies `run_live` forwards config
- `test_rewind_async_passes_get_session_config` — verifies `rewind_async` forwards config
- `test_run_debug_passes_get_session_config` — verifies `run_debug` forwards config
- `test_get_session_config_limits_events` — verifies `InMemorySessionService` actually limits events
```
======================= 39 passed, 10 warnings in 2.44s ========================
```
### 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] Any dependent changes have been merged and published in downstream modules.
### Additional context
This is the minimal viable fix — it gives users explicit control over session loading. A follow-up enhancement could automatically derive `GetSessionConfig` from `EventsCompactionConfig` (e.g., only load events after the last compaction timestamp), but that requires additional design decisions about the feedback loop between compaction and session loading.
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4693 from OiPunk:codex/adk-python-4673-get-session-config 85a814e679095c9fb20e4389320b51972bde6ce1
PiperOrigin-RevId: 881479524
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:
The agent's specific version wasn't being tracked in our telemetry data, limiting our ability to trace issues to specific agent versions. This change introduces the gen_ai.agent.version attribute to span context, defaulting to an empty string if omitted for backwards compatibility.
Solution:
We want to capture the specific version of an agent during execution by adding an optional version field to the base agent configurations (BaseAgent, BaseAgentConfig).
This solution was chosen because exposing this field directly to OpenTelemetry span attributes (gen_ai.agent.version) ensures the version is automatically recorded alongside other existing metadata (like name and description) during invocation. Defaulting the value to an empty string ensures backwards compatibility without breaking existing agent implementations that do not specify a version.
Testing Plan
- Added test_trace_agent_invocation_with_version to verify that the gen_ai.agent.version attribute is correctly captured when agent.version is populated.
- Updated existing telemetry span tests to ensure gen_ai.agent.version safely defaults to an empty string ('') when no version is provided.
Unit Tests:
- I have added or updated unit tests for my change.
- All unit tests pass locally.
Manual End-to-End (E2E) Tests:
- Tested on Agent Engine and in a local deployment.
Checklist
[x] I have read the 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
Add any other context or screenshots about the feature request here.
Co-authored-by: Achuth Narayan Rajagopal <achuthr@google.com>
PiperOrigin-RevId: 881234134
The BigQuery agent analytics plugin now catches cloud_exceptions.Conflict when creating or updating views, logging a debug message for concurrent updates.
Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 880961611
Allows optimization of the root agent instructions from the CLI using GEPA (https://gepa-ai.github.io/gepa/).
You can specify config files for sampler (which uses LocalEvalService to evaluate the agent during optimization) and optimizer (GEPA parameters).
Co-authored-by: Keyur Joshi <keyurj@google.com>
PiperOrigin-RevId: 880937886
During multi-agent simulation with Vertex LLMs, some chunks trigger filters or stream timeouts
causing the `generated_content` object to be entirely empty (None) instead of possessing an empty `parts` array.
This caused the simulator to fatally crash with `AttributeError: 'NoneType' object has no attribute 'parts'`.
Added explicit checks to guard against this payload issue.
PiperOrigin-RevId: 880282184
The class name `MCPTool` is changed to `McpTool`. This update resolves deprecation warnings by using the preferred naming convention.
PiperOrigin-RevId: 879789494
Introduces ToolExecutionError and ToolErrorType to standardize error reporting for tool failures. Updates trace_tool_call and function execution handlers to extract and record error.type semantics.
In a subsequent PR, existing tools would be retrofitted to report this new error code.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
1. Link to an existing issue (if applicable):
Closes: Support Error Codes in Traces sent during Tool Call Failures #4614
2. Or, if no issue exists, describe the change:
If applicable, please follow the issue templates to provide as much detail as
possible.
Problem:
A clear and concise description of what the problem is.
Solution:
A clear and concise description of what you want to happen and why you choose
this solution.
Testing Plan
Added tests for different supported error code scenarios (InternalServerError, Timeout) and an unsupported error code scenario (ValueError) where the error.code falls back to the error's class name.
Unit Tests:
- I have added or updated unit tests for my change.
- All unit tests pass locally.
Please include a summary of passed pytest results.
Manual End-to-End (E2E) Tests:
Tested manually using adk web
Checklist
[x] I have read the 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
Add any other context or screenshots about the feature request here.
Co-authored-by: Achuth Narayan Rajagopal <achuthr@google.com>
PiperOrigin-RevId: 879751384
The class name `MCPTool` is changed to `McpTool`. This update resolves deprecation warnings by using the preferred naming convention.
PiperOrigin-RevId: 879742731
This change enables sending PDF files as "document" blocks in user messages to the Anthropic API. PDF parts are base64 encoded. Similar to images, PDF documents are filtered out from assistant/model turns, as they are not supported by the Claude API in that context.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 879742633
Merge https://github.com/google/adk-python/pull/4200
**Problem:**
The current implementation of `SessionService`, `Event`, and other core components relies directly on `time.time()` and `uuid.uuid4()`. These standard library functions are non-deterministic, which prevents the ADK from being used in deterministic execution environments (like Temporal workflows). In such environments, logic that depends on time or random IDs must be replayable and consistent across executions.
**Solution:**
Introduced `google.adk.platform.time` and `google.adk.platform.uuid` modules to abstract time and UUID generation.
- Created `google.adk.platform.time` with `get_time()` and `set_time_provider()`.
- Created `google.adk.platform.uuid` with `new_uuid()` and `set_id_provider()`.
- Updated `Event`, `SessionService`, `InvocationContext`, and `SqliteSessionService` to use these new platform abstractions instead of `time` and `uuid` directly.
This allows runtimes to inject deterministic providers (e.g., Temporal's `workflow.now()` and side-effect-safe UUIDs) when running in a deterministic context, while defaulting to standard `time` and `uuid` for standard execution.
### Testing Plan
**Unit Tests:**
- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.
Added new unit tests for the platform modules:
- [tests/unittests/platform/test_time.py](cci:7://file:///usr/local/google/home/marcusmotill/Documents/code/temporal/adk-python-temporal/tests/unittests/platform/test_time.py:0:0-0:0): Verifies `get_time`, provider overriding, and resetting.
- [tests/unittests/platform/test_uuid.py](cci:7://file:///usr/local/google/home/marcusmotill/Documents/code/temporal/adk-python-temporal/tests/unittests/platform/test_uuid.py:0:0-0:0): Verifies `new_uuid`, provider overriding, and resetting.
- Updated [tests/unittests/artifacts/test_artifact_service.py](cci:7://file:///usr/local/google/home/marcusmotill/Documents/code/temporal/adk-python-temporal/tests/unittests/artifacts/test_artifact_service.py:0:0-0:0) to match the new patterns.
**Manual End-to-End (E2E) Tests:**
Verified that the ADK continues to function correctly in standard (non-deterministic) environments, ensuring the default providers for time and UUIDs work as expected.
- Ran existing agent workflows to confirm session creation and event logging still produce valid timestamps and IDs.
### 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
These changes are a prerequisite for the [Temporal integration](https://github.com/temporalio/sdk-python/pull/1282), allowing the ADK to run safely inside Temporal workflows without breaking determinism guarantees.
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4200 from marcusmotill:motill/durable-support 61d0e315f2d29304bdf89b084cf820751c5da246
PiperOrigin-RevId: 879662233
* Update the `toolbox-adk` package version to latest.
* Update `README.md` with the latest MCP Toolbox server version.
* Simplify Toolbox agent sample code with default toolset.
* Fix an error that says `cannot invoke close() on None`.
* Update Gemini model to `2.5` as `2.0` is deprecated.
PiperOrigin-RevId: 879400015
To use ADK tools, users can specify the tool name in a skill object's `additional_tools` and pass the tool in when initializing a SkillToolset.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 879230409
This change introduces several improvements to the BigQuery Agent Analytics Plugin:
* **Fix 1 (High):** Error callbacks (`on_model_error_callback`, `on_tool_error_callback`) now emit `status="ERROR"` instead of defaulting to `"OK"`.
* **Fix 2 (Medium):** Schema upgrade now detects missing sub-fields in nested RECORD columns via a new recursive helper. The version label is now stamped only after the `update_table` call succeeds, ensuring failures can be retried.
* **Fix 3 (Medium):** Multi-loop `shutdown()` now drains batch processors on non-current event loops using `run_coroutine_threadsafe` before closing transports.
* **Fix 4 (Medium):** Session state is truncated before logging to prevent oversized payloads.
* **Fix 5 (Low):** String system prompts are now truncated during content parsing.
* **Fix 6 (Low):** Removed the unused `_HITL_TOOL_NAMES` frozenset.
Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 879147684
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:
The agent's specific version wasn't being tracked in our telemetry data, limiting our ability to trace issues to specific agent versions. This change introduces the gen_ai.agent.version attribute to span context, defaulting to an empty string if omitted for backwards compatibility.
Solution:
We want to capture the specific version of an agent during execution by adding an optional version field to the base agent configurations (BaseAgent, BaseAgentConfig).
This solution was chosen because exposing this field directly to OpenTelemetry span attributes (gen_ai.agent.version) ensures the version is automatically recorded alongside other existing metadata (like name and description) during invocation. Defaulting the value to an empty string ensures backwards compatibility without breaking existing agent implementations that do not specify a version.
Testing Plan
- Added test_trace_agent_invocation_with_version to verify that the gen_ai.agent.version attribute is correctly captured when agent.version is populated.
- Updated existing telemetry span tests to ensure gen_ai.agent.version safely defaults to an empty string ('') when no version is provided.
Unit Tests:
- I have added or updated unit tests for my change.
- All unit tests pass locally.
Manual End-to-End (E2E) Tests:
- Tested on Agent Engine and in a local deployment.
Checklist
[x] I have read the 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
Add any other context or screenshots about the feature request here.
Co-authored-by: Achuth Narayan Rajagopal <achuthr@google.com>
PiperOrigin-RevId: 878835568
Merge https://github.com/google/adk-python/pull/4648
**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: #4647
- Related: #3429, #3430
**2. Or, if no issue exists, describe the change:**
**Problem:**
`AgentLoader.list_agents()` returns every non-hidden subdirectory in the agents directory, regardless of whether it contains a valid agent definition. This causes non-agent directories (e.g. `tmp/`, `data/`, `utils/`) to appear in the `/list-apps` API response. This affects both the ADK web UI agent selector and any production deployment depending on this API.
**Solution:**
Reuse the existing `_determine_agent_language()` method inside `list_agents()` to verify each candidate directory contains at least one recognized agent file (`root_agent.yaml`, `agent.py`, or `__init__.py`). Directories that fail this check are excluded from the result. This avoids introducing any new methods or abstractions and keeps the check lightweight (filesystem only, no agent imports).
### Testing Plan
**Unit Tests:**
- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.
27 passed in 2.85s:
pytest tests/unittests/cli/utils/test_agent_loader.py -v
======================= 27 passed, 14 warnings in 2.85s ========================
Added `test_list_agents_excludes_non_agent_directories` which creates a temp directory with three valid agent types (package with `__init__.py`, module with `agent.py`, YAML with `root_agent.yaml`) and three non-agent directories, and asserts only the valid agents are listed.
**Screenshots / Video:**
| Before (non-agent directories listed) | After (only valid agents listed) |
|----------------------------------------|----------------------------------|
|<img width="566" height="553" alt="Image" src="https://github.com/user-attachments/assets/0f50084b-319f-480e-8d8a-051c28d4a7e7" />|<img width="567" height="532" alt="Image" src="https://github.com/user-attachments/assets/52d3543f-4c4c-4ff3-a6dd-7d5ce3f19bb2" />|
**Manual End-to-End (E2E) Tests:**
1. Create a project directory containing both valid agent subdirectories and non-agent subdirectories
2. Run `adk web .`
3. Open the web UI and verify only valid agents appear in the agent selector
4. See screenshots below for before/after comparison
### 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
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4648 from markadelnawar:fix/list-agents-filter-non-agents-dirs 041895610fa0c52f2bf3cf7ba0d072a5c580c1b6
PiperOrigin-RevId: 878674609
The `_extract_reasoning_value` function now checks for both 'reasoning_content' and 'reasoning' fields in LiteLLM messages, with 'reasoning_content' taking precedence
Close#3694
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 878668213
Merge https://github.com/google/adk-python/pull/4618
## Summary
Fixes#4564
When using `output_key` with a `temp:` prefix (e.g. `output_key='temp:result'`) in a `SequentialAgent`, the output was silently lost. Agent-2 could never read the temp state written by agent-1.
## Root Cause
Two issues in `append_event`:
1. `_trim_temp_delta_state()` removed temp keys from the event delta **before** `_update_session_state()` could apply them to the in-memory session
2. `_update_session_state()` also explicitly skipped `temp:`-prefixed keys
```python
# Before (broken ordering):
async def append_event(self, session, event):
event = self._trim_temp_delta_state(event) # temp keys gone!
self._update_session_state(session, event) # nothing to apply
```
## Fix
Introduce `_apply_temp_state()` which writes temp-scoped keys to the in-memory `session.state` **before** the event delta is trimmed:
```python
# After:
async def append_event(self, session, event):
self._apply_temp_state(session, event) # temp keys → session.state
event = self._trim_temp_delta_state(event) # temp keys removed from delta
self._update_session_state(session, event) # non-temp keys applied
```
This ensures:
- ✅ Temp state is available to subsequent agents within the same invocation
- ✅ Temp state is still stripped from event deltas (not persisted to storage)
- ✅ All three session services (InMemory, Database, SQLite) behave consistently
## Files Changed
- `src/google/adk/sessions/base_session_service.py`: Added `_apply_temp_state()`, reordered `append_event` logic, removed temp-skip in `_update_session_state`
- `src/google/adk/sessions/database_session_service.py`: Added `_apply_temp_state()` call before trim
- `src/google/adk/sessions/sqlite_session_service.py`: Added `_apply_temp_state()` call before trim
- `tests/unittests/sessions/test_session_service.py`: Updated existing test + added new test for sequential agent scenario
## Testing
All 67 session service tests pass across InMemory, Database, and SQLite backends.
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4618 from stakeswky:fix/temp-state-output-key b9fc737e7a6dc07e06e99af3271a8fc026acae4a
PiperOrigin-RevId: 878499263