fix(Gemini): update ToolCallRequest and OpenAICompatProvider to handle thought signatures in extra_content

This commit is contained in:
Yohei Nishikubo 2026-03-25 09:40:21 +09:00 committed by Xubin Ren
parent 7b720ce9f7
commit af84b1b8c0
4 changed files with 25 additions and 4 deletions

View File

@ -30,7 +30,21 @@ class ToolCallRequest:
},
}
if self.provider_specific_fields:
tool_call["provider_specific_fields"] = self.provider_specific_fields
# Gemini OpenAI compatibility expects thought signatures in extra_content.google.
if "thought_signature" in self.provider_specific_fields:
tool_call["extra_content"] = {
"google": {
"thought_signature": self.provider_specific_fields["thought_signature"],
}
}
other_fields = {
k: v for k, v in self.provider_specific_fields.items()
if k != "thought_signature"
}
if other_fields:
tool_call["provider_specific_fields"] = other_fields
else:
tool_call["provider_specific_fields"] = self.provider_specific_fields
if self.function_provider_specific_fields:
tool_call["function"]["provider_specific_fields"] = self.function_provider_specific_fields
return tool_call

View File

@ -43,6 +43,13 @@ def _coerce_dict(value: Any) -> dict[str, Any] | None:
def _extract_tool_call_fields(tc: Any) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
"""Extract provider-specific metadata from a tool call object."""
provider_specific_fields = _coerce_dict(_get_attr_or_item(tc, "provider_specific_fields"))
extra_content = _coerce_dict(_get_attr_or_item(tc, "extra_content"))
google_content = _coerce_dict(_get_attr_or_item(extra_content, "google")) if extra_content else None
if google_content:
provider_specific_fields = {
**(provider_specific_fields or {}),
**google_content,
}
function = _get_attr_or_item(tc, "function")
function_provider_specific_fields = _coerce_dict(
_get_attr_or_item(function, "provider_specific_fields")

View File

@ -14,6 +14,6 @@ def test_tool_call_request_serializes_provider_fields() -> None:
message = tool_call.to_openai_tool_call()
assert message["provider_specific_fields"] == {"thought_signature": "signed-token"}
assert message["extra_content"] == {"google": {"thought_signature": "signed-token"}}
assert message["function"]["provider_specific_fields"] == {"inner": "value"}
assert message["function"]["arguments"] == '{"path": "todo.md"}'

View File

@ -40,7 +40,7 @@ def _fake_tool_call_response() -> SimpleNamespace:
id="call_123",
index=0,
function=function,
provider_specific_fields={"thought_signature": "signed-token"},
extra_content={"google": {"thought_signature": "signed-token"}},
)
message = SimpleNamespace(
content=None,
@ -160,7 +160,7 @@ async def test_openai_compat_preserves_provider_specific_fields_on_tool_calls()
assert tool_call.function_provider_specific_fields == {"inner": "value"}
serialized = tool_call.to_openai_tool_call()
assert serialized["provider_specific_fields"] == {"thought_signature": "signed-token"}
assert serialized["extra_content"] == {"google": {"thought_signature": "signed-token"}}
assert serialized["function"]["provider_specific_fields"] == {"inner": "value"}