Skip to content

fix(translator): preserve tool name in functionResponse when tool_call_id is reused - #66

Open
ZIRAN456 wants to merge 1 commit into
techysy:mainfrom
ZIRAN456:fix/gemini-tool-name-scope
Open

ZIRAN456 wants to merge 1 commit into
techysy:mainfrom
ZIRAN456:fix/gemini-tool-name-scope

Conversation

@ZIRAN456

@ZIRAN456 ZIRAN456 commented Oct 16, 2026 •

Copy link
Copy Markdown

Problem

In multi-turn Agent conversations with extensive tool interactions, random or client-generated tool_call_ids can occasionally collide across turns (or during multi-step execution).

Commit ea333e5 gracefully introduced _dupN deduplication and queued toolResponses to resolve Google's Duplicate function call ID 400 error. However, when resolving the tool name for functionResponse, line 166 still relied on the global lookup:

let name = tcID2Name[rawId];

Because tcID2Name is built by scanning all messages in body.messages beforehand, a later tool call that reuses the same rawId for a different tool will overwrite tcID2Name[rawId].

As a result:

  • Earlier turn's functionCall emits the original tool name (e.g. read_file).
  • Earlier turn's functionResponse emits the overwritten tool name from the subsequent turn (e.g. patch_file).
  • Google Gemini / Antigravity upstream strictly enforces functionCall.name === functionResponse.name and immediately returns:

    HTTP 400 INVALID_ARGUMENT: functionResponse name does not match functionCall name

Solution

  1. Record name: tc.function.name directly in toolCallPairs during the assistant turn ({ rawId, uniqueId, name: tc.function.name }).
  2. When constructing functionResponse, prioritize localName before falling back to tcID2Name[rawId].
  3. Add a unit test to tests/unit/gemini-duplicate-tool-call.test.js covering cross-turn ID reuse with different tool names.

Testing

  • Added test case: preserves correct tool name in functionResponse when identical tool_call_id is reused for different tools.
  • Verified translation output: both functionCall and functionResponse accurately retain their respective per-turn tool names (read_file -> read_file, patch_file -> patch_file).

…l_id is reused

When duplicate tool_call_ids occur across turns (or within a stream),
tcID2Name is a global object populated across all messages where later
occurrences overwrite earlier entries.

While commit ea333e5 introduced _dupN suffixing to prevent Duplicate ID
rejection from Google, functionResponse lookup still referenced the global
tcID2Name[rawId]. If tool_call_ids were reused across different tools,
earlier functionResponses received the later tool's name instead of the
matching functionCall name, triggering Google 400 INVALID_ARGUMENT.

This fix records the tool name directly in toolCallPairs ({ rawId, uniqueId, name })
and uses localName with fallback to tcID2Name, guaranteeing that functionCall
and functionResponse names match within the turn. Added unit regression test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant