fix: reverse-map sanitized tokens split across SSE events - #63
Open
shortside wants to merge 1 commit into
Open
Conversation
Per-event transformation assumed SSE events are self-contained, but upstream
splits assistant text and tool arguments at arbitrary offsets: "OCPlatform"
regularly arrives as "OCPlat" + "form" in two content_block_delta events.
Neither half matches a reverse pattern, so sanitized tokens leaked to the
client verbatim, and split tool/property names inside input_json_delta reached
OpenClaw's tool runtime unmapped ("message required", cf. zacdcook#11). Partial
overlaps corrupted text outright: "skillhub" + ".example.com" reverted to
"clawhub.example.com" instead of "clawhub.com".
The reverse pass now accumulates the decoded text_delta / input_json_delta
payload per content block and releases only the bytes that cannot still be
part of a match continuing into the next event (safeSplitPoint), flushing the
remainder at content_block_stop, message_stop and stream end. Hold-back only
triggers when a delta's tail is a prefix of some reverse pattern, so ordinary
prose streams with unchanged event boundaries and latency; thinking and
redacted_thinking blocks still pass through byte-identical.
Verified with a harness that boots the proxy against a mocked upstream: 9
targeted cases (mid-token splits, mid-event TCP splits, ping interleaving,
per-character deltas, truncated stream) fail 6/9 before and pass 9/9 after,
plus a 120-case fuzz asserting split streams produce byte-identical output to
the same payload sent as one delta (5 mismatches before, 0 after).
Co-Authored-By: Claude Opus 5 <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.
Per-event transformation assumed SSE events are self-contained, but upstream splits assistant text and tool arguments at arbitrary offsets: "OCPlatform" regularly arrives as "OCPlat" + "form" in two content_block_delta events. Neither half matches a reverse pattern, so sanitized tokens leaked to the client verbatim, and split tool/property names inside input_json_delta reached OpenClaw's tool runtime unmapped ("message required", cf. #11). Partial overlaps corrupted text outright: "skillhub" + ".example.com" reverted to "clawhub.example.com" instead of "clawhub.com".
The reverse pass now accumulates the decoded text_delta / input_json_delta payload per content block and releases only the bytes that cannot still be part of a match continuing into the next event (safeSplitPoint), flushing the remainder at content_block_stop, message_stop and stream end. Hold-back only triggers when a delta's tail is a prefix of some reverse pattern, so ordinary prose streams with unchanged event boundaries and latency; thinking and redacted_thinking blocks still pass through byte-identical.
Verified with a harness that boots the proxy against a mocked upstream: 9 targeted cases (mid-token splits, mid-event TCP splits, ping interleaving, per-character deltas, truncated stream) fail 6/9 before and pass 9/9 after, plus a 120-case fuzz asserting split streams produce byte-identical output to the same payload sent as one delta (5 mismatches before, 0 after).