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
This change introduces compatibility of the remote_a2a_agent with the new a2a_agent_executor.
New Event Converters:
`to_adk_event.py`= Defines a new set of default converters for transforming A2A types (Task, Message, TaskStatusUpdateEvent, TaskArtifactUpdateEvent) into ADK Event objects.
Configurable Remote Agent:
The A2aRemoteAgentConfig object allows users to override the default event converters with custom ones.
New AgentExecutor Compatibility:
RemoteA2aAgent now checks for `agent_executor_v2` metadata in A2A responses.
If detected, it delegates response handling to a new `_handle_a2a_response_impl` method, which utilizes the modular converters defined in the configuration.
PiperOrigin-RevId: 878487448
Previous rollback CL - cl/872951141
This change introduces a new search_catalog tool within the BigQuery toolset, enabling users to search for BigQuery assets across projects using the Dataplex Catalog API.
Key changes include:
- Adding google-cloud-dataplex as a dependency in pyproject.toml.
- Updating BigQuery credentials to include the Dataplex scope.
- Implementing get_dataplex_catalog_client in client.py to create Dataplex API clients.
- Creating search_tool.py with the search_catalog function, which constructs and executes Dataplex search queries.
- Adding extensive unit tests for the new Dataplex client and the search_catalog tool, covering various scenarios including query filtering and error handling.
- Updating the BigQuery toolset to include the new search_catalog tool.
- Updating the BigQuery samples README to mention the new tool.
PiperOrigin-RevId: 878435463
This change introduces new implementation files for the A2aAgentExecutor and event converters. The existing A2aAgentExecutor now acts as a wrapper, allowing a switch between the legacy and new implementations. The new implementation includes support for execution interceptors and a dedicated executor context.
Main Changes=
`a2a_agent_executor_impl.py` = the new implementation of the AgentExecutor differs from the legacy one (`a2a_agent_executor.py`) for the removal of the TaskResultAggregator and the explicit `InvocationContext` creation. Instead, it uses `ExecutorContext` and delegates event conversion to the new logic that supports streaming. It maintains an `agents_artifact` state map to handle partial updates and emits TaskArtifactUpdateEvents for content. The `long_running_functions.py` is used to keep track of the LongRunning FunctionCalls and respective FunctionResponse, to emit them at the end of the generation loop in a `TaskStateUpdateEvent(input-required/auth-required)`.
`from_adk_event.py` = this file replaces the conversion functions in the `event_converter.py` used to convert the adk events into a2a events, estrapolating them in a dedicated file. The main changes in the methods are the introduction of TaskArtifactUpdateEvent to handle content parts, allowing for true artifact streaming and chunking. It utilizes an `agents_artifacts` dictionary to track artifact IDs across partial events to correctly handle append operations.
PiperOrigin-RevId: 878399140
This change introduces an `ensure_part` helper function that normalizes input to `types.Part`. This allows `save_artifact` methods in `FileArtifactService`, `GcsArtifactService`, and `InMemoryArtifactService` to accept dictionaries, including those with camelCase keys as used by Agentspace, and convert them into proper `types.Part` instances before saving
Close#2886
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 878131948
This change enables round-tripping of EventCompaction data by storing it within the event's custom_metadata under the key "_compaction" when appending events. When retrieving events, the "_compaction" data is extracted from custom_metadata and used to populate the EventActions.compaction field. This is a temporary measure until the Vertex AI SDK's SessionEvent model supports a dedicated compaction field.
Close#3465
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 878128265
Only acquire FOR UPDATE locks on app and user state rows when the event's state_delta contains changes for those specific scopes. This avoids unnecessary locking on state rows that are not being modified, improving concurrency.
Close#4655
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 878108562
details:
* Uses GEPA (https://gepa-ai.github.io/gepa/) to optimize the instructions for the root agent. Can be extended to sub-agents and other components in the future.
* GEPA package is imported dynamically; you do not need to install it along with ADK unless you plan to use this optimizer.
Co-authored-by: Keyur Joshi <keyurj@google.com>
PiperOrigin-RevId: 878009649
Refactor ToolResultBlockParam content handling to use json.dumps for dict/list results.
Implement _generate_content_streaming to handle Anthropic's streaming API
Close#3250
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 877613612
- **Fork-safety (#4636):** Adds PID tracking to `BigQueryAgentAnalyticsPlugin` so that forked child processes detect stale gRPC channels and re-initialize instead of deadlocking. Uses the standard `os.getpid()` pattern (same as SQLAlchemy, gRPC-python).
- **Auto-create views (#4639):** After ensuring the `agent_events` table exists, automatically creates 15 per-event-type BigQuery views (`v_llm_request`, `v_tool_completed`, etc.) that unnest JSON columns into typed, queryable columns. Controlled by `BigQueryLoggerConfig.create_views` (default `True`), idempotent via `CREATE OR REPLACE VIEW`.
- **Trace-ID continuity & o11y alignment (#4645):** Fixes trace_id fracture between early events (USER_MESSAGE_RECEIVED, INVOCATION_STARTING) and later events (AGENT_STARTING onwards) when no ambient OTel span exists. Also aligns BQ rows with Cloud Trace span IDs when o11y is active.
- **Span-ID consistency under ambient OTel (#4640 review):** Fixes `*_STARTING` / `*_COMPLETED` events producing mismatched span IDs when an ambient OTel span is active. Completion callbacks now check for ambient spans and defer to `_resolve_ids` Layer 2 instead of overriding with plugin-synthetic IDs.
- **Stack leak safety (#4640 review):** Adds `TraceManager.clear_stack()` and makes `ensure_invocation_span()` clear stale records from *different* invocations, preventing span stack leaks across invocations. Uses `_active_invocation_id_ctx` to distinguish stale leak vs same-invocation re-entry.
- **Root agent name staleness fix:** `init_trace()` now refreshes `_root_agent_name_ctx` unconditionally on each invocation (previously set-once-on-None). `after_run_callback` resets it alongside other invocation cleanup.
- **Exception-safe cleanup:** `after_run_callback` uses `try/finally` to guarantee invocation state (`clear_stack`, `_active_invocation_id_ctx`, `_root_agent_name_ctx`) is always reset, even if `_log_event` raises.
- **`on_tool_error_callback` span fix:** Previously discarded the span_id from `pop_span()`, causing TOOL_ERROR events to get the wrong span. Now captures and uses the popped span_id.
Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 877580395
This change updates the part_converter to ensure that the name field in a2a_types.FileWithUri and a2a_types.FileWithBytes is correctly mapped to the display_name field in genai_types.FileData and genai_types.Blob, respectively, during conversions between A2A and Genai Part types. Tests are updated to verify this propagation in both directions.
PiperOrigin-RevId: 877507283
LiteLlm provides built-in handling for tool and response format compatibility across different providers, allowing output schemas to be used reliably with tools for any LiteLlm instance
Close#3969
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 877471153