Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions amplifier_module_provider_gemini/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,14 @@ def _convert_to_chat_response(self, response) -> GeminiChatResponse:
fc = part.function_call
tool_call_id = self._generate_tool_call_id()

# Preserve thought_signature if Gemini returned one. The API
# requires it to be re-submitted verbatim in subsequent turns
# (inside the functionCall part of the model-role content);
# omitting it causes INVALID_ARGUMENT on the second tool-using
# turn. Both ToolCallBlock and ToolCall carry
# extra="allow" so the field survives model_dump() round-trips.
thought_signature = getattr(fc, "thought_signature", None)

# Create ToolCallBlock
content_blocks.append(
ToolCallBlock(
Expand All @@ -978,8 +986,16 @@ def _convert_to_chat_response(self, response) -> GeminiChatResponse:
# Create ToolCall for tool_calls list
from amplifier_core.message_models import ToolCall as TCModel

tc_extra: dict[str, Any] = {}
if thought_signature is not None:
tc_extra["thought_signature"] = thought_signature
tool_calls.append(
TCModel(id=tool_call_id, name=fc.name, arguments=dict(fc.args))
TCModel(
id=tool_call_id,
name=fc.name,
arguments=dict(fc.args),
**tc_extra,
)
)
event_blocks.append(
ToolCallContent(
Expand Down Expand Up @@ -1123,14 +1139,17 @@ def _convert_messages(
# Extract name - handle both old format (tool) and new format (name)
tool_name = tc.get("name") or tc.get("tool", "")

parts.append(
{
"function_call": {
"name": tool_name,
"args": tc.get("arguments", {}),
}
}
)
fc_part: dict[str, Any] = {
"name": tool_name,
"args": tc.get("arguments", {}),
}
# Re-attach thought_signature when present so Gemini does
# not reject the request with INVALID_ARGUMENT on the
# second (and subsequent) tool-using turns.
thought_sig = tc.get("thought_signature")
if thought_sig is not None:
fc_part["thought_signature"] = thought_sig
parts.append({"function_call": fc_part})

gemini_contents.append({"role": gemini_role, "parts": parts})

Expand Down
Loading