Skip to content

ToolCallManager can run the same tool call twice on a repeat TOOL_CALL_START #1187

Description

@AlemTuzlak

TanStack AI version

@tanstack/ai on feat/ag-ui-metadata-compliance (PR #1174)

Framework/Library version

N/A (engine, @tanstack/ai)

Describe the bug and the steps to reproduce it

ToolCallManager.addToolCallStartEvent keys the internal map by index (event.index ?? map.size). AG-UI spec TOOL_CALL_START has no index. First-party adapters still send index on the adapter yield, and they emit START only once (!started after id and name exist).

If a producer sends TOOL_CALL_START twice for the same toolCallId:

  1. Same id, same index: the second START overwrites the slot and resets arguments to ''. Any TOOL_CALL_ARGS already stored are lost.
  2. Same id, missing or different index: the second START inserts a second map row. getToolCalls() returns the id twice, and the engine can run the tool twice.

First-party adapters do not hit this. It is a custom-server / malformed-stream case.

We reverted an in-PR guard (skip a second START with the same id) out of #1174 so that PR stays on the AG-UI metadata work.

A later fix can skip a repeat START for an already-tracked toolCallId, or key the map by id.

Minimal sequence:

manager.addToolCallStartEvent({
  type: "TOOL_CALL_START",
  toolCallId: "call_1",
  toolCallName: "ask_user",
  index: 0,
})
manager.addToolCallArgsEvent({
  type: "TOOL_CALL_ARGS",
  toolCallId: "call_1",
  delta: '{"question":"Which option?"}',
})
manager.addToolCallStartEvent({
  type: "TOOL_CALL_START",
  toolCallId: "call_1",
  toolCallName: "ask_user",
  index: 0,
})
// arguments are now ""

Related: #1174

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

#1174ToolCallManager.addToolCallStartEvent in packages/ai/src/activities/chat/tools/tool-calls.ts. Use the snippet above in packages/ai/tests/tool-call-manager.test.ts.

Do you intend to try to help solve this bug with your own PR?

Maybe, I'll investigate and start debugging

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    has-prAn open PR references this issuewaiting-on: maintainerThe ball is in the maintainers’ court

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions