Repository navigation
Conversation
The stream parser held the unterminated line and the event being built with no limit, so a server streaming an endless line grew panel memory until the tab died. The parser now holds at most 1 Mi UTF-16 code units for the partial line plus the current event's fields. Past that it drops what it holds, cancels the body and throws SseProtocolError. The client reports it as DeweeApiError protocol_error with afterResponse, so the panel reconciles the turn like other faults after the response and never resends it. Closes #2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the cap tripped partway through a chunk, the parser threw and dropped the frames that chunk had already completed, such as chat.started or message.completed, so the panel could not learn the session key or settle a continuation. SseProtocolError now carries the frames completed before the overflow. readSseFrames cancels the body, yields those frames, then throws. The client maps SseProtocolError to protocol_error before it checks the abort signal, so a Stop that lands while the body is cancelled no longer turns the fault into a raw error that could offer "Send again". The joined data size no longer counts one newline too many, and the redundant post-line cap check is gone: a parsed line never holds more than its own length. Refs #2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Addressed the review findings in 34a9f15:
Mutation-checked: removing the frame delivery fails the reader and client tests, and restoring the abort guard before the mapping fails the abort test. Gates: lint, typecheck, test (398 passed) and build all pass. |
When the chunk that overflowed the SSE cap also completed message.completed, the reply finished normally and the protocol_error that followed then added an error bubble and a reconcile to a turn that had already succeeded. use-chat now ignores a stream error once the turn has seen its terminal frame. A continuation that saw message.completed is already acknowledged and out of the queue, and stays so. The client keeps reading after a terminal frame, so frames the server may still send are not cut off. Refs #2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Re-review addressed in 955e8be:
Gates: lint, typecheck, test (400 passed) and build all pass. |
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.
Stacked on #3 (base
claude/dewee-chrome-ext-bootstrap-58115d). Retarget tomainafter #3 merges.Closes #2
Problem
src/protocol/sse-reader.tskept the unterminated line and the event being built with no limit. A misbehaving server could stream an endless line and grow the panel's memory until the tab died.Change
MAX_SSE_PENDING= 1 Mi UTF-16 code units (JavaScript string length). It covers the partial line plus the current event's held fields (event name, data lines with their joining newlines, id). Code units need no re-encoding. The cap is at most 2 MiB of string memory and at least 1 MiB of UTF-8 on the wire, well above the 160 KiB respond body cap.pushscans each chunk for newlines and checks the cap before it appends anything. Past the cap it drops everything it holds, throwsSseProtocolErrorand stays failed. Many small events whose total passes the cap still parse, because each event is released when it ends. The line splitting is unchanged, including CR/LF handling.readSseFramescancels the body onSseProtocolError.streamChatmapsSseProtocolErrortoDeweeApiError(0, 'protocol_error', …, afterResponse: true, cause). Other non-API faults still becomeruntime_request_failed.protocol_errorwas added to the transport codes inuse-chat, and it has en/vi strings.afterResponsealready makesnotReceivedfalse, so the turn follows the documented Chat policy: it is uncertain, markeddelivery_unconfirmedand reconciled, with no "Send again" and no automatic resend. A continuation stays held, as for other drops after the response.docs/architecture.md(Chat) namesprotocol_errorunder decoder faults and states the cap.Tests
pendingstays at or below the cap on every push, the error fires on the push that would pass it, and the held data is dropped afterwards (pendingis 0 and later pushes throw).chat.startedthen an endless data line givesprotocol_errorwithafterResponse: trueand aSseProtocolErrorcause.protocol_errorgivesdelivery_unconfirmed, noretryText, and a singlestreamChatcall.Gates
pnpm lint,pnpm typecheck,pnpm test(387 passed) andpnpm buildpass.pnpm test:e2ewith no.env: 5 smoke tests passed and 16 live tests skipped.🤖 Generated with Claude Code