google / google/adk-python

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

Đang mở
#6,848 4 bình luận 0 reaction 1 người được giao Được @llalitkumarrr nhận Xem trên GitHub
tools
Ngôn ngữ chính
Python
Star
21.5k
Fork
4k
Merge trung bình
1 ngày 14 giờ
Pull request đã merge (30 ngày)
37

Mô tả

## 🔴 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.