Skip to content

fix(agent): converge vLLM output-cap retries and recover relay 'maximum output tokens' rejections - #90563

Merged
kshitijk4poor merged 4 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/output-cap-cluster
Aug 20, 2026
Merged

fix(agent): converge vLLM output-cap retries and recover relay 'maximum output tokens' rejections#90563
kshitijk4poor merged 4 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/output-cap-cluster

Conversation

@kshitijk4poor

@kshitijk4poor kshitijk4poor commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Output-cap retries now converge on vLLM and recover DeepSeek/relay "exceeds model's maximum output tokens" rejections — including when a relay wraps them as HTTP 429 — instead of crawling 65 tokens per retry or burning generic/rate-limit retries on a deterministic request-shape failure.

Salvages two contributor PRs onto current main with authorship preserved:

Validation

Before After
vLLM binding-constraint retry 65471 → 65406 → 65341 … budget exhausted halves: 65536 → 32768, fits
DeepSeek "exceeds maximum output tokens" 400 unparsed → "failed after 3 retries" clamped to 65536-cap on retry 1
relay-wrapped 429 form classified rate_limit → generic retries / provider failover routed to output-cap clamp; fallback slot unspent, model unchanged
genuine 429s (TPM/quota/retry-after) still route to rate-limit handling (probed 4 shapes, all stay None)

28 targeted output-cap tests green including the 3 pre-existing main regression tests the original #72283 broke, both #72283 scenarios, and a new non-empty-fallback-chain ordering guard. 119 fallback/rate-limit tests green. E2E probes: parser on lowercased/wrapped forms, degenerate vs measured vLLM inputs, false-positive sweep.

Closes #89923. Closes #72283. Fixes #72281. Also removes the input-drift root cause behind #61761 (see that issue's competing-margin PRs #62197/#61846).

Credit

@Dhruv7201 (#89923) and @ekinnee (#72283) — commits cherry-picked with authorship preserved.

Infographic

salvage infographic

Dhruv7201 and others added 3 commits August 20, 2026 11:15
Fixes the retry loop that spins forever when a vLLM server rejects a
request for having a max_tokens too big for what is left of the context
window.

The catch is that vLLM does not tell you how big your prompt actually is
in that situation. It works the number backwards from the constraint it
just failed, so you get:

    "requested 65536 output tokens and your prompt contains at least
     36865 input tokens, for a total of at least 102401 tokens"

That 36865 is just window + 1 - requested, and the total is always
exactly window + 1. Subtracting it from the window hands back
requested - 1 every single time, whatever the real prompt size is.

parse_available_output_tokens_from_error believed it and returned
requested - 1. conversation_loop then takes off its 64 token safety
margin and retries, which walks the cap down 65 tokens at a time while
the reported input walks up by the same 65:

    65536 -> 65471 -> 65406 -> 65341

Three attempts is the default budget, so the session gives up with
"Context length exceeded" having closed 195 tokens of a roughly 28000
token gap. Compression cannot save it either, because the input was
never the problem, which is why the compressor keeps refusing with
"summary would have GROWN".

This is also what is behind the unexplained "input-token drift" in
issue NousResearch#61761. The input is not drifting. It is a derived number, and it
moves because we moved max_tokens.

So when that shape shows up (the "at least" wording, plus a budget that
works out to exactly requested - 1), halve the requested cap instead. It
is still guaranteed to sit under whatever was just rejected, and it
converges on the first retry: 65536 -> 32768, which next to a real 36865
token prompt comes to 69633 against a 102400 window.

Nothing else moves. A measured input is still trusted, and a genuine
input overflow still returns None so the caller falls through to
compression the way it always did.

The existing test asserted the bogus 65535, so it is updated. Added
tests for the measured input path, and for the retry actually
converging.
…errors

Recognizes the DeepSeek/OpenAI-compatible relay wording
  max_tokens (98304) exceeds model's maximum output tokens (65536)
in both parse_available_output_tokens_from_error (returns the cap) and
is_output_cap_error (keeps the 400 out of the compression death-loop).

Salvaged from PR NousResearch#72283; the conversation_loop early-clamp block was
dropped in favor of routing through the existing output-cap handler
(follow-up commit).
…andler

Salvage follow-up for NousResearch#72283: instead of a second pre-retry clamp block
(which bypassed the NousResearch#55546 clamp+compress path and broke its three
regression tests), parse the output cap ONCE at classification time and:
- exempt parseable wrapped output-cap 429s from the eager rate-limit
  provider fallback (a deterministic request-shape failure that failover
  cannot fix but the clamp fixes in one retry), and
- widen is_context_length_error so they reach the SAME NousResearch#55546
  clamp+compress recovery as plain output-cap 400s.

Adds both NousResearch#72283 regression scenarios plus an ordering guard proving a
NON-EMPTY fallback chain does not consume the wrapped 429 (fallback
slot unspent, model unchanged). 119 fallback/rate-limit tests green.
@kshitijk4poor
kshitijk4poor enabled auto-merge (rebase) August 20, 2026 05:58
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/deepseek DeepSeek API labels Aug 20, 2026
@kshitijk4poor
kshitijk4poor merged commit 6702949 into NousResearch:main Aug 20, 2026
50 checks passed
@ekinnee

ekinnee commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists provider/deepseek DeepSeek API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Output-cap 400 from OpenAI-compatible relays is not parsed for retry

4 participants