diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 4c500d5dd..098367fc3 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -14,9 +14,9 @@ export async function executeBackgroundContinuation( parentContext: ParentContext ): Promise { const { manager } = executorCtx + const taskID = getTaskID(args) try { - const taskID = getTaskID(args) if (!taskID) { throw new Error("task_id is required to continue a background task") } @@ -30,6 +30,9 @@ export async function executeBackgroundContinuation( parentAgent: parentContext.agent, parentTools: getSessionTools(parentContext.sessionID), }) + const sessionId = task.sessionID + const backgroundTaskId = task.id + const resolvedModel = resolveMetadataModel(task.model, parentContext.model) const bgContMeta = { title: `Continue: ${task.description}`, @@ -41,38 +44,38 @@ export async function executeBackgroundContinuation( load_skills: args.load_skills, description: args.description, run_in_background: args.run_in_background, - taskId: task.sessionID, - backgroundTaskId: task.id, - sessionId: task.sessionID, + taskId: sessionId, + backgroundTaskId, + sessionId, command: args.command, - model: resolveMetadataModel(task.model, parentContext.model), + model: resolvedModel, }, } await publishToolMetadata(ctx, bgContMeta) return `Background task continued. -Task ID: ${task.id} +Task ID: ${backgroundTaskId} Description: ${task.description} Agent: ${task.agent} Status: ${task.status} Agent continues with full previous context preserved. -System notifies on completion. Use \`background_output\` with task_id="${task.id}" to check. +System notifies on completion. Use \`background_output\` with task_id="${backgroundTaskId}" to check. Do NOT call background_output now. Wait for notification first. ${buildTaskMetadataBlock({ - sessionId: task.sessionID, - taskId: task.sessionID, - backgroundTaskId: task.id, + sessionId, + taskId: sessionId, + backgroundTaskId, agent: task.agent, })}` } catch (error) { return formatDetailedError(error, { operation: "Continue background task", args, - sessionID: getTaskID(args), + sessionID: taskID, }) } } diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 2f767b477..54bfd1351 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -115,9 +115,9 @@ export async function executeBackgroundTask( if (sessionId) { executorCtx.modelFallbackControllerAccessor?.setSessionFallbackChain(sessionId, fallbackChain) - } - if (args.category && sessionId) { - SessionCategoryRegistry.register(sessionId, args.category) + if (args.category) { + SessionCategoryRegistry.register(sessionId, args.category) + } } const resolvedModel = resolveMetadataModel(categoryModel, parentContext.model) @@ -130,17 +130,15 @@ export async function executeBackgroundTask( description: args.description, run_in_background: args.run_in_background, command: args.command, - ...(sessionId ? { taskId: sessionId } : {}), + ...(sessionId ? { taskId: sessionId, sessionId } : {}), backgroundTaskId: task.id, - ...(sessionId ? { sessionId } : {}), ...(resolvedModel ? { model: resolvedModel } : {}), } - const unstableMeta = { + await publishToolMetadata(ctx, { title: args.description, metadata, - } - await publishToolMetadata(ctx, unstableMeta) + }) const taskMetadataBlock = sessionId ? `\n\n${buildTaskMetadataBlock({ diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index a99f6ff39..ce29c7048 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -4,13 +4,12 @@ import { isPlanFamily } from "./constants" import { publishToolMetadata } from "../../features/tool-metadata-store" import { getTaskToastManager } from "../../features/task-toast-manager" import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions" -import { getMessageDir } from "../../shared" +import { getMessageDir, normalizeSDKResponse } from "../../shared" import { promptWithModelSuggestionRetry } from "../../shared/model-suggestion-retry" import { findNearestMessageWithFields } from "../../features/hook-message-injector" import { formatDuration } from "./time-formatter" import { syncContinuationDeps, type SyncContinuationDeps } from "./sync-continuation-deps" import { setSessionTools } from "../../shared/session-tools-store" -import { normalizeSDKResponse } from "../../shared" import { buildTaskPrompt } from "./prompt-builder" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" import { getTaskID } from "./task-id" @@ -41,8 +40,6 @@ export async function executeSyncContinuation( }) } - let syncContMeta: { title: string; metadata: Record } | undefined - let resumeAgent: string | undefined let resumeModel: { providerID: string; modelID: string } | undefined let resumeVariant: string | undefined @@ -56,8 +53,11 @@ export async function executeSyncContinuation( for (let i = messages.length - 1; i >= 0; i--) { const info = messages[i].info if (info?.agent || info?.model || (info?.modelID && info?.providerID)) { + const fallbackResumeModel = info.providerID && info.modelID + ? { providerID: info.providerID, modelID: info.modelID } + : undefined resumeAgent = info.agent - resumeModel = info.model ?? (info.providerID && info.modelID ? { providerID: info.providerID, modelID: info.modelID } : undefined) + resumeModel = info.model ?? fallbackResumeModel resumeVariant = info.variant break } @@ -65,14 +65,15 @@ export async function executeSyncContinuation( } catch { const resumeMessageDir = getMessageDir(continuationID) const resumeMessage = resumeMessageDir ? findNearestMessageWithFields(resumeMessageDir) : null + const resumeMessageModel = resumeMessage?.model resumeAgent = resumeMessage?.agent - resumeModel = resumeMessage?.model?.providerID && resumeMessage?.model?.modelID - ? { providerID: resumeMessage.model.providerID, modelID: resumeMessage.model.modelID } + resumeModel = resumeMessageModel?.providerID && resumeMessageModel.modelID + ? { providerID: resumeMessageModel.providerID, modelID: resumeMessageModel.modelID } : undefined - resumeVariant = resumeMessage?.model?.variant + resumeVariant = resumeMessageModel?.variant } - syncContMeta = { + const syncContMeta = { title: `Continue: ${args.description}`, metadata: { prompt: args.prompt, diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index e1b5e2cba..b1a0d6f38 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -88,13 +88,15 @@ export async function executeSyncTask( if (onSyncSessionCreated) { log("[task] Invoking onSyncSessionCreated callback", { sessionID, parentID: parentContext.sessionID }) - await onSyncSessionCreated({ - sessionID, - parentID: parentContext.sessionID, - title: args.description, - }).catch((err) => { - log("[task] onSyncSessionCreated callback failed", { error: String(err) }) - }) + try { + await onSyncSessionCreated({ + sessionID, + parentID: parentContext.sessionID, + title: args.description, + }) + } catch (error) { + log("[task] onSyncSessionCreated callback failed", { error: String(error) }) + } await new Promise(r => setTimeout(r, 200)) } @@ -134,16 +136,20 @@ export async function executeSyncTask( } await publishToolMetadata(ctx, syncTaskMeta) - let effectiveCategoryModel = categoryModel - let promptError = await deps.sendSyncPrompt(client, { + const syncPromptInput = { sessionID, agentToUse, args, systemContent, - categoryModel: effectiveCategoryModel, toastManager, taskId, sisyphusAgentConfig: executorCtx.sisyphusAgentConfig, + } + + let effectiveCategoryModel = categoryModel + let promptError = await deps.sendSyncPrompt(client, { + ...syncPromptInput, + categoryModel: effectiveCategoryModel, }) if (promptError) { const promptResult = await retrySyncPromptWithFallbacks({ @@ -153,14 +159,8 @@ export async function executeSyncTask( fallbackChain, sendPrompt: async (fallbackModel) => { return deps.sendSyncPrompt(client, { - sessionID, - agentToUse, - args, - systemContent, + ...syncPromptInput, categoryModel: fallbackModel, - toastManager, - taskId, - sisyphusAgentConfig: executorCtx.sisyphusAgentConfig, }) }, }) @@ -198,12 +198,12 @@ export async function executeSyncTask( const parentModelStr = parentContext.model ? `${parentContext.model.providerID}/${parentContext.model.modelID}` : undefined - const modelRoutingNote = - actualModelStr && parentModelStr && actualModelStr !== parentModelStr - ? `\n⚠️ Model routing: parent used ${parentModelStr}, this subagent used ${actualModelStr} (via category: ${args.category ?? "unknown"})` - : actualModelStr - ? `\nModel: ${actualModelStr}${args.category ? ` (category: ${args.category})` : ""}` - : "" + let modelRoutingNote = "" + if (actualModelStr && parentModelStr && actualModelStr !== parentModelStr) { + modelRoutingNote = `\n⚠️ Model routing: parent used ${parentModelStr}, this subagent used ${actualModelStr} (via category: ${args.category ?? "unknown"})` + } else if (actualModelStr) { + modelRoutingNote = `\nModel: ${actualModelStr}${args.category ? ` (category: ${args.category})` : ""}` + } return `Task completed in ${duration}. diff --git a/src/tools/delegate-task/unstable-agent-task.ts b/src/tools/delegate-task/unstable-agent-task.ts index bc4011fbe..f81eb9971 100644 --- a/src/tools/delegate-task/unstable-agent-task.ts +++ b/src/tools/delegate-task/unstable-agent-task.ts @@ -87,6 +87,14 @@ export async function executeUnstableAgentTask( } await publishToolMetadata(ctx, bgTaskMeta) + const taskMetadataBlock = buildTaskMetadataBlock({ + sessionId: sessionID, + taskId: sessionID, + backgroundTaskId: task.id, + agent: agentToUse, + category: args.category, + }) + const startTime = new Date() const timingCfg = getTimingConfig() const pollStart = Date.now() @@ -152,13 +160,7 @@ Model: ${actualModel} The task session may contain partial results. -${buildTaskMetadataBlock({ - sessionId: sessionID, - taskId: sessionID, - backgroundTaskId: task.id, - agent: agentToUse, - category: args.category, - })}` +${taskMetadataBlock}` } if (!completedDuringMonitoring) { @@ -176,13 +178,7 @@ Model: ${actualModel} The task session may still contain partial results. -${buildTaskMetadataBlock({ - sessionId: sessionID, - taskId: sessionID, - backgroundTaskId: task.id, - agent: agentToUse, - category: args.category, - })}` +${taskMetadataBlock}` } const messagesResult = await client.session.messages({ path: { id: sessionID } }) @@ -193,9 +189,8 @@ ${buildTaskMetadataBlock({ const assistantMessages = messages .filter((m) => m.info?.role === "assistant") .sort((a, b) => (b.info?.time?.created ?? 0) - (a.info?.time?.created ?? 0)) - const lastMessage = assistantMessages[0] - if (!lastMessage) { + if (assistantMessages.length === 0) { return `No assistant response found (task ran in background mode).\n\nSession ID: ${sessionID}` } @@ -230,13 +225,7 @@ RESULT: ${textContent || "(No text output)"} -${buildTaskMetadataBlock({ - sessionId: sessionID, - taskId: sessionID, - backgroundTaskId: task.id, - agent: agentToUse, - category: args.category, - })}` +${taskMetadataBlock}` } catch (error) { if (!cleanupReason) { cleanupReason = "exception"