From 291eeed87af68e88f5b5186f109b12b00a9aafd2 Mon Sep 17 00:00:00 2001 From: tw-yshuang Date: Mon, 11 May 2026 02:45:40 +0800 Subject: [PATCH] fix(delegate-task): preserve late background session wiring on abort Keep the new manager-side bootstrap registration as the primary path, but restore a compatibility fallback when the parent call aborts before the child session id resolves. This preserves late delegated session wiring for already-launched background tasks without reverting the new bootstrap architecture. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/tools/delegate-task/background-task.ts | 71 +++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 9c67e7c05..07854b8f6 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -10,6 +10,65 @@ import { QUESTION_DENIED_SESSION_PERMISSION } from "../../shared/question-denied import { stripAgentListSortPrefix } from "../../shared/agent-display-names" import { buildTaskMetadataBlock } from "../../features/tool-metadata-store/task-metadata-contract" import { resolveMetadataModel } from "./resolve-metadata-model" +import { registerDelegatedChildSessionBootstrap } from "../../shared/delegated-child-session-bootstrap" + +function registerBackgroundSessionContext(args: { + sessionId: string + promptText: string + fallbackChain?: FallbackEntry[] + category?: string + modelFallbackControllerAccessor?: ExecutorContext["modelFallbackControllerAccessor"] +}): void { + registerDelegatedChildSessionBootstrap({ + sessionID: args.sessionId, + promptText: args.promptText, + fallbackChain: args.fallbackChain, + category: args.category, + modelFallbackControllerAccessor: args.modelFallbackControllerAccessor, + }) +} + +function continueSessionSetup(args: { + taskID: string + promptText: string + manager: ExecutorContext["manager"] + timing: ReturnType + fallbackChain?: FallbackEntry[] + category?: string + modelFallbackControllerAccessor?: ExecutorContext["modelFallbackControllerAccessor"] +}): void { + if (!args.fallbackChain && !args.category) { + return + } + + void (async () => { + const waitStart = Date.now() + while (Date.now() - waitStart < args.timing.WAIT_FOR_SESSION_TIMEOUT_MS) { + await new Promise(resolve => setTimeout(resolve, args.timing.WAIT_FOR_SESSION_INTERVAL_MS)) + const updated = args.manager.getTask(args.taskID) + if (!updated) { + return + } + if (updated.status === "error" || updated.status === "cancelled" || updated.status === "interrupt") { + return + } + + const sessionId = updated.sessionId + if (!sessionId) { + continue + } + + registerBackgroundSessionContext({ + sessionId, + promptText: args.promptText, + fallbackChain: args.fallbackChain, + category: args.category, + modelFallbackControllerAccessor: args.modelFallbackControllerAccessor, + }) + return + } + })() +} async function waitForBackgroundSessionStart(args: { taskId: string @@ -88,7 +147,17 @@ export async function executeBackgroundTask( manager, timing, abortSignal: ctx.abort, - onAbort: () => {}, + onAbort: () => { + continueSessionSetup({ + taskID: task.id, + promptText: effectivePrompt, + manager, + timing, + fallbackChain, + category: args.category, + modelFallbackControllerAccessor: executorCtx.modelFallbackControllerAccessor, + }) + }, }) const updatedTask = typeof manager.getTask === "function"