google / google/adk-python

`GoogleSearchAgentTool` parallel responses fail to serialize deferred `GroundingMetadata` (`MockValSer`)

オープン
#6,848 コメント 4 件 リアクション 0 件 担当者 1 名 @llalitkumarrr が担当を希望しています GitHub で見る
tools
主要言語
Python
スター
21.5k
フォーク
4k
平均マージ
1日 14時間
マージ済み PR(30日)
37

説明

## 🔴 Required Information

**Describe the Bug:**

`AgentTool(propagate_grounding_metadata=True)`—which `GoogleSearchAgentTool`
enables—stores a raw `google.genai.types.GroundingMetadata` instance in session
state under `temp:_adk_grounding_metadata`. That value reaches
`EventActions.state_delta`, which is typed as `dict[str, Any]`, so event
serialization relies on Pydantic's duck-typed serialization of the value.

`google-genai` 2.18.0 and newer configure their generated models with
`defer_build=True`. A `GroundingMetadata` produced by nested validation (for
example, as part of `Candidate` validation, as happens for model responses)
leaves `GroundingMetadata.__pydantic_serializer__` as a `MockValSer`.
Serializing the event then raises:

```text
pydantic_core._pydantic_core.PydanticSerializationError: Error calling function `_serialize_state_delta`: TypeError: 'MockValSer' object is not an instance of 'SchemaSerializer'
```

The `_make_json_serializable` fallback introduced by #4748 does not recover
from this case. `pydantic_core.to_jsonable_python(value,
serialize_unknown=True)` raises the same `TypeError` before
`serialize_unknown` can apply, so the exception escapes
`_serialize_state_delta`.

This surfaces in `merge_parallel_function_response_events` in
`google/adk/flows/llm_flows/functions.py`, which calls
`event.actions.model_dump(exclude_none=True, by_alias=True)`. When a search call
runs in parallel with another function call, the merge raises and aborts the
invocation.

This is related to #4748 and prior grounding-metadata persistence reports such
as #5840, but it is a distinct failure mode: the value is a valid Pydantic
model whose deferred serializer has not been built.

**Steps to Reproduce:**

1. Install the affected versions:

```bash
python -m pip install "google-adk==2.7.1" "google-genai==2.19.0" "pydantic==2.13.4"
```

2. Run the snippet under *Minimal Reproduction Code* below. It requires no
model call or API key.
3. Observe the `PydanticSerializationError` above.

**Expected Behavior:**

Serializing an event whose `state_delta` contains grounding metadata propagated
by ADK succeeds, and parallel function-response merging preserves both tool
results. ADK-created state should not depend on whether a deferred class
serializer happened to be built earlier in the process.

**Observed Behavior:**

`EventActions.model_dump(...)` raises from
`merge_parallel_function_response_events`, and the invocation terminates
without a final response.

**Environment Details:**

- ADK Library Version: 2.7.1 (also reproduced on 2.7.0)
- Desktop OS: macOS 26.6 (also reproduced on Linux)
- Python Version: 3.14.6 (also reproduced on 3.12.6)
- `google-genai`: 2.19.0 (also reproduced on 2.18.1)
- `pydantic`: 2.13.4 / `pydantic-core`: 2.46.4

**Model Information:**

- Are you using LiteLLM: No
- Which model is being used: N/A—the minimal reproduction performs no model
call and requires no API key.

---

## 🟡 Optional Information

**Regression:**

This is a `google-genai` 2.18.0 regression:

- `google-genai==2.17.0`: nested `GroundingMetadata` has a built
`SchemaSerializer`; the merge succeeds.
- `google-genai==2.18.0`: the shared model config includes `defer_build=True`;
nested `GroundingMetadata` retains a `MockValSer`; the merge fails.

The failure also reproduces with `google-adk==2.6.0` plus
`google-genai==2.18.1`, so it is not specific to ADK 2.7.x. ADK is affected
because it propagates the raw deferred model through `state_delta` and then
serializes that state while merging parallel tool responses.

**Logs:**

```text
Failed to serialize `state_delta`; some values are not JSON-serializable and
will be replaced with a string representation in the persisted event.

Traceback (most recent call last):
File "google/adk/events/event_actions.py", line 106, in _serialize_state_delta
return cast(dict[str, Any], handler(value))
TypeError: 'MockValSer' object is not an instance of 'SchemaSerializer'

During fallback handling, `to_jsonable_python(...)` raises the same TypeError.
The resulting PydanticSerializationError escapes the parallel-response merge.
```

**Additional Context:**

Two details make this easy to miss in tests:

- Constructing `types.GroundingMetadata(...)` directly builds the serializer as
a side effect. Nested validation via `types.Candidate.model_validate(...)`,
which mirrors the response-validation path, leaves the `MockValSer`.
- Once anything else in the process builds this class serializer, the failure
disappears for subsequent calls.

Possible fixes, in rough order of narrowness:

1. Build `types.GroundingMetadata` before ADK propagates or serializes it, for
example with `types.GroundingMetadata.model_rebuild(force=True)`. Removing
`defer_build` for this model in `google-genai` would also resolve the root
behavior.
2. Store grounding metadata in `state_delta` in serialized form, then
revalidate it where `base_llm_flow` attaches it to the response.
3. Make `_make_json_serializable` resilient per value so the fallback cannot
itself abort event serialization. This is defense in depth and would
degrade the metadata rather than preserve it.

Happy to send a PR for the preferred direction.

**Minimal Reproduction Code:**

```python
from google.adk.events import Event, EventActions
from google.adk.flows.llm_flows.functions import (
merge_parallel_function_response_events,
)
from google.genai import types

candidate = types.Candidate.model_validate(
{"groundingMetadata": {"webSearchQueries": ["some query"]}}
)
print(type(types.GroundingMetadata.__pydantic_serializer__).__name__)
# MockValSer

def response_event(name: str, state_delta: dict) -> Event:
return Event(
invocation_id="inv",
author="my_agent",
content=types.Content(
role="user",
parts=[
types.Part.from_function_response(
name=name,
response={"ok": True},
)
],
),
actions=EventActions(state_delta=state_delta),
)

events = [
response_event(
"search_agent",
{"temp:_adk_grounding_metadata": candidate.grounding_metadata},
),
response_event("other_tool", {"temp:other": 1}),
]

merge_parallel_function_response_events(events)
# PydanticSerializationError
```

The fallback also fails directly:

```python
from pydantic_core import to_jsonable_python

to_jsonable_python(
{"k": candidate.grounding_metadata},
serialize_unknown=True,
)
# TypeError: 'MockValSer' object is not an instance of 'SchemaSerializer'
```

**How often has this issue occurred?:**

- Always (100%) when a deferred `GroundingMetadata` is present in one of two
or more function-response events being merged.

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。