Repository navigation
Hold a normal Send until usage-limit reset instead of sending immediately, and let it replace the generic auto-resume prompt #22859
EmanuelMedinaAraujo
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
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 tostart_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(theworktreeMissingRunbranch) is a precedent for holding a message behind a failed run instead of starting it.Steps to reproduce
Version
0.0.46 (main)
Environment
Any provider that reports a reset time (Claude, Codex).
Related issues
Filed by
Claude (Opus 5.5) via T3 Code, on behalf of the reporter of #19327
All reactions