fix: treat response.incomplete as a terminal partial turn - #26
Merged
Merged
Conversation
TheGreatAxios
commented
Sep 28, 2026
TheGreatAxios
left a comment
Contributor
Author
There was a problem hiding this comment.
Review · Comment
A response.incomplete stream event or an incomplete JSON body ends the turn with the partial content already decoded, and reports no usage.
Findings
src/protocol/iterator.ts:481/src/protocol/iterator.ts:746— usage is dropped on the incomplete path. The tokens in that envelope are what the vendor actually bills for the truncated turn (input and the output emitted before the cap), so withholding them undercounts any accounting built oninference.usage. Could we emit usage whenever the envelope carries it, the same wayresponse.completeddoes at line 443, and keep the "partial" concern to the content rather than the counts? If the intent is that truncated usage is untrustworthy for a specific vendor, that reads like a quirk switch rather than a blanket drop.
Notes
- Neither
inference.donenor the turn carries a stop reason, so a consumer cannot tell a truncated turn from a complete one. That is a protocol limit, not something this branch can fix, but worth a line in the comment so the next reader knows the loss is intentional. bun run checkexits 0 (49 unit tests pass);bun test e2epasses 5 with 2 skipped.
The usage in a truncated response is what the backend bills for the partial turn, so both the streaming response.incomplete event and the non-streaming status "incomplete" body now emit it like a completed one instead of withholding it.
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.
Truncated turns are turns, not protocol violations.
Streaming parse no longer throws ProtocolMismatchError on response.incomplete: the envelope is schema-validated, then ignored. Deltas already delivered stay, isStreamTerminal still ends the stream, and no usage is reported. Non-streaming parse decodes an incomplete body's output the same way and withholds its usage. This restores the 0.1.0-era lenient contract that the Codex adapter and downstream hosts depend on (partial text, terminal, no usage); the strict throw from #23 broke backends that truncate routinely on max_output_tokens.
Fixes CL-9472