Repository navigation
Description
What happened
When a thread is stopped on a usage limit and auto-resume is armed ("Resume at reset"), typing a new message and sending it (normal Send, not queue) does not wait for the reset. It goes to the provider immediately, fails on the same limit, and cancels the scheduled resume. After the reset nothing resumes; the message has to be sent again. The scheduled continuation also always uses the generic "Continue where you left off." text, so a message the user typed while limited can never take its place.
This is the remaining open part of #19327. #19583 fixed the queued-run case (a message already saved while a turn runs is held while the thread is usage-limited, including when compaction failed but was recorded as completed). A normal new Send still takes the immediate path.
Desired behavior
While a thread is usage-limited with a known future reset (thread.usageLimitResetAt / limitRecovery), a newly sent message should be held like a held queued run instead of being dispatched immediately, so it does not fail on the same limit and does not cancel the armed recovery. At reset it should be delivered in place of the generic "Continue where you left off." continuation (or run alongside it), so the user's actual message is what resumes the thread.
Diagnosis
In orchestration V2 a usage-limited thread is idle (latest run failed with class usage_limit), so a send resolves to start_immediately:
apps/server/src/orchestration-v2/CommandPolicy.ts(resolveMessageDispatchIntent): with no active run, returns{ type: "start_immediately" }.apps/server/src/orchestration-v2/Orchestrator.ts: a send is held/queued only behind an active run, or behind a failed run whose worktree is missing (worktreeMissingRun). There is no equivalent hold for a usage-limited run, so evenqueue_after_activestarts immediately.docs/user/thread-sidebar.md: "Sending a new message ... prevents a pending continuation from starting", so the send also cancels the armed recovery.
This is inconsistent with how the server already treats the existing queue on the same thread:
Orchestrator.ts(startNextQueuedRun): refuses to start whileusageLimitBlockedRun(...)is non-null, because "Starting the queue would send every waiting message and drop it from the queue as each one fails."
A new message takes the very path that comment warns against. The server already knows the limit and reset time, so the send is predictably doomed and destroys the scheduled recovery as a side effect.
The scheduled continuation text is hard-coded in apps/server/src/orchestration-v2/UsageLimitRecoveryWorker.ts ("Continue where you left off.").
The worktree-missing hold at Orchestrator.ts (the worktreeMissingRun branch) is a precedent for holding a message behind a failed run instead of starting it.
Steps to reproduce
- Settings → General: enable "Auto-resume limited threads" (or use "Resume at reset" on the thread).
- Run a thread on a provider that reports a reset time (Claude or Codex) until it stops on a usage limit. The thread shows Limited and the banner offers "Cancel auto-resume".
- While still limited, type a new message in the composer and send it (normal Send; Mod+Enter queue behavior is already covered by fix(server): a /compact stopped by the Claude usage limit now fails #19583).
- Observe: the message starts a new turn immediately and fails on the same usage limit, and the scheduled auto-resume is cancelled.
- After the reset, nothing resumes; the message has to be sent again manually.
Version
0.0.46 (main)
Environment
Any provider that reports a reset time (Claude, Codex).
Related issues
- Sending a message while a thread is usage-limited fails immediately and cancels the scheduled resume #19327 (parent report; queued-message compaction case fixed in fix(server): a /compact stopped by the Claude usage limit now fails #19583)
- feat(v2): resume limited threads when usage resets #12686 (auto-resume origin)
- feat(server): continue threads after usage limits reset #12831 (closed PR: editable resume prompt)
- discussion [Feature]: Scheduled Prompts #6748 (scheduled prompts)
- [Bug]: Claude usage-limit reset shown in activity but missing auto-resume controls during subagent workflow #15665, [Bug]: inactivity auto-settle cancels a pending usage-limit auto-resume #18928 (missing reset time)
Filed by
Claude (beam-free) via T3 Code, on behalf of the reporter of #19327
Activity