Claude streaming output sometimes truncated at end #3970

Closed
opened 2026-02-16 17:42:08 -05:00 by yindo · 1 comment
Owner

Originally created by @CasualDeveloper on GitHub (Dec 29, 2025).

Originally assigned to: @thdxr on GitHub.

Summary

Intermittently, Claude-based models stream responses that are missing the last few characters/words. The stream ends cleanly (no visible error), but the final text delta never arrives.

This appears isolated to Claude providers; OpenAI / Gemini models do not seem to be affected.

Environment

  • OpenCode: v1.0.207 (release commit 76880dce0)
  • Runtime: Bun 1.3.5
  • Claude via AI SDK: @ai-sdk/anthropic@2.0.50

Reproduction

  1. Configure any Claude model/provider.
  2. Run a prompt with a strict sentinel at the end (repeat ~10 times):
Write 200 lines numbered 001–200.
Then write a final line exactly:
SENTINEL:'`’()[]{}<>✓Ω漢END
Do not output anything after END.

Expected

The final sentinel line always appears intact.

Actual

Occasionally the output ends early (mid-word / missing last characters). Examples include the final line being cut, e.g. SENTINEL:'\’`.

Investigation / suspected root cause

OpenCode consumes streamText().fullStream and appends each text-delta into the message; the TUI batches updates but flushes after stream end. This suggests OpenCode is not dropping the final chunk in its own aggregation/rendering.

OpenCode v1.0.207 pins @ai-sdk/anthropic to 2.0.50. In that version, the provider's doStream() uses ReadableStream.tee() and an un-awaited async IIFE to pull/cancel a "first chunk" branch while returning a delayed stream result. In some runtimes, canceling one tee branch while the other is still being consumed can prematurely end/disturb the underlying source, which can drop tail chunks. That would present exactly as "end-of-response truncation" with no explicit error.

@ai-sdk/anthropic@2.0.56 rewrites the first-chunk pulling logic to be synchronous/awaited and returns the consumer stream directly (no async IIFE / no DelayedPromise), which should remove this race.

Proposed fix (minimal)

Bump deps (staying within v2):

  • @ai-sdk/anthropic: 2.0.502.0.56
  • @ai-sdk/provider-utils: 3.0.183.0.19 (required by 2.0.56)

Patch:

diff --git a/packages/opencode/package.json b/packages/opencode/package.json
@@
-    "@ai-sdk/anthropic": "2.0.50",
+    "@ai-sdk/anthropic": "2.0.56",
@@
-    "@ai-sdk/provider-utils": "3.0.18",
+    "@ai-sdk/provider-utils": "3.0.19",

(and regenerate bun.lock)

I have this change ready on a branch and can open a PR if that’s the preferred workflow.

Originally created by @CasualDeveloper on GitHub (Dec 29, 2025). Originally assigned to: @thdxr on GitHub. ## Summary Intermittently, Claude-based models stream responses that are missing the last few characters/words. The stream ends cleanly (no visible error), but the final text delta never arrives. This appears isolated to Claude providers; OpenAI / Gemini models do not seem to be affected. ## Environment - OpenCode: v1.0.207 (release commit `76880dce0`) - Runtime: Bun 1.3.5 - Claude via AI SDK: `@ai-sdk/anthropic@2.0.50` ## Reproduction 1. Configure any Claude model/provider. 2. Run a prompt with a strict sentinel at the end (repeat ~10 times): ``` Write 200 lines numbered 001–200. Then write a final line exactly: SENTINEL:'`’()[]{}<>✓Ω漢END Do not output anything after END. ``` ### Expected The final sentinel line always appears intact. ### Actual Occasionally the output ends early (mid-word / missing last characters). Examples include the final line being cut, e.g. `SENTINEL:'\`’`. ## Investigation / suspected root cause OpenCode consumes `streamText().fullStream` and appends each `text-delta` into the message; the TUI batches updates but flushes after stream end. This suggests OpenCode is not dropping the final chunk in its own aggregation/rendering. OpenCode v1.0.207 pins `@ai-sdk/anthropic` to `2.0.50`. In that version, the provider's `doStream()` uses `ReadableStream.tee()` and an un-awaited async IIFE to pull/cancel a "first chunk" branch while returning a delayed stream result. In some runtimes, canceling one tee branch while the other is still being consumed can prematurely end/disturb the underlying source, which can drop tail chunks. That would present exactly as "end-of-response truncation" with no explicit error. `@ai-sdk/anthropic@2.0.56` rewrites the first-chunk pulling logic to be synchronous/awaited and returns the consumer stream directly (no async IIFE / no DelayedPromise), which should remove this race. ## Proposed fix (minimal) Bump deps (staying within v2): - `@ai-sdk/anthropic`: `2.0.50` → `2.0.56` - `@ai-sdk/provider-utils`: `3.0.18` → `3.0.19` (required by 2.0.56) Patch: ```diff diff --git a/packages/opencode/package.json b/packages/opencode/package.json @@ - "@ai-sdk/anthropic": "2.0.50", + "@ai-sdk/anthropic": "2.0.56", @@ - "@ai-sdk/provider-utils": "3.0.18", + "@ai-sdk/provider-utils": "3.0.19", ``` (and regenerate `bun.lock`) I have this change ready on a branch and can open a PR if that’s the preferred workflow.
yindo closed this issue 2026-02-16 17:42:08 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Dec 29, 2025):

This issue might be a duplicate of existing issues. Please check:

  • #5838: Sometimes the conversation streaming just cuts off near the end (cosmetically) - Similar symptom of incomplete streaming output
  • #6117: Sometimes AI responses doesn't get rendered towards the end - Related rendering issue at response end
  • #6244: Response terminates prematurely when using Gemini 3 via LiteLLM - Related premature response termination

Your detailed investigation into the @ai-sdk/anthropic version and the ReadableStream.tee() race condition is valuable and provides a concrete fix path that may also address these other reported streaming truncation issues.

Feel free to ignore if your specific case involves different root causes.

@github-actions[bot] commented on GitHub (Dec 29, 2025): This issue might be a duplicate of existing issues. Please check: - #5838: Sometimes the conversation streaming just cuts off near the end (cosmetically) - Similar symptom of incomplete streaming output - #6117: Sometimes AI responses doesn't get rendered towards the end - Related rendering issue at response end - #6244: Response terminates prematurely when using Gemini 3 via LiteLLM - Related premature response termination Your detailed investigation into the @ai-sdk/anthropic version and the ReadableStream.tee() race condition is valuable and provides a concrete fix path that may also address these other reported streaming truncation issues. Feel free to ignore if your specific case involves different root causes.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#3970