Skip to content

streamProxy drops ToolCall.thoughtSignature — Gemini multi-turn tool calls 400 through a proxy #6414

Description

@anilgulecha

What happened?

Running an Agent with `streamFn: streamProxy` against a proxy server that uses `streamSimple` on the backend: any Gemini run that makes a tool call fails on the second turn with:

400 INVALID_ARGUMENT: Function call is missing a thought_signature in functionCall parts.
This is required for tools to work correctly ... function call `default_api:write`, position 2.

Root cause: the proxy wire protocol (`ProxyAssistantMessageEvent`) sends `toolcall_end` as `{ type, contentIndex }` only, and `processProxyEvent` reconstructs the toolCall from argument deltas — so `ToolCall.thoughtSignature` (google-specific, populated by the google provider) never reaches the client. When the agent replays the conversation on the next turn, the functionCall part has no signature and Gemini rejects the request. Direct `streamSimple` is fine; only the proxy path loses it.

(`text_end`/`thinking_end` already have `contentSignature?` in the protocol for exactly this class of problem — toolcall_end is the gap.)

Steps to reproduce

  1. Agent + `streamProxy` → any proxy server forwarding to `streamSimple` with a Gemini model (e.g. `gemini-flash-lite-latest`) and one tool.
  2. Prompt something that triggers a tool call.
  3. Turn 2 (tool result replay) → 400 above.

Expected behavior

Tool calls round-trip the proxy losslessly, signatures included.

Proposed fix (happy to PR)

Backwards-compatible protocol extension, mirroring the existing `contentSignature` pattern:

  • `ProxyAssistantMessageEvent`: `{ type: "toolcall_end"; contentIndex: number; toolCall?: ToolCall }`
  • `processProxyEvent` `toolcall_end`: if `proxyEvent.toolCall` present, use it wholesale (`partial.content[i] = { ...proxyEvent.toolCall }`); else keep today's delta-reconstruction fallback.
  • Servers can then forward the complete `toolCall` from pi-ai's native `toolcall_end` event.

We run this patched in production (jimmy, an agent-in-the-cloud built on pi) and it fixes Gemini tool-calling through our proxy; also fixed our server to populate `contentSignature` on text/thinking_end, which the client already applies.

Version

0.73.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions