Uh oh!
There was an error while loading. Please reload this page.
fix(llm): recover from truncated tool-call arguments instead of failing the stream - #37913
fix(llm): recover from truncated tool-call arguments instead of failing the stream#37913Robin1987China wants to merge 1 commit into
Conversation
…e stream When a provider streams tool arguments with truncated JSON, the current behavior terminates the entire execution. This change catches the parse failure in ToolStream.finish/finishWithInput/finishAll and replaces it with a placeholder tool call and an error tool result. The model receives the error as a recoverable tool failure and can retry, instead of losing the entire stream. Diagnostic metadata (byte count, parse error message) is attached via providerMetadata.malformedInput.
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate PRs FoundRelated PR #37220:
Historical PR #24289:
Related PR #26167:
The most likely duplicate is #37220, as both target truncated tool argument recovery. You should verify whether they're addressing the same issue or complementary parts of the fix. |
Robin1987China
commented
Aug 11, 2026
Closing this PR: the v2 branch has since rewritten |
Robin1987China
commented
Aug 11, 2026
Closing as superseded — see comment above. |
Created by a bot. Do not close or edit manually.
Issue for this PR
Fixes#36766
Note: #37220 (KlyneChrysler) targets dev, this PR targets the correct
v2branch for the 2.0-labeled issue. Both implement recovery at complementary layers — this PR at the LLM protocol/tool-stream layer, #37220 at the session runner layer.Type of change
What does this PR do?
When a provider (e.g., OpenAI native Responses) streams tool arguments with truncated JSON, the current
parseToolInput()behavior produces anLLMErrorthat terminates the entire execution stream. This PR replaces that fatal failure with a recoverable pattern: a placeholdertool-callevent (withinput: {}) followed by an errortool-resultevent. The model receives the error as a recoverable tool failure and can retry, instead of losing the entire execution.This mirrors the existing AI SDK path, which already redirects malformed tool calls to the
experimental_repairToolCall/ "invalid" tool mechanism.Changes
packages/llm/src/protocols/utils/tool-stream.ts:malformedRecovery()helper: produces a placeholdertool-call+ errortool-resultwith diagnostic metadata (providerMetadata.malformedInputcontaining byte count and parse error).catchMalformed()helper: usesEffect.catchIfto interceptLLMErrorwithInvalidProviderOutputreason.finish(),finishWithInput(), andfinishAll()to wraptoolCall()incatchMalformed(), so truncated inputs produce recovery events instead of stream failures.How did you verify your code works?
bun typecheckpasses inpackages/llm(no new errors)Schema.Defectruntime crash in test runner)Checklist