fix: detect interrupted/error/cancelled status in unstable-agent-task polling loop

The polling loop in executeUnstableAgentTask only checked session status
and message stability, never checking if the background task itself had
been interrupted. This caused the tool call to hang until MAX_POLL_TIME_MS
(10 minutes) when a task was interrupted by prompt errors.

Add manager.getTask() check at each poll iteration to break immediately
on terminal statuses (interrupt, error, cancelled), returning a clear
failure message instead of hanging.
This commit is contained in:
YeonGyu-Kim
2026-02-16 15:56:52 +09:00
parent dd11d5df1b
commit 0ef682965f
3 changed files with 294 additions and 35 deletions
@@ -77,6 +77,7 @@ export async function executeUnstableAgentTask(
const pollStart = Date.now()
let lastMsgCount = 0
let stablePolls = 0
let terminalStatus: { status: string; error?: string } | undefined
while (Date.now() - pollStart < timingCfg.MAX_POLL_TIME_MS) {
if (ctx.abort?.aborted) {
@@ -85,6 +86,12 @@ export async function executeUnstableAgentTask(
await new Promise(resolve => setTimeout(resolve, timingCfg.POLL_INTERVAL_MS))
const currentTask = manager.getTask(task.id)
if (currentTask && (currentTask.status === "interrupt" || currentTask.status === "error" || currentTask.status === "cancelled")) {
terminalStatus = { status: currentTask.status, error: currentTask.error }
break
}
const statusResult = await client.session.status()
const allStatuses = (statusResult.data ?? {}) as Record<string, { type: string }>
const sessionStatus = allStatuses[sessionID]
@@ -110,6 +117,24 @@ export async function executeUnstableAgentTask(
}
}
if (terminalStatus) {
const duration = formatDuration(startTime)
return `SUPERVISED TASK FAILED (${terminalStatus.status})
Task was interrupted/failed while running in monitored background mode.
${terminalStatus.error ? `Error: ${terminalStatus.error}` : ""}
Duration: ${duration}
Agent: ${agentToUse}${args.category ? ` (category: ${args.category})` : ""}
Model: ${actualModel}
The task session may contain partial results.
<task_metadata>
session_id: ${sessionID}
</task_metadata>`
}
const messagesResult = await client.session.messages({ path: { id: sessionID } })
const messages = ((messagesResult as { data?: unknown }).data ?? messagesResult) as SessionMessage[]