Skip to content

feat(tui): show free-limit notice, recall prompt, and skip failure toast - #57467

Merged
kitlangton merged 1 commit into
devfrom
free-limit-tui-notice
Oct 20, 2026
Merged

kitlangton merged 1 commit into
devfrom
free-limit-tui-notice

Conversation

@kitlangton

@kitlangton kitlangton commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Stack (merge in order):

  1. feat(core): typed free-limit error with reset time #57146 — feat(core): typed free-limit error with reset time (base dev)
  2. fix(app): restore free-tier usage limit dialog, timeline line, and prompt recall #57466 — fix(app): restore free-tier usage limit dialog, timeline line, and prompt recall (merged)
  3. feat(tui): show free-limit notice, recall prompt, and skip failure toast #57467 — feat(tui): show free-limit notice, recall prompt, and skip failure toast (this PR, base feat(core): typed free-limit error with reset time #57146)
  4. feat(tui): restore animated Go upsell modal on free usage limit #57471 — feat(tui): restore animated Go upsell modal on free usage limit (base feat(tui): show free-limit notice, recall prompt, and skip failure toast #57467)

Size: +281/−5 (4 files)

Related: #50996, #52894

Today

When the free allowance runs out in the TUI, the transcript shows a red Error: Rate limit exceeded. Please try again later. line, the notifications plugin fires a redundant red "Session failed" toast, and the composer loses the prompt the user just submitted.

After

  • Inline notice: AssistantFooter renders FreeLimitNotice ("You've used today's free messages. They reset at 5:00 PM." and "Upgrade to OpenCode Go → /connect · Switch model → /models") in muted text instead of a red Error: line.
  • No failure toast: the notifications plugin skips the red "Session failed" toast and desktop notification for provider.free-limit.
  • Prompt restore: recalls the delivered user message for the failed step once when the entire composer draft (text, files, agents, skills, pasted content) is empty.
Today (dev) After (#57467)
tui-before tui-after-notice

How

  • packages/tui/src/routes/session/index.tsx: render FreeLimitNotice with freeLimitReset on provider.free-limit assistant messages, and recall the failed step's delivered user message once when the composer is empty.
  • packages/tui/src/feature-plugins/system/notifications.ts: skip the error toast and notification when event.data.error.type === "provider.free-limit" while still marking the session execution as ended.

Proof

  • packages/tui/test/app-lifecycle.test.tsx: verifies FreeLimitNotice renders the reset time and /connect · /models next steps, recalls the delivered user prompt (not a queued one) once, does not re-restore on duplicate events, recalls the next turn's prompt on subsequent hits, and preserves an in-progress typing draft.
  • packages/tui/test/cli/cmd/tui/notifications.test.ts: verifies session.execution.failed with provider.free-limit does not emit a "Session failed" toast or system notification.

Risk

Low. Only affects provider.free-limit failures in the TUI; all other session errors keep their red error line and "Session failed" toast.


Added by the opencode bot (AI-generated).

Related: #52894

@kitlangton
kitlangton force-pushed the free-limit-tui-notice branch from c9c33dd to 086051f Compare October 20, 2026 22:13
@kitlangton
kitlangton marked this pull request as ready for review October 20, 2026 22:51
@kitlangton
kitlangton merged commit 86a0950 into dev Oct 20, 2026
14 checks passed
@kitlangton
kitlangton deleted the free-limit-tui-notice branch October 20, 2026 22:51

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran the TUI from source with the simulated model returning a FreeUsageLimitError. On dev you get the red Error: line, a "Session failed" toast and an empty composer. With this PR you get the muted notice with /connect · /models, no toast, and the composer shows the submitted prompt again. The changed tests and the packages/tui type check pass.

Public API is unchanged; this is TUI rendering and plugin behaviour only.

Two concerns, both inline: free-limit failures now send no notification at all, which leaves background and unfocused sessions silent, and the first new lifecycle test is hard to follow.

Related: #52894

Before

After

errored.add(sessionID)
notify(context, sessionID, event.data.error.message, "error")
context.ui.toast.show({ sessionID, title: "Session failed", message: event.data.error.message, variant: "error" })
if (event.data.error.type !== "provider.free-limit") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This skips the desktop notification and the toast. Because errored is still set, ended() also skips the "Session done" notification. So when the TUI is unfocused, or the free limit hits a session the user isn't viewing (another tab, a subagent), nothing tells them the work stopped. The inline notice and the prompt recall only help once they open that session. Could we drop just the red toast and keep a neutral notification, e.g. notify(..., "Free usage limit reached", "error"), or show the toast only when sessionID isn't the session on screen?

expect(setup.captureCharFrame()).toContain("Open plugins")
})

test("free usage limit lists next steps, recalls the delivered prompt once, and skips the failure toast", async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test runs four scenarios one after another: the first recall, clearing plus a duplicate event, delivering the queued message, then a second failure. It checks each step by counting matches with frame.split(...).length === N, which makes it hard to follow and hard to debug when it fails. Could you cut it down to the core case (notice renders, the delivered prompt is recalled rather than the queued one, no Error:) and maybe one short test for the duplicate event? The Session failed check is already covered in notifications.test.ts.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant