Skip to content

fix(tui-gateway): restore openrouter provider override on session.resume - #57597

Closed
Ahmett101 wants to merge 1 commit into
NousResearch:mainfrom
Ahmett101:fix/57588-resume-billing-provider-overrides
Closed

fix(tui-gateway): restore openrouter provider override on session.resume#57597
Ahmett101 wants to merge 1 commit into
NousResearch:mainfrom
Ahmett101:fix/57588-resume-billing-provider-overrides

Conversation

@Ahmett101

Copy link
Copy Markdown
Contributor

Summary
_BARE_BILLING_PROVIDERS at tui_gateway/server.py:2011 incorrectly bundled "openrouter" with the real bare buckets "auto" and "custom". OpenRouter is a fully routable provider — it owns the session's API key, base_url, and live model catalog — so dropping its billing provider on session.resume silently redirected the restored model through whatever the user's current config default was (typically a newly-added custom endpoint like Featherless). That endpoint then probed its own /v1/models for the restored Opus model's context length, didn't find Opus, and surfaced as "context window of 2,048 tokens, which is below the minimum 64,000 required by Hermes Agent". Fixes #57588.

Fix: drop "openrouter" from the bare set. The remaining two bare buckets ("auto" global-default sentinel, "custom" unnamed billing class) stay filtered because restoring either as a provider override breaks resume for the documented reason — "auto" defeats session-scoped restore, "custom" is non-routable and surfaces as "No LLM provider configured".

Composition note: this fix is independent of the in-flight #57503 (picker filter) and #50289 (first-class mistral plugin). All three merge cleanly with no overlap; the bare-bucket set in tui_gateway does not interact with the picker or provider plugin registries.

Changes

  • tui_gateway/server.py: drop "openrouter" from _BARE_BILLING_PROVIDERS, expand the docstring to spell out why each of the two remaining bare buckets is bare and why openrouter is not. Single conceptual change: {"auto", "openrouter", "custom"}{"auto", "custom"}.
  • tests/test_tui_gateway_server.py: update test_stored_session_runtime_overrides_skips_bare_billing_provider"openrouter" is now removed from the bare-tuple loop and added as a positive assertion (ov["provider_override"] == "openrouter").
  • tests/tui_gateway/test_custom_provider_session_persistence.py: add two tests under TestBareCustomNoBaseUrlHealsFromConfig:
    • test_restore_preserves_openrouter_billing_provider — pins the bug. row.model=anthropic/claude-opus-4-8, row.billing_provider="openrouter"overrides["provider_override"] == "openrouter" AND overrides["model_override"]["provider"] == "openrouter". Failure mode reproduces the reporter's "context window … below 64,000" error.
    • test_restore_drops_auto_billing_provider — companion negative check that the "auto" sentinel stays filtered (resume falls back to the configured default for bare "auto").

How to Test

# new + updated regression suite
pytest tests/tui_gateway/test_custom_provider_session_persistence.py::TestBareCustomNoBaseUrlHealsFromConfig::test_restore_preserves_openrouter_billing_provider \
       tests/tui_gateway/test_custom_provider_session_persistence.py::TestBareCustomNoBaseUrlHealsFromConfig::test_restore_drops_auto_billing_provider \
       tests/test_tui_gateway_server.py::test_stored_session_runtime_overrides_skips_bare_billing_provider -xvs
# 3/3 passed

# broader suite to confirm no regressions
pytest tests/tui_gateway/test_custom_provider_session_persistence.py \
       tests/tui_gateway/test_billing_rpc.py \
       tests/tui_gateway/test_finalize_session_persist.py \
       tests/test_tui_gateway_server.py -q
# 346/346 passed

Bug-catch verification (the new regression test catches the bug):

git stash push -m bug-check tui_gateway/server.py
pytest tests/tui_gateway/test_custom_provider_session_persistence.py::TestBareCustomNoBaseUrlHealsFromConfig::test_restore_preserves_openrouter_billing_provider -vs
# FAILS: AssertionError — provider_override dropped on resume (the exact symptom #57588 reports)
git stash pop

