diff --git a/cli/src/components/session-ended-banner.tsx b/cli/src/components/session-ended-banner.tsx index daad0ab11b..b99ac28536 100644 --- a/cli/src/components/session-ended-banner.tsx +++ b/cli/src/components/session-ended-banner.tsx @@ -52,6 +52,12 @@ export const SessionEndedBanner: React.FC = ({ const bannerTitle = premiumQuota ? `Session ended · ${formatSessionUnits(premiumQuota.recentCount)} of ${premiumQuota.limit} ${quotaLabel} used today` : 'Session ended' + const landingButtonLabel = + accessTier === 'limited' ? 'Back to start' : 'Change model' + const landingPendingLabel = + accessTier === 'limited' + ? 'Opening start screen…' + : 'Opening model selection…' // While a request is still streaming, restart is disabled: it would // unmount and abort the in-flight agent run. The promise is "we @@ -167,10 +173,11 @@ export const SessionEndedBanner: React.FC = ({ }} > {pendingAction === 'waiting-room' ? ( - 'Opening model selection…' + landingPendingLabel ) : ( <> - Change model{' Esc'} + {landingButtonLabel} + {' Esc'} )} diff --git a/cli/src/hooks/use-freebuff-session.ts b/cli/src/hooks/use-freebuff-session.ts index fd82a03c62..deef67e74e 100644 --- a/cli/src/hooks/use-freebuff-session.ts +++ b/cli/src/hooks/use-freebuff-session.ts @@ -216,6 +216,25 @@ function shouldReleaseSlot(current: FreebuffSessionResponse | null): boolean { ) } +function toLandingSession( + current: FreebuffSessionResponse | null, +): Extract { + const accessTier = + current && 'accessTier' in current ? current.accessTier : undefined + const queueDepthByModel = + current && 'queueDepthByModel' in current + ? current.queueDepthByModel + : undefined + const rateLimitsByModel = getRateLimitsByModel(current) + + return { + status: 'none', + ...(accessTier ? { accessTier } : {}), + ...(queueDepthByModel ? { queueDepthByModel } : {}), + ...(rateLimitsByModel ? { rateLimitsByModel } : {}), + } +} + /** Best-effort DELETE of the caller's session row, gated on actually holding * one. Used both by exit paths and any flow that wants the next POST to * start clean (rejoin, return-to-landing). Always swallows errors — the @@ -588,7 +607,10 @@ export function useFreebuffSession(): UseFreebuffSessionResult { // picker metadata from the response, ignoring whatever status it // claims. Polling resumes when the user commits to a model via // joinFreebuffQueue. - apply({ status: 'none' }) + const landingSession = toLandingSession( + useFreebuffSessionStore.getState().session, + ) + apply(landingSession) const fetchController = abortController callSession('GET', token, { signal: fetchController.signal }) .then((response) => { @@ -602,9 +624,14 @@ export function useFreebuffSession(): UseFreebuffSessionResult { if (response.status === 'none' || response.status === 'queued') { apply({ status: 'none', - accessTier: response.accessTier, - queueDepthByModel: response.queueDepthByModel, - rateLimitsByModel: response.rateLimitsByModel, + accessTier: + response.accessTier ?? landingSession.accessTier, + queueDepthByModel: + response.queueDepthByModel ?? + landingSession.queueDepthByModel, + rateLimitsByModel: + response.rateLimitsByModel ?? + landingSession.rateLimitsByModel, }) } })