fix(compression): OpenRouter fallback survives credit-limited 402s by clamping to the affordable budget (salvage #41055) - #99725
Merged
Conversation
…er 402 _build_call_kwargs strips max_tokens for non-Anthropic providers to avoid wire-format issues (Copilot, ZAI, GPT-5). However, OpenRouter free/limited-credit tiers need max_tokens because the model's full output window exceeds the credit budget, causing HTTP 402. Without max_tokens, the 402 triggers fallback to a text-only model which then fails with 'unknown variant image_url, expected text'. Include max_tokens when provider is 'openrouter' or base_url contains 'openrouter.ai'. Fixes #41035
…stead of failing Second leg of the masoria 20-minute 'Summarizing' stall (Aug 31 2026 bundle): after the Codex timeout, compression fell back to OpenRouter, which defaulted the omitted output cap to the model's full 65,536-token window and rejected with '402 ... can only afford 7117' — on an account whose balance easily covered a summary. Three fallbacks, three 402s, zero summaries. - _create_with_progress: when a 402 names an affordable budget, retry ONCE with that cap (minus 64-token margin, 512-token floor); plain exhaustion 402s and within-budget 402s re-raise unchanged. Single funnel covers primary, fallback, and retry call sites. - extends the #41055 OpenRouter max_tokens preservation onto the current _build_call_kwargs gate (explicit caps survive; None still omitted). Live A/B against a mock OpenRouter enforcing a 7117-token budget with the real SDK + real adapter: main fails with the exact bundle 402; fixed branch retries clamped and returns the summary.
Contributor
૮ >ﻌ< ა ci reviewran on 86aed25 — fix(auxiliary): credit-limited 402s clamp to the affordable
|
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.
Summary
Compression's OpenRouter fallback no longer dies on credit-limited 402s — when the provider says "can only afford N tokens", Hermes retries once with that budget instead of failing the summary. This closes the second leg of the masoria 20-minute "Summarizing thread" stall (Aug 31 2026 bundle): after each Codex timeout, the fallback to OpenRouter defaulted the omitted output cap to the model's full 65,536-token window and 402'd on an account that could afford 7,117 tokens — plenty for a summary. Three fallbacks, three 402s, zero summaries.
Salvages PR #41055 by @liuhao1024 (issue #41035; commit authorship preserved) and applies the affordable-clamp pattern from closed PR #49785 (@Perseus-Computing-LLC, main loop) to the auxiliary path.
Changes
agent/auxiliary_client.py:_create_with_progressis now a credit-aware wrapper: a 402 naming an affordable budget retries ONCE with that cap (minus 64-token margin, 512-token usefulness floor). Plain-exhaustion 402s and 402s on already-within-budget requests re-raise unchanged. One funnel covers the primary, fallback, and credential-retry call sites._build_call_kwargspreserves an explicitmax_tokensfor OpenRouter routes (provider match +openrouter.aibase_url match) — salvaged from fix(auxiliary): preserve max_tokens for OpenRouter to prevent free-tier 402 #41055, reapplied onto the currentauxiliary_max_tokens_paramgate.max_tokens=Nonestill omits the param.test_aux_affordable_402_retry.py(12 tests: extraction, single-retry, no-spin guards, OpenRouter cap preservation) + the contributor'stest_auxiliary_openrouter_max_tokens.py(5 tests, adapted to the max_completion_tokens-aware gate).Validation
_create_with_progress)402 ... requested up to 65536 ... can only afford 7117— summary failstest_auxiliary_client.py+test_aux_progress_streaming.py— 254 passed totalruff checkcleanLive repro: A/B above, identical harness on origin/main vs this branch; main reproduces the exact 402 from the debug bundle.
Infographic