Checklist

Risk & Impact
Low. Strictly removes a spurious continue-equivalent in a session-restore path: stored OpenRouter rows now come through with their provider override intact instead of being silently dropped. Users who currently hit the bug get a fixed resume immediately; users with working environments see no change. The two real bare-bucket cases (auto, custom) still filter identically to before.

Type: Bug fix
Closes #57588

Related findings (out of scope here, flagged for maintainers):

  • The historical commit (e256f4a per the reporter's analysis) appears to have intended only "custom" but bundled "openrouter" along for what was likely a "route via OpenRouter if any credential resolves to OR" mental model. If a similar bundling exists elsewhere (e.g. a sibling bare-bucket check that mistakenly skips "anthropic", "google", or other routable names), an audit pass driven by the now-shrunk _BARE_BILLING_PROVIDERS semantics would surface it. Strictly out of scope for this PR; happy to file/follow up if asked.
  • A future micro-bench step in the resume path could call resolve_provider_client("openrouter", ...) as an early sanity check rather than deferring to agent_init's 64K-context guard, but that's a hermes_init-level change and depends on design buy-in.

…ume (NousResearch#57588)

_BARE_BILLING_PROVIDERS at tui_gateway/server.py:2011 incorrectly
bundled 'openrouter' with the actual bare buckets 'auto' and 'custom'.
OpenRouter is a fully routable provider — it owns the session's API
key, base_url, and live /v1/models catalog — so dropping its billing
provider on session.resume silently redirected the restored model
through the user's current config default (any newly-added custom
endpoint like Featherless). That endpoint then probed its own
/v1/models for the restored Opus model's context length, didn't find
Opus, and surfaced as 'context window of 2,048 tokens, which is below
the minimum 64,000 required by Hermes Agent'.

Drop 'openrouter' from the bare set. The remaining two bare buckets
('auto' = global-default sentinel, 'custom' = unnamed billing class)
stay filtered because restoring either as a provider override breaks
resume for the documented reason: 'auto' defeats session-scoped
restore, 'custom' is non-routable and surfaces as 'No LLM provider
configured'.

Verified the new test catches the bug by reverting the production
change: test_restore_preserves_openrouter_billing_provider fails with
'provider_override' dropped — the exact symptom the reporter saw.
Unreverted, all 4 new+updated tests pass alongside 346 pre-existing
tui_gateway picker/server tests (no regressions).

Tests:
- tests/test_tui_gateway_server.py::test_stored_session_runtime_overrides_skips_bare_billing_provider
  Updated to drop 'openrouter' from the bare-tuple assertion and add
  a positive check that openrouter IS restored as provider_override.
- tests/tui_gateway/test_custom_provider_session_persistence.py
  Added two tests under TestBareCustomNoBaseUrlHealsFromConfig:
  - test_restore_preserves_openrouter_billing_provider: pins the bug —
    row.model='anthropic/claude-opus-4.8', row.billing_provider='openrouter'
    → overrides['provider_override'] == 'openrouter' and
    overrides['model_override']['provider'] == 'openrouter'.
  - test_restore_drops_auto_billing_provider: companion negative
    check that the 'auto' sentinel stays filtered.
@alt-glitch alt-glitch added type/bug Something isn't working comp/tui Terminal UI (ui-tui/ + tui_gateway/) sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jul 3, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #57593 — both PRs fix #57588 with the byte-identical change (drop "openrouter" from _BARE_BILLING_PROVIDERS in tui_gateway/server.py). #57593 was opened first (07:56Z vs 08:05Z), so it is the canonical version; only the docstring wording differs. Cross-linking so a maintainer can pick one.

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

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Adding new custom provider breaks all previous sessions. Provider changes, but not the model.

2 participants