Repository navigation
fix: keep long extended-thinking streams intact - #142
Merged
Merged
Conversation
- ClaudeTransformer scanned each SSE event with bufio.Scanner's default
64KB line limit and ignored the error. The signature_delta of long
thinking blocks exceeds that, so the line was silently dropped and
clients received thinking blocks without a signature, which the API
then rejects on every following turn ("each thinking block must
contain thinking").
- The upstream http.Client had a 300s total Timeout that cut off
healthy streams mid-response. Replace it with an idle timeout that
only aborts upstreams sending nothing for 10 minutes.
- Lift the server WriteTimeout (10 min) for the proxy route so long
streams are not truncated on the client side.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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
claudetransformer's per-event scanner to the event itself instead ofbufio.Scanner's default 64 KiB limit, and pass the original event through if scanning ever failsTimeoutwith a 10-minute idle timeout (no headers / no body data), so healthy long streams are never cut off while stalled upstreams are still abortedWriteTimeout(10 min) for the proxy route only, so long streams are not truncated on the client side/v1/modelsfetches bounded by their own 300s timeout, since the shared client no longer has a total timeoutWhy
With long extended thinking (e.g. Opus at high effort), Claude Code sessions behind ccNexus broke permanently:
signature_deltaline grows with thinking length and goes over 64 KiB after roughly 4 minutes of thinking.ClaudeTransformer.TransformResponseWithContextused a defaultbufio.Scannerand ignoredscanner.Err(), so that line was silently dropped (onlyevent: content_block_deltawas forwarded). The client stored a thinking block without a signature, and every following request failed with400 messages.N.content.0.thinking: each thinking block must contain thinking. The session could not continue until the transcript was edited by hand. fix: support multi-megabyte SSE events #141 raised the limit ininternal/proxy, but this scanner ininternal/transformer/ccstill used the default.http.Client.Timeoutcovers reading the response body, so any stream longer than 300s ended withConnection lost mid-response. The serverWriteTimeoutwould cut them off again at 10 minutes.Tests
TestClaudeTransformerForwardsLargeSignatureDelta(fails before the fix: 27 of 102525 bytes forwarded)TestProxiedStreamOutlivesServerWriteTimeout: end-to-end throughhandleProxy, fails before the fix withunexpected EOFgo test ./... -count=1 -race🤖 Generated with Claude Code