Surface Gemini server-side tool-call and tool-response parts - #1107
PratikDhanave (PratikDhanave) wants to merge 1 commit into
Conversation
buildResponsePart never inspected part.ToolCall or part.ToolResponse, so a server-side tool invocation echoed back by the model (its call and result) was silently dropped and the caller never saw it. Map part.ToolCall to an informational-only FunctionCallContent (so the tool loop observes but does not re-execute the server-side call) and part.ToolResponse to a FunctionResultContent, mirroring the Python client. Tool names come from ToolType; missing call ids are synthesized like the existing FunctionCall path.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Address call-ID correlation and ThoughtSignature preservation; strengthen the response-payload assertion.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Surfaces Gemini server-side tool calls and responses as framework function content.
Changes:
- Maps
ToolCallto informational-only function calls. - Maps
ToolResponseto function results. - Adds regression coverage for both mappings.
| File | Summary |
|---|---|
provider/geminiprovider/agent.go |
Converts server-side tool parts into framework content. |
provider/geminiprovider/agent_test.go |
Tests surfaced tool calls and responses. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| callID := part.ToolResponse.ID | ||
| if callID == "" { | ||
| callID = "tool-call-" + uuid.NewString() | ||
| } |
|
Scope: internal-only (bug fix to unexported parsing logic; no exported API surface added or changed) Changed Go contract: None. Upstream evidence reviewed:
The Go change ( Result: Aligned. This closes a genuine parity gap (Go was previously silently dropping these parts while Python already surfaced them) and does not introduce any exported Go API or new user-configurable behavior — the new content is instances of existing public types and is correctly treated as non-executable via the existing
|

Gemini can echo back server-side tool invocations as
toolCall/toolResponseresponse parts (e.g. when a function tool is combined with a native tool).buildResponsePartonly handledThought,Text,FunctionCall,InlineData,FileData,ExecutableCode, andCodeExecutionResult— it never readpart.ToolCallorpart.ToolResponse, so those parts were silently dropped and the caller never observed the model's server-side tool interactions.The Python client (
_parse_parts) maps both:tool_call→ a function call withinformational_only=True,tool_response→ a function result.Change
part.ToolCall→FunctionCallContent{InformationalOnly: true}— surfaced so callers can observe it, but marked informational so the tool-call loop does not try to execute a call the server already ran (toolautocallskipsInformationalOnlycalls).part.ToolResponse→FunctionResultContent.ToolType(fallback"tool_call"); missing call ids are synthesized like the existingFunctionCallpath.Test
TestServerSideToolCallAndResponsePartsSurfaced: a candidate carrying atoolCalland atoolResponsenow surfaces an informational-onlyFunctionCallContentand aFunctionResultContent. Fails before the change (both dropped), passes after.