fix(runtime-fallback): abort stuck subagent on quota error with no fallback

When a subagent session (e.g. Momus on GPT) hits a quota/usage-limit
error and the agent's category has no `fallback_models` configured, the
runtime-fallback hook previously returned silently. The OpenCode session
stayed in `retry` status indefinitely while the SDK kept hitting the
limit, the sync-task poller treated `retry` as active work, and the
parent's pending `task` tool call never resolved — leaving a stuck
"waiting for subagent" indicator in the parent conversation.

Narrow fix: at the `fallbackModels.length === 0` exit point, if the
session is a known subagent AND the error classifies as
`quota_exceeded`, abort the subagent session. The existing
`getTerminalSessionError` path in `sync-session-poller.ts` then surfaces
the error via the parent's tool result, which is the persistent surface
the user is already watching.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ivan Smetanin
2026-05-11 14:40:43 +01:00
parent 1c05c60dcc
commit ecb92c1e70
2 changed files with 153 additions and 0 deletions
@@ -8,6 +8,7 @@ import { getFallbackModelsForSession } from "./fallback-models"
import { resolveFallbackBootstrapModel } from "./fallback-bootstrap-model"
import { dispatchFallbackRetry } from "./fallback-retry-dispatcher"
import { hasVisibleAssistantResponse } from "./visible-assistant-response"
import { subagentSessions } from "../../features/claude-code-session-state"
export { hasVisibleAssistantResponse } from "./visible-assistant-response"
@@ -112,6 +113,16 @@ export function createMessageUpdateHandler(deps: HookDeps, helpers: AutoRetryHel
const fallbackModels = getFallbackModelsForSession(sessionID, resolvedAgent, pluginConfig)
if (fallbackModels.length === 0) {
if (
subagentSessions.has(sessionID) &&
classifyErrorType(error) === "quota_exceeded"
) {
log(`[${HOOK_NAME}] Aborting subagent on unrecoverable quota error (no fallback configured)`, {
sessionID,
model,
})
await helpers.abortSessionRequest(sessionID, "message.updated.subagent-quota-no-fallback")
}
return
}