fix: prevent Anthropic streams from merging overlapping message generations - #18402
Conversation
Co-authored-by: Lars Grammel <205036+lgrammel@users.noreply.github.com>
Bugfix reviewOutcome: approved Reproduction replayStatus: no-longer-reproduces The exact original reproduction completed successfully and the original bug signal did not appear. Fixes issueStatus: fully-addresses The parser now ignores a same-ID duplicate start, emits InvalidResponseDataError for a different ID while a message is open, and suppresses subsequent events so no second-message finish or tool call is produced. This follows Anthropic's documented message_start-to-message_stop lifecycle. (platform.claude.com) Side effectsRisk: low Valid sequential message sequences remain accepted because lifecycle state resets at message_stop, while only overlapping malformed generations change behavior. Existing multi-message programmatic tool-calling tests pass. PerformanceRisk: low The implementation adds only three scalar state variables and a constant-time check per stream chunk, with no new buffering, collections, or unbounded retention. Backwards compatibilityRisk: low Existing stored histories and persisted formats are unchanged; the new error path prevents an invalid overlapping stream from being finalized into corrupted history. This protects the requirement that thinking blocks be replayed complete and unmodified. (platform.claude.com) Breaking changesRisk: none No public APIs, types, exports, accepted request inputs, configuration, defaults, or persisted formats change. Only malformed overlapping streams and benign duplicate metadata behavior receive the intended corrected error/output semantics. ArchitectureRisk: low The lifecycle validation is localized to the Anthropic stream parser and uses InvalidResponseDataError through the declared @ai-sdk/provider dependency; no package boundary, dependency direction, export, or cross-package src access is introduced. Change scopeStatus: minimal Every changed file supports the fix: localized parser state, two regression fixtures, lifecycle tests, and the required patch changeset. No unrelated production changes or speculative abstractions are present. SecurityRisk: low The change adds no external input execution, credential handling, network behavior, parsing primitive, or new dependency; failing closed on an invalid stream reduces corrupted-history risk. TestingStatus: appropriate Tests cover the reported different-ID splice and same-ID duplicate, asserting error type, metadata IDs, suppression of the second tool call, and absence of finish. Existing sequential programmatic tool-calling coverage also passes in Node and Edge suites. VerificationInspected the complete merge-base diff and all changed files; verified package architecture and exports; package Node and Edge suites each passed all 476 tests, workspace type checking passed, the Anthropic package build passed, and diff validation found no formatting errors. Relevant Documentation |
|
🚀 Published in:
|
Background
Spliced Anthropic streams silently merged separate generations, corrupting signed thinking history and causing subsequent tool-loop requests to fail.
Root Cause
The Anthropic stream transform did not track whether a message was open or its ID; reproduction showed a second message_start overwrote metadata while existing content state remained, merging both generations.
Summary
Added message lifecycle tracking that ignores same-ID duplicate starts, emits InvalidResponseDataError for a different message while one is open, and suppresses remaining invalid stream events.
Testing
Added Node and Edge regression coverage for spliced generations and benign duplicate message_start events, while preserving sequential programmatic tool-calling streams.
End-to-end Validation
pnpm -C packages/anthropic buildfollowed by the reproduction script: emitted one InvalidResponseDataError, no second-message metadata or finish event, and only one metadata event for the same-ID duplicate.Related Issues
Fixes #18331
Closes #18397