Pre-generation large-context switch kills opencode run callers: CLI exits with „Error: Aborted", continuation prompt never lands, scheduled tasks silently lost
Environment
- opencode-auto-fallback: v0.4.59 (latest on npm)
- opencode: v1.18.31
- OS: Linux (Debian 13), agent config with
largeContextModel (opencode/big-pickle → opencode/glm-5.2)
- Task scheduler: cron →
opencode run -s <session> "<task>" (fresh CLI process per run)
Summary
The Pre-generation large-context switch (chat.params, context at threshold) aborts the caller's running prompt and then re-sends a continuation prompt fire-and-forget via context.client.session.prompt(...). That works when the caller is a long-lived client (TUI / HTTP to a serve instance). But when the caller is opencode run (one-shot CLI), the abort makes the CLI print Error: Aborted and exit — taking the plugin's not-yet-delivered continuation prompt with it. Result: no model switch, no continuation, session left idle, and the scheduled task is never executed.
Observed failure (4 consecutive days, fully logged)
Daily research job, session context at 88 % (176k/200k, usable 160k):
06:00:03.866 Session status: busy
06:00:05.689 Pre-generation: context at threshold, switching to large model
06:00:06.249 User-initiated abort, ignoring ← misleading: it is the plugin's own abort
06:00:09.315 Switching to large context model ← continuation prompt fired fire-and-forget
# ... nothing. No messages created, session stays idle.
- Job log, 4 days in a row (15.–18.09.2026):
opencode run prints Error: Aborted after ~10 s and exits.
- Session DB shows the task message + an empty (aborted) assistant message — no continuation messages.
- The fire-and-forget
session.prompt() in handleLargeContextSwitch (~L855) silently dies with the process; its .catch() never logs because the process is already gone.
Note: this is not caused by local patches — vanilla v0.4.59 aborts at pre-generation as well („Pre-generation: context at threshold, aborting"), just without any switch attempt. The task-loss failure mode exists upstream either way; with the switch added, the outcome for one-shot callers is the same (abort → caller exits → continuation lost).
Why it works elsewhere
When the prompt is sent from a long-lived client (TUI or HTTP POST /session/:id/message against a serve instance), the abort only kills the prompt — the process survives, the continuation lands (or the idle-path switch takes over), and the task runs to completion on the large model. Verified: same session, manual probe via TUI → switch → task executed + compaction.
Possible directions
- Verify-after-send: after firing the continuation, poll for a few seconds whether the session actually got new activity; if not, log an
ERROR („continuation lost — caller process likely exited, e.g. opencode run"). Today this failure mode is completely silent on the plugin side (only the CLI's own Error: Aborted hints at it).
- Document the limitation:
opencode run (one-shot) + largeContextModel + session over context threshold are incompatible; recommend the HTTP-API/serve route for automated workloads. We switched our cron job to POST /session/:id/message — works reliably.
- Root cause is the hook API, not the plugin: the
chat.params hook can only override sampling params (temperature, topP, reasoningEffort, maxTokens, thinking) — not providerID/modelID. So abort+resend is the only possible way for any plugin to switch models mid-task. If the hook API allowed a model override for the upcoming request, abort-free switching would be possible and this whole failure class disappears. (I'll file a corresponding feature request on the opencode repo.)
- Minor: the log line
User-initiated abort, ignoring is misleading when the abort was triggered by the plugin's own switch logic — a distinct message („plugin-initiated abort for large-context switch") would make post-mortems much easier.
Happy to provide full logs or test a fix.
Pre-generation large-context switch kills
opencode runcallers: CLI exits with „Error: Aborted", continuation prompt never lands, scheduled tasks silently lostEnvironment
largeContextModel(opencode/big-pickle→opencode/glm-5.2)opencode run -s <session> "<task>"(fresh CLI process per run)Summary
The Pre-generation large-context switch (chat.params, context at threshold) aborts the caller's running prompt and then re-sends a continuation prompt fire-and-forget via
context.client.session.prompt(...). That works when the caller is a long-lived client (TUI / HTTP to a serve instance). But when the caller isopencode run(one-shot CLI), the abort makes the CLI printError: Abortedand exit — taking the plugin's not-yet-delivered continuation prompt with it. Result: no model switch, no continuation, session left idle, and the scheduled task is never executed.Observed failure (4 consecutive days, fully logged)
Daily research job, session context at 88 % (176k/200k, usable 160k):
opencode runprintsError: Abortedafter ~10 s and exits.session.prompt()inhandleLargeContextSwitch(~L855) silently dies with the process; its.catch()never logs because the process is already gone.Note: this is not caused by local patches — vanilla v0.4.59 aborts at pre-generation as well („Pre-generation: context at threshold, aborting"), just without any switch attempt. The task-loss failure mode exists upstream either way; with the switch added, the outcome for one-shot callers is the same (abort → caller exits → continuation lost).
Why it works elsewhere
When the prompt is sent from a long-lived client (TUI or HTTP
POST /session/:id/messageagainst a serve instance), the abort only kills the prompt — the process survives, the continuation lands (or the idle-path switch takes over), and the task runs to completion on the large model. Verified: same session, manual probe via TUI → switch → task executed + compaction.Possible directions
ERROR(„continuation lost — caller process likely exited, e.g.opencode run"). Today this failure mode is completely silent on the plugin side (only the CLI's ownError: Abortedhints at it).opencode run(one-shot) +largeContextModel+ session over context threshold are incompatible; recommend the HTTP-API/serve route for automated workloads. We switched our cron job toPOST /session/:id/message— works reliably.chat.paramshook can only override sampling params (temperature,topP,reasoningEffort,maxTokens,thinking) — notproviderID/modelID. So abort+resend is the only possible way for any plugin to switch models mid-task. If the hook API allowed a model override for the upcoming request, abort-free switching would be possible and this whole failure class disappears. (I'll file a corresponding feature request on the opencode repo.)User-initiated abort, ignoringis misleading when the abort was triggered by the plugin's own switch logic — a distinct message („plugin-initiated abort for large-context switch") would make post-mortems much easier.Happy to provide full logs or test a fix.