Skip to content

feat(tui): show OpenCode Console usage limits - #58731

Merged
adamdotdevin merged 1 commit into
devfrom
tui-usage
Oct 24, 2026
Merged

adamdotdevin merged 1 commit into
devfrom
tui-usage

Conversation

@adamdotdevin

@adamdotdevin adamdotdevin commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Issue for this PR

No issue. Builds the TUI usage designs Aarav shared on Slack (tooey "TUI Q4 2026", Usage page, Zen sections).

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Shows what the workspace's OpenCode Console limits leave for a model, using the usage limits endpoint from #58694.

  • Model picker: the detail row shows "$6 left" for the highlighted model (red when almost out), or "No limit" for a paid Console model with no limit on it. A new "usage" action (ctrl+u) opens /usage. This only appears with the new-designs experiment on, because that's when the picker has a detail row.
  • Composer: after the model and variant, it shows "$6 left" once the model is running low, red "$1.20 left" when almost out, and red "Limit reached" at the limit. "Running low" is relative to the model, per the designs: what's left won't cover three requests that fill its context at its input price. "Almost out" means it won't cover one.
  • Toasts: one when the selected model runs low ("› View usage") and one when it reaches its limit ("› Switch model"). Each shows once per model while OpenCode runs. Limits reload whenever a session's turn ends.
  • Refused turns: a budget refusal ends the turn with a notice instead of "Error: …". It's either "GPT 5.6 Sol usage limit reached" or, for a limit on all spend, "Usage limit reached". Both say when the limit resets and to switch models with the model-list shortcut. A 402 from Console says the workspace is out of credits.
  • Sidebar: a "Limit" section shows what's left for the selected model, and is hidden when no limit applies to it.
  • /usage: lists the models that have limits, with a search box. Only the selected row shows its amount, so money shared between models doesn't look counted twice. Opening a model shows what's left, when it resets, and every limit on it: who spends from it, which models it covers, and a dot on the limit that runs out first.
  • The client data store gets a location.usage resource, the same change the desktop PR (feat(app): show Console budgets and Go usage where they stop you #58714) made on beta.

Not in this PR:

  • The OpenCode Go parts of the designs, which the thread called WIP.
  • The subagent-specific limit rows.
  • The sidebar restyle (muted headings, the "Usage" rename).

How did you verify your code works?

  • I added unit tests for the limit math, the thresholds, the formatting and the reset parsing. I also added an app test that renders the TUI with a limited model and checks each of these: the composer label, the toast, the refused-turn notice, /usage (list and detail), and the picker's detail row and action. I broke the code under test and watched the tests fail.
  • The full TUI suite passes except go-upsell-art, which fails the same way on the base branch. Client tests, typecheck:tsc and bun run check all pass.

Visual

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="72" viewBox="0 0 240 72" fill="none">
  <style>
    .toast { animation: toast 4s ease-in-out infinite; }
    .label { animation: label 4s ease-in-out infinite; }
    @keyframes toast { 0%, 20% { opacity: 0; transform: translateX(8px) } 35%, 85% { opacity: 1; transform: none } 100% { opacity: 0 } }
    @keyframes label { 0%, 15% { opacity: 0 } 30%, 100% { opacity: 1 } }
    @media (prefers-reduced-motion: reduce) { .toast, .label { animation: none } }
  </style>
  <rect x="8.5" y="40.5" width="223" height="23" rx="1.5" stroke="currentColor" stroke-opacity=".25" />
  <rect x="9" y="41" width="2" height="22" fill="currentColor" fill-opacity=".6" />
  <rect x="18" y="49" width="24" height="5" rx="1" fill="currentColor" fill-opacity=".6" />
  <rect x="46" y="49" width="48" height="5" rx="1" fill="currentColor" fill-opacity=".9" />
  <rect x="98" y="49" width="22" height="5" rx="1" fill="currentColor" fill-opacity=".45" />
  <rect class="label" x="128" y="49" width="30" height="5" rx="1" fill="currentColor" fill-opacity=".35" />
  <g class="toast">
    <rect x="140.5" y="6.5" width="91" height="25" rx="1.5" stroke="currentColor" stroke-opacity=".5" />
    <rect x="148" y="12" width="52" height="4" rx="1" fill="currentColor" fill-opacity=".85" />
    <rect x="148" y="21" width="40" height="4" rx="1" fill="currentColor" fill-opacity=".45" />
    <rect x="206" y="12" width="18" height="4" rx="1" fill="currentColor" fill-opacity=".45" />
  </g>
</svg>

Screenshots / recordings

The app test renders these frames (TUI, new designs):

  ┃  Refactor the parser                        ┃  Running low on GPT 5.6 Sol  › View usage  ┃
                                                ┃  $6 left · resets Nov 1                    ┃
    ┃ GPT 5.6 Sol usage limit reached
    ┃ Resets Nov 1. Switch model with ctrl+x m to continue.

     Usage                                            esc
     Workspace: Acme · Resets Nov 1
     Search models
   ┃ Claude Opus 5                                $6 left
     GPT 5.6 Sol

     Usage › Claude Opus 5                            esc
     $6 remaining
     Resets Nov 1
     Limits
     • $44 used of $50
       Only you · GPT 5.6 Sol, Claude Opus 5

  ┃  Build · GPT 5.6 Sol OpenCode  $6 left

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Base automatically changed from console-usage to dev October 24, 2026 16:13
The model picker, the composer and the sidebar say what the workspace's limits leave for the selected model, a toast warns once as it runs low and once at its limit, and a turn a limit refused ends with why and how to keep going. /usage lists the limited models and every limit on each.
@adamdotdevin
adamdotdevin merged commit 5e4aa55 into dev Oct 24, 2026
19 checks passed
@adamdotdevin
adamdotdevin deleted the tui-usage branch October 24, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant