Repository navigation
fix(app): restore free-tier usage limit dialog, timeline line, and prompt recall - #57466
Conversation
3564c3b to
744d516
Compare
bb415a8 to
5661994
Compare
744d516 to
1a5abbf
Compare
5661994 to
db97211
Compare
db97211 to
da88620
Compare
There was a problem hiding this comment.
I couldn't run the new e2e test: Playwright's Chromium won't start in this sandbox, and a real free-limit response needs Zen. So I reviewed the code by reading it. The session-ui timeline test passes, and typecheck is clean for session-ui and app. The prompt recall matches the TUI version from #57467. Paid quota and rate-limit errors still take their existing paths, so the change looks sound.
Public API: unchanged. The only additions are internal UI props (kind/resetAt on the timeline Error row, selection/onDone on useUsageExceededDialogs) and new i18n keys.
Main concern: the new e2e test (inline comment). It adds a typecheck:e2e error. It's also one long scenario that's hard to follow, and its last "no dialog" check passes straight away.
Related: #52894
|
|
||
| test.use({ permissions: ["clipboard-read", "clipboard-write"] }) | ||
|
|
||
| test("the free usage limit opens the Go dialog once, leaves a readable notice, and restores the prompt", async ({ |
There was a problem hiding this comment.
This adds a typecheck:e2e error. default: { build: "opencode/big-pickle" } (line 44) doesn't match MockProviderCatalog's default, which expects { providerID, modelID } (TS2322).
The test is also one ~170-line scenario that checks seven behaviours: the dialog, the timeline line, recall, the Go sign-in model switch, the 24h window, "Don't show again" across a reload, and the attachment-only draft. It uses frozen clocks and a reload along the way, so when it fails it will be hard to tell which part broke.
Also, the final expect(page.getByRole("dialog")).toHaveCount(0) passes as soon as the event is pushed, so it doesn't really show that "Don't show again" suppressed anything.
Could you cut this down to the core case (failure → muted line, dialog with reset time, prompt restored)? The Go-switch and "Don't show again" flows could go in small separate tests, or be dropped.
Stack (merge in order):
feat(core): typed free-limit error with reset time(basedev)fix(app): restore free-tier usage limit dialog, timeline line, and prompt recall(this PR, basedev)feat(tui): show free-limit notice, recall prompt, and skip failure toast(base feat(core): typed free-limit error with reset time #57146)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)▶ Pitch (phone, 69 s):
pr-57146-phone.mp4
Desktop: https://github.com/user-attachments/assets/8ddef02d-df27-4829-a6bb-743c475ad23d
**Size: +445/−46 (10 files)
Closes #50996
Related: #52894
Today
Desktop's existing
DialogUsageExceeded(#27677) still listens for v1'ssession.statuswithreason: "free_tier_limit", which v2 never emits. When a free user hits the daily limit, Desktop shows a red"Rate limit exceeded. Please try again later."error card in the timeline, never opens the"Free limit reached"dialog, and leaves the composer empty.After
useUsageExceededDialogslistens forsession.step.failedwitherror.type === "provider.free-limit"oncepersisted()preferences have hydrated, openingDialogUsageExceededat most once per 24 hours when"Don't show again"isn't set and the composer draft is empty. Includes the local reset time anchored to the failure's timestamp and passes the active composer's modelselectiontoDialogConnectProvidersoSubscribe → Go sign-in → Continueswitches the model in the current session instead of opening a new draft tab."You've used today's free messages. They reset at 5:00 PM."in muted text instead of a red error card.dev)How
packages/session-ui/src/timeline/projection.ts,timeline-row.ts, &session-timeline-row.tsx: projectprovider.free-limitinto an error row withkind: "free-limit"and validatedresetAttimestamp, rendered as muted inline copy.packages/app/src/session/usage-exceeded-dialogs.tsx&packages/app/src/session/screen.tsx: gateDialogUsageExceededongoUpsellReady(), format the reset sentence anchored toevt.created, and thread the composer'sselectionandonDonefocus callback intoDialogConnectProvider.packages/app/src/session/composer/region.tsx&packages/app/src/session/revert.ts: recall the failed assistant turn's delivered user input once when the full composer draft is empty anddata.session.input.ready(sessionID)is true.Proof
packages/session-ui/src/timeline/rows-current.test.ts: verifiesprovider.free-limitprojectskind: "free-limit"andresetAt, omitting out-of-range delays.packages/app/e2e/regression/composer.spec.ts: with a frozen clock, verifiesFree limit reachedopens with the reset time, renders the muted timeline line, restores the prompt, switches the model in the current session afterSubscribe → Go sign-in → Continuewithout opening a new draft tab, respectsDon't show againafter >24h and reload, and preserves an attachment-only draft.Risk
Low. Scoped to
provider.free-limitevents on Desktop; paid quota and rate-limit errors keep their existing error cards and dialogs.Added by the opencode bot (AI-generated).
Related: #52894