fix(langgraph): replace partial accumulator when final canonical content arrives#218
Merged
Merged
Conversation
Targets Finding C from the live smoke pass: visible answer renders ~1.83x expected length in chat-streaming-md when the AI message content array has both a reasoning block (with summary items) and a text block. Root cause: accumulateContent's fallback blindly appends when neither side is a strict prefix. Streaming accumulator (~690 chars) plus final canonical text (830 chars) differ by trailing whitespace or normalization, so the prefix check fails and the bug fires. Reference research grounded the approach. Stays with the current model; hardens the fallback with a captured-fixture replay test plus 9 helper unit tests pinning both the genuine delta-append path and the bug-fix path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six-phase plan: branch, capture script (Node ESM using LangGraph SDK directly to dump chunks as JSON fixture), failing replay test, targeted fix in accumulateContent (narrow heuristic for final-canonical reasoning+text array shape), 9 helper unit tests pinning both legitimate delta-append and bug-fix replace paths, verification and PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Targets Finding C from the live smoke pass: visible answer in
<chat-streaming-md>rendered ~1.83× expected length when the AI message content array contained both areasoningblock and atextblock.Root cause
accumulateContentinlibs/langgraph/src/lib/internals/stream-manager.bridge.tsfalls back toexisting + incomingtext concatenation when neither side is a strict prefix. Streaming chunks accumulate the visible answer; the final canonical message arrives with full text but with small formatting differences (whitespace / Unicode normalization), the prefix check fails, and the fallback produces visible duplication.Fix
Narrow heuristic that only triggers on a specific final-canonical shape:
```ts
function isFinalCanonicalReasoningContent(content: unknown): boolean {
// true when content is an array containing BOTH a reasoning/thinking block
// AND a text/output_text block — the shape used for final canonical messages.
}
function accumulateContent(existing, incoming) {
// ...existing prefix-detection logic kept...
if (isFinalCanonicalReasoningContent(incoming)) return incomingText; // NEW
return existingText + incomingText; // legitimate delta-append path preserved
}
```
The legitimate sequential-string-delta path (
existing='hello',incoming='world', neither a prefix) is preserved — only the final-canonical-array shape is intercepted.Verification
mergeMessagesproduces visible text length matching server canonical (within 20 chars).Test plan
Verified locally
Pending visual verification
Spec: `docs/superpowers/specs/2026-05-08-langgraph-streaming-content-dedup-design.md`
Plan: `docs/superpowers/plans/2026-05-08-langgraph-streaming-content-dedup.md`
Note
The captured fixture didn't reproduce the original 1.83× duplication (chunks happened to accumulate byte-for-byte to canonical), so the fix is best-understood as defense-in-depth: the synthetic Phase 4 unit test directly exercises the bug path (
existing='partial answer'+ incoming reasoning+text array → returns canonical, not appended). Once merged, the next live smoke pass against the demo will confirm whether the original visible duplication is gone or whether a different code path needs investigation.