The token ceiling is ours, and a cut reply says so - #786
Merged
Merged
Conversation
Extraction never sent `max_tokens`, so where a long answer stopped was decided by the endpoint's own default: with reasoning off, a dense passage's answer stopped at exactly 4,096 completion tokens with `finish_reason: length`, and that JSON could not be parsed. Send an explicit 16,384 on the streamed calls — four times the longest answer measured on this path. This endpoint ignores the field with reasoning on, where a call capped at 4,096 returned 45,428 completion tokens and finished normally; it honours it with reasoning off, which is where the truncation was seen. The field costs nothing where it is not read. Carry `finish_reason` out with the answer rather than dropping it once the stream is known to have ended. A reply cut at the ceiling is a valid string and looks complete to the parser, so the drop row could only say the reply did not parse. It now says the reply hit the token ceiling, and the two causes stay apart: an answer that is too long is a number to change, a reply that does not fit the shape is not. Fixes #760 Signed-off-by: basil-k-aji-dev <70605804+basil-k-aji-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
WaylandYang
force-pushed
the
land/token-ceiling
branch
from
September 19, 2026 08:03
38748db to
3691e78
Compare
This was referenced Sep 19, 2026
Merged
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.
basil-k-aji-dev's #776, rebased onto
devafter #764 turned the streaming buffer into bytes, with the number from the review changed. Fixes #760.Their change, unaltered. The streamed calls send an explicit
max_tokensinstead of accepting whatever the endpoint defaults to, andchat_at_streamingreturnsReply { text, finish_reason }so a reply cut at the ceiling can say so.extraction_openuses it: a chunk that hit the ceiling gets a drop row that says it, instead of one that says only that the reply would not parse. An answer that is too long is a number to change; a reply that does not fit the shape is not.Both halves were verified to fail on their own. Removing the field:
and deleting the one line that records the reason fails the same test from the other side.
What changed: 16,384 became 65,536. The original number was four times the longest answer, which is safe on this endpoint because it ignores the field with reasoning on. But the field now rides every streamed call, and
max_tokensis not one thing: Anthropic counts thinking inside it, OpenAI'smax_completion_tokenscounts reasoning tokens. On an endpoint that counts reasoning, a ceiling sized for the answer is a budget for the thinking — which is exactly the lever #759 measured and rejected, where holding this model to about 16,000 reasoning tokens cost 885 statements against 729 and took table figures reaching no statement from 2% to 16%.The largest completion measured on this path is 45,428 tokens. 65,536 sits above it, so the field can only ever guard against the endpoint's own 4,096 default and can never quietly become the cap we turned down. The constant's comment and the design page both say which quantity the number is measured against, because "four times the longest answer" would not lead a reader to expect it to bound the thinking somewhere else.
One test needed adapting to the rebase: #764's Unicode assertion now reads
answer.text.Their branch could not be rebased from here, so this carries their commit with authorship intact and #776 closes with it.
27
utopia-llmtests pass, clippy acrossutopia-llmandutopia-serveris clean, fmt clean.🤖 Generated with Claude Code