{"version":3,"file":"chain-root-attachment.d.ts","sourceRoot":"","sources":["../../../../src/runs/background/chain-root-attachment.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAe,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGtG,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AA0MD,wBAAsB,wBAAwB,CAC7C,IAAI,EAAE,iBAAiB,EACvB,OAAO,GAAE;IACR,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACnB,GACJ,OAAO,CAAC,uBAAuB,CAAC,CAwBlC;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpF","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { AcceptanceLedger, AsyncStatus, CostSummary, ModelAttempt } from \"../../shared/types.ts\";\nimport { readStatus } from \"../../shared/utils.ts\";\n\nexport interface ImportedAsyncRoot {\n\trunId: string;\n\tasyncDir: string;\n\tresultPath: string;\n\tindex: number;\n}\n\nexport interface ImportedAsyncRootResult {\n\tagent: string;\n\toutput: string;\n\tsuccess: boolean;\n\texitCode: number;\n\terror?: string;\n\tsessionFile?: string;\n\tintercomTarget?: string;\n\tmodel?: string;\n\tattemptedModels?: string[];\n\tmodelAttempts?: ModelAttempt[];\n\ttotalCost?: CostSummary;\n\tstructuredOutput?: unknown;\n\tstructuredOutputPath?: string;\n\tstructuredOutputSchemaPath?: string;\n\tacceptance?: AcceptanceLedger;\n\ttimedOut?: boolean;\n\tstopped?: boolean;\n}\n\ninterface AsyncResultFile {\n\tstate?: string;\n\tsuccess?: boolean;\n\tsummary?: string;\n\terror?: string;\n\ttimedOut?: boolean;\n\tstopped?: boolean;\n\tresults?: Array<{\n\t\tagent?: string;\n\t\toutput?: string;\n\t\terror?: string;\n\t\tsuccess?: boolean;\n\t\ttimedOut?: boolean;\n\t\tstopped?: boolean;\n\t\tsessionFile?: string;\n\t\tintercomTarget?: string;\n\t\tmodel?: string;\n\t\tattemptedModels?: string[];\n\t\tmodelAttempts?: ModelAttempt[];\n\t\ttotalCost?: CostSummary;\n\t\tstructuredOutput?: unknown;\n\t\tstructuredOutputPath?: string;\n\t\tstructuredOutputSchemaPath?: string;\n\t\tacceptance?: AcceptanceLedger;\n\t}>;\n}\n\nconst TERMINAL_STATES = new Set([\"complete\", \"failed\", \"paused\", \"stopped\"]);\nconst TERMINAL_STEP_STATUSES = new Set([\"complete\", \"completed\", \"failed\", \"paused\", \"stopped\"]);\n\nfunction readResultFile(resultPath: string): AsyncResultFile | undefined {\n\ttry {\n\t\treturn JSON.parse(fs.readFileSync(resultPath, \"utf-8\")) as AsyncResultFile;\n\t} catch (error) {\n\t\tif (\n\t\t\ttypeof error === \"object\" &&\n\t\t\terror !== null &&\n\t\t\t\"code\" in error &&\n\t\t\t(error as NodeJS.ErrnoException).code === \"ENOENT\"\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction selectedStatusStep(\n\tstatus: AsyncStatus | null,\n\tindex: number,\n): NonNullable<AsyncStatus[\"steps\"]>[number] | undefined {\n\treturn status?.steps?.[index];\n}\n\nfunction isTerminalStatus(status: AsyncStatus | null, index: number): boolean {\n\tif (!status) return false;\n\tconst step = selectedStatusStep(status, index);\n\tif (step && TERMINAL_STEP_STATUSES.has(step.status)) return true;\n\treturn TERMINAL_STATES.has(status.state);\n}\n\nfunction resultState(\n\tresult: AsyncResultFile | undefined,\n\tchild: NonNullable<AsyncResultFile[\"results\"]>[number] | undefined,\n): \"complete\" | \"failed\" | \"paused\" | \"stopped\" | undefined {\n\tif (!result) return undefined;\n\tif (child?.stopped === true) return \"stopped\";\n\tif (child?.success === true) return \"complete\";\n\tif (child?.success === false)\n\t\treturn result.state === \"stopped\" ? \"stopped\" : result.state === \"paused\" ? \"paused\" : \"failed\";\n\tif (\n\t\tresult.state === \"complete\" ||\n\t\tresult.state === \"failed\" ||\n\t\tresult.state === \"paused\" ||\n\t\tresult.state === \"stopped\"\n\t)\n\t\treturn result.state;\n\tif (result.success === true) return \"complete\";\n\tif (result.success === false) return \"failed\";\n\treturn undefined;\n}\n\nfunction outputFromTerminalStatus(\n\troot: ImportedAsyncRoot,\n\tstatus: AsyncStatus,\n\tstep: NonNullable<AsyncStatus[\"steps\"]>[number] | undefined,\n): ImportedAsyncRootResult {\n\tconst agent = step?.agent ?? status.steps?.[root.index]?.agent ?? \"subagent\";\n\tconst timedOut = step?.timedOut === true || status.timedOut === true;\n\tconst stopped = step?.stopped === true || status.stopped === true || status.state === \"stopped\";\n\tconst message =\n\t\tstep?.error ??\n\t\tstatus.error ??\n\t\t(stopped\n\t\t\t? \"Subagent stopped by user.\"\n\t\t\t: `Attached async root ${root.runId} ended without a result file at ${root.resultPath}.`);\n\treturn {\n\t\tagent,\n\t\toutput: message,\n\t\tsuccess: false,\n\t\texitCode: 1,\n\t\terror: message,\n\t\t...(timedOut ? { timedOut: true } : {}),\n\t\t...(stopped ? { stopped: true } : {}),\n\t\t...((step?.sessionFile ?? status.sessionFile) ? { sessionFile: step?.sessionFile ?? status.sessionFile } : {}),\n\t\t...(step?.model ? { model: step.model } : {}),\n\t\t...(step?.attemptedModels ? { attemptedModels: step.attemptedModels } : {}),\n\t\t...(step?.modelAttempts ? { modelAttempts: step.modelAttempts } : {}),\n\t\t...(step?.totalCost ? { totalCost: step.totalCost } : {}),\n\t\t...(step?.structuredOutput !== undefined ? { structuredOutput: step.structuredOutput } : {}),\n\t\t...(step?.structuredOutputPath ? { structuredOutputPath: step.structuredOutputPath } : {}),\n\t\t...(step?.structuredOutputSchemaPath ? { structuredOutputSchemaPath: step.structuredOutputSchemaPath } : {}),\n\t\t...(step?.acceptance ? { acceptance: step.acceptance } : {}),\n\t};\n}\n\nfunction outputFromTimeout(\n\troot: ImportedAsyncRoot,\n\tstatus: AsyncStatus | null,\n\tmessage: string,\n): ImportedAsyncRootResult {\n\tconst step = selectedStatusStep(status, root.index);\n\treturn {\n\t\tagent: step?.agent ?? status?.steps?.[root.index]?.agent ?? \"subagent\",\n\t\toutput: message,\n\t\tsuccess: false,\n\t\texitCode: 1,\n\t\terror: message,\n\t\ttimedOut: true,\n\t\t...((step?.sessionFile ?? status?.sessionFile) ? { sessionFile: step?.sessionFile ?? status?.sessionFile } : {}),\n\t\t...(step?.model ? { model: step.model } : {}),\n\t\t...(step?.attemptedModels ? { attemptedModels: step.attemptedModels } : {}),\n\t\t...(step?.modelAttempts ? { modelAttempts: step.modelAttempts } : {}),\n\t\t...(step?.totalCost ? { totalCost: step.totalCost } : {}),\n\t};\n}\n\nfunction buildImportedResult(\n\troot: ImportedAsyncRoot,\n\tstatus: AsyncStatus | null,\n\tresult: AsyncResultFile,\n): ImportedAsyncRootResult {\n\tconst child = result.results?.[root.index];\n\tconst step = selectedStatusStep(status, root.index);\n\tconst state = resultState(result, child);\n\tconst agent = child?.agent ?? step?.agent ?? status?.steps?.[root.index]?.agent ?? \"subagent\";\n\tconst output = child?.output ?? result.summary ?? \"\";\n\tconst timedOut =\n\t\tchild?.timedOut === true || step?.timedOut === true || result.timedOut === true || status?.timedOut === true;\n\tconst stopped =\n\t\tchild?.stopped === true ||\n\t\tstep?.stopped === true ||\n\t\tresult.stopped === true ||\n\t\tstatus?.stopped === true ||\n\t\tstate === \"stopped\";\n\tconst success = state === \"complete\" && !timedOut && !stopped;\n\tconst error =\n\t\tchild?.error ??\n\t\t(success\n\t\t\t? undefined\n\t\t\t: stopped\n\t\t\t\t? \"Subagent stopped by user.\"\n\t\t\t\t: (result.error ??\n\t\t\t\t\tresult.summary ??\n\t\t\t\t\tstatus?.error ??\n\t\t\t\t\t`Attached async root ${root.runId} did not complete successfully.`));\n\treturn {\n\t\tagent,\n\t\toutput: success ? output : output || error || \"\",\n\t\tsuccess,\n\t\texitCode: success ? 0 : 1,\n\t\t...(error ? { error } : {}),\n\t\t...(timedOut ? { timedOut: true } : {}),\n\t\t...(stopped ? { stopped: true } : {}),\n\t\t...((child?.sessionFile ?? step?.sessionFile ?? status?.sessionFile)\n\t\t\t? { sessionFile: child?.sessionFile ?? step?.sessionFile ?? status?.sessionFile }\n\t\t\t: {}),\n\t\t...(child?.intercomTarget ? { intercomTarget: child.intercomTarget } : {}),\n\t\t...((child?.model ?? step?.model) ? { model: child?.model ?? step?.model } : {}),\n\t\t...((child?.attemptedModels ?? step?.attemptedModels)\n\t\t\t? { attemptedModels: child?.attemptedModels ?? step?.attemptedModels }\n\t\t\t: {}),\n\t\t...((child?.modelAttempts ?? step?.modelAttempts)\n\t\t\t? { modelAttempts: child?.modelAttempts ?? step?.modelAttempts }\n\t\t\t: {}),\n\t\t...((child?.totalCost ?? step?.totalCost) ? { totalCost: child?.totalCost ?? step?.totalCost } : {}),\n\t\t...(child?.structuredOutput !== undefined\n\t\t\t? { structuredOutput: child.structuredOutput }\n\t\t\t: step?.structuredOutput !== undefined\n\t\t\t\t? { structuredOutput: step.structuredOutput }\n\t\t\t\t: {}),\n\t\t...((child?.structuredOutputPath ?? step?.structuredOutputPath)\n\t\t\t? { structuredOutputPath: child?.structuredOutputPath ?? step?.structuredOutputPath }\n\t\t\t: {}),\n\t\t...((child?.structuredOutputSchemaPath ?? step?.structuredOutputSchemaPath)\n\t\t\t? { structuredOutputSchemaPath: child?.structuredOutputSchemaPath ?? step?.structuredOutputSchemaPath }\n\t\t\t: {}),\n\t\t...((child?.acceptance ?? step?.acceptance) ? { acceptance: child?.acceptance ?? step?.acceptance } : {}),\n\t};\n}\n\nexport async function waitForImportedAsyncRoot(\n\troot: ImportedAsyncRoot,\n\toptions: {\n\t\tpollIntervalMs?: number;\n\t\tterminalResultGraceMs?: number;\n\t\tnow?: () => number;\n\t\tshouldAbort?: () => boolean;\n\t\ttimeoutMessage?: string;\n\t} = {},\n): Promise<ImportedAsyncRootResult> {\n\tconst pollIntervalMs = options.pollIntervalMs ?? 500;\n\tconst terminalResultGraceMs = options.terminalResultGraceMs ?? 1_000;\n\tconst now = options.now ?? Date.now;\n\tlet terminalSince: number | undefined;\n\tfor (;;) {\n\t\tconst status = readStatus(root.asyncDir);\n\t\tif (options.shouldAbort?.())\n\t\t\treturn outputFromTimeout(root, status, options.timeoutMessage ?? \"Subagent timed out.\");\n\t\tconst result = readResultFile(root.resultPath);\n\t\tif (result) return buildImportedResult(root, status, result);\n\t\tif (isTerminalStatus(status, root.index)) {\n\t\t\tterminalSince ??= now();\n\t\t\tif (now() - terminalSince >= terminalResultGraceMs) {\n\t\t\t\treturn outputFromTerminalStatus(root, status!, selectedStatusStep(status, root.index));\n\t\t\t}\n\t\t} else {\n\t\t\tterminalSince = undefined;\n\t\t}\n\t\tif (!status && !fs.existsSync(root.asyncDir)) {\n\t\t\tthrow new Error(`Attached async root '${root.runId}' directory does not exist: ${root.asyncDir}`);\n\t\t}\n\t\tawait new Promise((resolve) => setTimeout(resolve, pollIntervalMs));\n\t}\n}\n\nexport function resolveAsyncRootResultPath(resultsDir: string, runId: string): string {\n\treturn path.join(resultsDir, `${runId}.json`);\n}\n"]}