diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts
index 7c3eadd8..61fa5898 100644
--- a/src/tools/delegate-task/sync-continuation.ts
+++ b/src/tools/delegate-task/sync-continuation.ts
@@ -50,11 +50,13 @@ export async function executeSyncContinuation(
let resumeAgent: string | undefined
let resumeModel: { providerID: string; modelID: string } | undefined
let resumeVariant: string | undefined
+ let anchorMessageCount: number | undefined
try {
try {
const messagesResp = await client.session.messages({ path: { id: args.session_id! } })
const messages = (messagesResp.data ?? []) as SessionMessage[]
+ anchorMessageCount = messages.length
for (let i = messages.length - 1; i >= 0; i--) {
const info = messages[i].info
if (info?.agent || info?.model || (info?.modelID && info?.providerID)) {
@@ -91,39 +93,34 @@ export async function executeSyncContinuation(
parts: [{ type: "text", text: args.prompt }],
},
})
- } catch (promptError) {
- if (toastManager) {
- toastManager.removeTask(taskId)
- }
- const errorMessage = promptError instanceof Error ? promptError.message : String(promptError)
- return `Failed to send continuation prompt: ${errorMessage}\n\nSession ID: ${args.session_id}`
- }
+ } catch (promptError) {
+ if (toastManager) {
+ toastManager.removeTask(taskId)
+ }
+ const errorMessage = promptError instanceof Error ? promptError.message : String(promptError)
+ return `Failed to send continuation prompt: ${errorMessage}\n\nSession ID: ${args.session_id}`
+ }
- const pollError = await pollSyncSession(ctx, client, {
- sessionID: args.session_id!,
- agentToUse: resumeAgent ?? "continue",
- toastManager,
- taskId,
- })
- if (pollError) {
- return pollError
- }
+ try {
+ const pollError = await pollSyncSession(ctx, client, {
+ sessionID: args.session_id!,
+ agentToUse: resumeAgent ?? "continue",
+ toastManager,
+ taskId,
+ anchorMessageCount,
+ })
+ if (pollError) {
+ return pollError
+ }
- const result = await fetchSyncResult(client, args.session_id!)
- if (!result.ok) {
- if (toastManager) {
- toastManager.removeTask(taskId)
- }
- return result.error
- }
+ const result = await fetchSyncResult(client, args.session_id!, anchorMessageCount)
+ if (!result.ok) {
+ return result.error
+ }
- if (toastManager) {
- toastManager.removeTask(taskId)
- }
+ const duration = formatDuration(startTime)
- const duration = formatDuration(startTime)
-
- return `Task continued and completed in ${duration}.
+ return `Task continued and completed in ${duration}.
---
@@ -132,4 +129,9 @@ ${result.textContent || "(No text output)"}
session_id: ${args.session_id}
`
+ } finally {
+ if (toastManager) {
+ toastManager.removeTask(taskId)
+ }
+ }
}
diff --git a/src/tools/delegate-task/sync-result-fetcher.ts b/src/tools/delegate-task/sync-result-fetcher.ts
index 977f93b7..64d1a278 100644
--- a/src/tools/delegate-task/sync-result-fetcher.ts
+++ b/src/tools/delegate-task/sync-result-fetcher.ts
@@ -3,7 +3,8 @@ import type { SessionMessage } from "./executor-types"
export async function fetchSyncResult(
client: OpencodeClient,
- sessionID: string
+ sessionID: string,
+ anchorMessageCount?: number
): Promise<{ ok: true; textContent: string } | { ok: false; error: string }> {
const messagesResult = await client.session.messages({
path: { id: sessionID },
@@ -15,11 +16,27 @@ export async function fetchSyncResult(
const messages = ((messagesResult as { data?: unknown }).data ?? messagesResult) as SessionMessage[]
- const assistantMessages = messages
+ const messagesAfterAnchor = anchorMessageCount !== undefined ? messages.slice(anchorMessageCount) : messages
+
+ if (anchorMessageCount !== undefined && messagesAfterAnchor.length === 0) {
+ return {
+ ok: false,
+ error: `Session completed but no new response was generated. The model may have failed silently.\n\nSession ID: ${sessionID}`,
+ }
+ }
+
+ const assistantMessages = messagesAfterAnchor
.filter((m) => m.info?.role === "assistant")
.sort((a, b) => (b.info?.time?.created ?? 0) - (a.info?.time?.created ?? 0))
const lastMessage = assistantMessages[0]
+ if (anchorMessageCount !== undefined && !lastMessage) {
+ return {
+ ok: false,
+ error: `Session completed but no new response was generated. The model may have failed silently.\n\nSession ID: ${sessionID}`,
+ }
+ }
+
if (!lastMessage) {
return { ok: false, error: `No assistant response found.\n\nSession ID: ${sessionID}` }
}
diff --git a/src/tools/delegate-task/sync-session-poller.ts b/src/tools/delegate-task/sync-session-poller.ts
index 00f6fd96..458267e4 100644
--- a/src/tools/delegate-task/sync-session-poller.ts
+++ b/src/tools/delegate-task/sync-session-poller.ts
@@ -30,6 +30,7 @@ export async function pollSyncSession(
agentToUse: string
toastManager: { removeTask: (id: string) => void } | null | undefined
taskId: string | undefined
+ anchorMessageCount?: number
}
): Promise {
const syncTiming = getTimingConfig()
@@ -48,7 +49,13 @@ export async function pollSyncSession(
await new Promise(resolve => setTimeout(resolve, syncTiming.POLL_INTERVAL_MS))
pollCount++
- const statusResult = await client.session.status()
+ let statusResult: { data?: Record }
+ try {
+ statusResult = await client.session.status()
+ } catch (error) {
+ log("[task] Poll status fetch failed, retrying", { sessionID: input.sessionID, error: String(error) })
+ continue
+ }
const allStatuses = (statusResult.data ?? {}) as Record
const sessionStatus = allStatuses[input.sessionID]
@@ -65,8 +72,19 @@ export async function pollSyncSession(
continue
}
- const messagesResult = await client.session.messages({ path: { id: input.sessionID } })
- const msgs = ((messagesResult as { data?: unknown }).data ?? messagesResult) as SessionMessage[]
+ let messagesResult: { data?: unknown } | SessionMessage[]
+ try {
+ messagesResult = await client.session.messages({ path: { id: input.sessionID } })
+ } catch (error) {
+ log("[task] Poll messages fetch failed, retrying", { sessionID: input.sessionID, error: String(error) })
+ continue
+ }
+ const rawData = (messagesResult as { data?: unknown })?.data ?? messagesResult
+ const msgs = Array.isArray(rawData) ? (rawData as SessionMessage[]) : []
+
+ if (input.anchorMessageCount !== undefined && msgs.length <= input.anchorMessageCount) {
+ continue
+ }
if (isSessionComplete(msgs)) {
log("[task] Poll complete - terminal finish detected", { sessionID: input.sessionID, pollCount })