-
Notifications
You must be signed in to change notification settings - Fork 2.9k
fix(ai-sdk): emit tool-call events for OpenRouter compatibility #11420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
processAiSdkStreamPart() silently ignored AI SDK tool-call events, relying entirely on tool-input-start/delta/end for tool delivery. @openrouter/ai-sdk-provider v2.1.1 does not emit tool-input-end for incrementally streamed tool calls, and emits only tool-call (no tool-input-* events) for flush-path tool calls. This caused tool calls to be silently dropped, triggering false "no tools used" errors for users proxying through OpenRouter. - Emit tool-call as tool_call chunk instead of ignoring it - String input passthrough to avoid double-encoding when upstream JSON parse fails - Deduplicate in Task.ts tool_call handler: skip already-finalized tools, replace in-flight partial tools, push for flush-only path - 8 new tests covering emission, serialization, and dedup ordering
All previous issues resolved. Test updates in 90a3ee2 correctly align provider specs with the new tool-call emission behavior. No new issues found. LGTM.
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
| const alreadyPresent = this.assistantMessageContent.some( | ||
| (block) => | ||
| block.type === "tool_use" && | ||
| !block.partial && | ||
| (block as any).id === chunk.id, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dedup check only matches block.type === "tool_use", but NativeToolCallParser.finalizeStreamingToolCall() returns McpToolUse (type "mcp_tool_use") for dynamic MCP tools (mcp--serverName--toolName). When such a tool is already finalized via the streaming path, the block has type: "mcp_tool_use" and streamingToolCallIndices has been cleaned up, so both guards miss it. parseToolCall then returns a second McpToolUse which gets pushed as a duplicate. This only triggers when MCP tools are proxied through OpenRouter and both streaming events and tool-call are emitted for the same call.
| const alreadyPresent = this.assistantMessageContent.some( | |
| (block) => | |
| block.type === "tool_use" && | |
| !block.partial && | |
| (block as any).id === chunk.id, | |
| ) | |
| const alreadyPresent = this.assistantMessageContent.some( | |
| (block) => | |
| (block.type === "tool_use" || block.type === "mcp_tool_use") && | |
| !block.partial && | |
| (block as any).id === chunk.id, | |
| ) |
Fix it with Roo Code or mention @roomote and request a fix.
…lush-only tools Address review feedback: - Extend dedup predicate to match mcp_tool_use blocks, preventing duplicate MCP tool entries when both streaming and tool-call events arrive for the same call - Finalize preceding partial text block in flush-only path to prevent stalling tool presentation until stream-end cleanup - Add regression tests for both scenarios
|
Acknowledged — both issues addressed in 381faee:
Regression tests added for both scenarios (17/17 passing in duplicate-tool-use-ids suite, 128/128+4 skipped across ai-sdk and Task suites). |
Four provider test suites (deepseek, mistral, moonshot, openrouter) still asserted that tool-call events are ignored. Update them to assert the new behavior: tool-call emits a tool_call chunk, with deduplication handled by Task.ts.
|
Pushed CI fix 90a3ee2: updated provider test suites (DeepSeek, Mistral, Moonshot, OpenRouter) to expect tool_call chunk emission. Local: 107/107 passing across those suites. |
|
CI green. All review feedback addressed across 3 commits. Broad Unicode/control-char scan clean (no bidi, zero-width, BOM, soft hyphen, or formatting chars). Ready for re-review. |
Closes #11419
Summary
processAiSdkStreamPart()silently ignored AI SDKtool-callevents, relying entirely ontool-input-start/delta/endlifecycle events for tool delivery.@openrouter/ai-sdk-providerv2.1.1 does not emittool-input-endfor incrementally streamed tool calls, and emits onlytool-callwith notool-input-*events for flush-path calls. This caused tool calls to be silently dropped for all OpenRouter-proxied models.tool-callas atool_callchunk with string passthrough (avoids double-encoding when upstream JSON parse fails) and?? {}fallback for undefined input.Task.tstool_callhandler: skips tools already finalized via streaming path, replaces in-flight partial tools, pushes new blocks for flush-only path. All three OpenRouter streaming paths are now handled correctly.Test plan