Skip to content

feat(billing): consistent out-of-credits UX across CLI, TUI, and desktop - #69655

Merged
OutThisLife merged 4 commits into
mainfrom
bb/out-of-credits-ux
Jul 23, 2026
Merged

feat(billing): consistent out-of-credits UX across CLI, TUI, and desktop#69655
OutThisLife merged 4 commits into
mainfrom
bb/out-of-credits-ux

Conversation

@OutThisLife

@OutThisLife OutThisLife commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

When an inference call fails because the account is out of credits / payment is
required, each surface behaved differently: desktop showed a generic error toast
(and dropped the backend's structured signal), TUI showed a raw error line, and
the CLI only linked billing for OpenRouter. This makes all surfaces render one
shared, provider-aware billing signal.

Scoped to billing failures only — reuses the existing FailoverReason.billing
classification, so provider-unreachable / rate-limit / auth errors are untouched.

How it works

Detection stays in agent/error_classifier.py. New code only maps the failure
to a recovery link and carries it as a structured BillingBlock:

  • agent/billing_links.py — one provider table (slug + base_url host → label,
    billing URL). is_nous routes to the in-app top-up flow; unknown providers
    degrade to a label with no URL.
  • conversation_loop — both billing exit paths return a billing_block; the
    guidance text carries the derived URL for every provider (was OpenRouter-only).
  • gateway — forwards billing_block on message.complete (was dropped).
  • @hermes/sharedBillingBlock type for desktop + TUI.

No surface disables the composer, so /topup, /model, /login keep working.

Per surface

  • Desktop — billing-specific sticky toast + in-composer banner (shared
    StatusRow, no bordered alert). CTA: Nous → Settings → Billing; others → their
    billing page.
  • TUI — opens the shared ConfirmPrompt dialog (not a truncating status notice).
    CTA: Nous → /topup, others → billing page, or /model if no URL.
  • CLI — an "Out of credits" panel below the response with the one action.

Commits

  1. feat(billing) — shared signal (billing_links + gateway + shared type)
  2. feat(desktop) — toast + banner
  3. feat(tui) — confirm dialog
  4. feat(cli) — panel

Tests

  • test_billing_links.py — provider/host/Nous mapping + degrade.
  • billing-block.test.ts (desktop) — CTA routing + scoped clear.
  • billingDialog.test.ts + handler wiring (TUI) — copy + Nous→/topup / others→URL.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

running on dd3bd70

looks good to me!

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) comp/tui Terminal UI (ui-tui/ + tui_gateway/) area/billing Account usage, credit usage, billing (cross-cutting) labels Jul 22, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.
@rob-maron Tagging you on this credits-notice item as the soft maintainer (follow-up to #43669).

Detect a billing wall once (agent/error_classifier → FailoverReason.billing) and
map it to a recovery link + label in one place, then carry that structured
BillingBlock to every surface instead of re-parsing free-form error text per
surface.

- agent/billing_links.py: provider-agnostic slug/host → (label, billing URL)
  table (single source of truth), Nous-aware (is_nous routes to the in-app flow);
  unknown providers degrade to a readable label with no invented URL.
- conversation_loop: both billing exit paths return a billing_block through one
  helper; the guidance message carries the derived URL for every provider.
- gateway forwards billing_block on message.complete (it was dropped).
- @hermes/shared: BillingBlock type shared by desktop + TUI.
On a billing wall, raise a sticky, billing-specific toast (never the generic
error toast) and a persistent in-composer banner for the active session — both
with one recovery action: Nous → in-app Settings → Billing, other providers →
their billing page (deep-linked). The banner reuses the shared StatusRow chrome
(no bordered alert, Codicon glyph, shared buttons), and the composer stays usable
so slash commands keep working.
Open the shared ConfirmPrompt (full-width, themed, same lane as approval/clarify)
rather than a truncating status-bar notice. One recovery action: Nous → /topup
(opens the rich billing overlay), other providers → their billing page, or /model
to switch when there's no URL. The transcript keeps the full guidance; the dialog
is the concise actionable layer.
Pin a provider-agnostic "Out of credits" panel after a billing-classified turn so
the one recovery action (Nous → /topup, other providers → their billing page)
stays visible instead of scrolling away as prose.
@OutThisLife
OutThisLife force-pushed the bb/out-of-credits-ux branch from 30986a9 to dd3bd70 Compare July 22, 2026 23:09
@OutThisLife OutThisLife changed the title feat(billing): shared out-of-credits UX across CLI, TUI, and desktop feat(billing): best-in-class out-of-credits UX across CLI, TUI, and desktop Jul 22, 2026
@OutThisLife OutThisLife changed the title feat(billing): best-in-class out-of-credits UX across CLI, TUI, and desktop feat(billing): consistent out-of-credits UX across CLI, TUI, and desktop Jul 22, 2026
@OutThisLife
OutThisLife merged commit 2c1d585 into main Jul 23, 2026
43 checks passed
@OutThisLife
OutThisLife deleted the bb/out-of-credits-ux branch July 23, 2026 02:03
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
…dits-ux

feat(billing): consistent out-of-credits UX across CLI, TUI, and desktop
33hodl pushed a commit to 33hodl/hermes-agent that referenced this pull request Aug 12, 2026
…dits-ux

feat(billing): consistent out-of-credits UX across CLI, TUI, and desktop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/billing Account usage, credit usage, billing (cross-cutting) comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants