@duckmind/dm-windows-x64 0.60.6 → 0.60.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dm.exe +0 -0
- package/extensions/.dm-extensions.json +70 -123
- package/extensions/dm-9router-ext/src/index.js +410 -5
- package/extensions/dm-caveman/extensions/caveman.js +283 -12
- package/extensions/dm-cliproxy/index.js +182 -2
- package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
- package/extensions/dm-cliproxy/src/apply.js +228 -1
- package/extensions/dm-cliproxy/src/cache.js +42 -1
- package/extensions/dm-cliproxy/src/commands.js +50 -2
- package/extensions/dm-cliproxy/src/compat.js +81 -1
- package/extensions/dm-cliproxy/src/config.js +192 -2
- package/extensions/dm-cliproxy/src/conflicts.js +46 -1
- package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
- package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
- package/extensions/dm-cliproxy/src/log.js +23 -1
- package/extensions/dm-cliproxy/src/status-quota.js +77 -1
- package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
- package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
- package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
- package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
- package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
- package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
- package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
- package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
- package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
- package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
- package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
- package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
- package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
- package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
- package/extensions/dm-context/src/context.js +144 -1
- package/extensions/dm-context/src/index.js +339 -7
- package/extensions/dm-context/src/utils.js +9 -1
- package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
- package/extensions/dm-cua/index.js +75 -6
- package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
- package/extensions/dm-cua/src/browser-install.mjs +331 -2
- package/extensions/dm-fff/src/index.js +688 -12
- package/extensions/dm-fff/src/query.js +60 -1
- package/extensions/dm-goal/src/goal.js +894 -23
- package/extensions/dm-image2/index.js +103 -9
- package/extensions/dm-image2/src/image-lib.mjs +1275 -8
- package/extensions/dm-subagents/install.mjs +62 -8
- package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
- package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
- package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
- package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
- package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
- package/extensions/dm-subagents/src/agents/agents.js +1139 -11
- package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
- package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
- package/extensions/dm-subagents/src/agents/identity.js +29 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
- package/extensions/dm-subagents/src/agents/skills.js +614 -6
- package/extensions/dm-subagents/src/extension/config.js +35 -2
- package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
- package/extensions/dm-subagents/src/extension/doctor.js +172 -15
- package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
- package/extensions/dm-subagents/src/extension/index.js +521 -359
- package/extensions/dm-subagents/src/extension/rpc.js +266 -7
- package/extensions/dm-subagents/src/extension/schemas.js +275 -1
- package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
- package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
- package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
- package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
- package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
- package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
- package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
- package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
- package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
- package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
- package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
- package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
- package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
- package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
- package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
- package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
- package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
- package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
- package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
- package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
- package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
- package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
- package/extensions/dm-subagents/src/shared/formatters.js +98 -7
- package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
- package/extensions/dm-subagents/src/shared/model-info.js +62 -1
- package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
- package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
- package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
- package/extensions/dm-subagents/src/shared/settings.js +198 -11
- package/extensions/dm-subagents/src/shared/status-format.js +53 -1
- package/extensions/dm-subagents/src/shared/types.js +184 -6
- package/extensions/dm-subagents/src/shared/utils.js +462 -2
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
- package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
- package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
- package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
- package/extensions/dm-subagents/src/tui/render.js +1542 -4
- package/extensions/dm-usage/index.js +1294 -9
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
- package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
- package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
- package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
- package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
- package/extensions/greedysearch-dm/bin/search.mjs +620 -540
- package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
- package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
- package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
- package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
- package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
- package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
- package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
- package/extensions/greedysearch-dm/index.js +123 -23
- package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
- package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
- package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
- package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
- package/extensions/greedysearch-dm/src/github.mjs +222 -7
- package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
- package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
- package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
- package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
- package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
- package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
- package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
- package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
- package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
- package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
- package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
- package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
- package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
- package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
- package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
- package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
- package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
- package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
- package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
- package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
- package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
- package/package.json +1 -1
|
@@ -1,51 +1,1171 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`;if(J+W+Buffer.byteLength(z,"utf-8")>X){U();return}try{_$.appendFileSync($.transcriptPath,q,"utf-8"),J+=W}catch(j){Z=`Failed to write child transcript '${$.transcriptPath}': ${C0(j)}`}};try{_$.mkdirSync(A1.dirname($.transcriptPath),{recursive:!0}),_$.writeFileSync($.transcriptPath,"","utf-8")}catch(H){Z=`Failed to initialize child transcript '${$.transcriptPath}': ${C0(H)}`}let Y=(H,q)=>{let W=R$(q.content);G({...B("message"),sourceEventType:H,role:q.role,...W?{text:W}:{},...q.model?{model:q.model}:{},...q.stopReason?{stopReason:q.stopReason}:{},...q.errorMessage?{errorMessage:q.errorMessage}:{},...q.usage?{usage:o2(q.usage)}:{},message:q})};return{path:$.transcriptPath,writeInitialUserMessage(H){G({...B("message"),sourceEventType:"initial_prompt",role:"user",text:H,message:{role:"user",content:[{type:"text",text:H}]}})},writeChildEvent(H){if((H.type==="message_end"||H.type==="tool_result_end")&&H.message){Y(H.type,H.message);return}if(H.type==="tool_execution_start"&&H.toolName){let q=l2(H);G({...B("tool_start"),sourceEventType:H.type,toolName:H.toolName,...Object.keys(q).length>0?{argsPreview:Z0(q)}:{}});return}if(H.type==="tool_execution_end")G({...B("tool_end"),sourceEventType:H.type,...H.toolName?{toolName:H.toolName}:{}})},writeStdoutLine(H){if(!H.trim())return;G({...B("stdout"),text:H})},writeStderrLine(H){if(!H.trim())return;G({...B("stderr"),text:H})},writeStderrText(H){for(let q of H.split(/\r?\n/))this.writeStderrLine(q)},getError(){return Z}}}var s2=["event","async","intercom"],i2=["active_long_running","needs_attention"],C1={enabled:!0,needsAttentionAfterMs:60000,activeNoticeAfterMs:240000,failedToolAttemptsBeforeAttention:3,notifyOn:i2,notifyChannels:s2};function N1($){if(!$.config.enabled)return;let J=$.now??Date.now(),Z=$.lastActivityAt??$.startedAt;return Math.max(0,J-Z)>$.config.needsAttentionAfterMs?"needs_attention":void 0}function X0($){let J=$.ts??Date.now(),Z=$.type??($.to==="active_long_running"?"active_long_running":"needs_attention"),Q=$.elapsedMs??($.lastActivityAt?Math.max(0,J-$.lastActivityAt):void 0),X=Q!==void 0?Math.floor(Q/1000):void 0,B=$.message??(Z==="active_long_running"?`${$.agent} is still active but long-running`:X!==void 0?`${$.agent} needs attention (no observed activity for ${X}s)`:`${$.agent} needs attention`);return{type:Z,...$.from?{from:$.from}:{},to:$.to,ts:J,runId:$.runId,agent:$.agent,...$.index!==void 0?{index:$.index}:{},message:B,reason:$.reason??(Z==="active_long_running"?"active_long_running":"idle"),...$.turns!==void 0?{turns:$.turns}:{},...$.tokens!==void 0?{tokens:$.tokens}:{},...$.toolCount!==void 0?{toolCount:$.toolCount}:{},...$.currentTool?{currentTool:$.currentTool}:{},...$.currentToolDurationMs!==void 0?{currentToolDurationMs:$.currentToolDurationMs}:{},...$.currentPath?{currentPath:$.currentPath}:{},...Q!==void 0?{elapsedMs:Q}:{},...$.recentFailureSummary?{recentFailureSummary:$.recentFailureSummary}:{}}}function N0($,J){return $.enabled&&$.notifyOn.includes(J.type)}function r2($,J){return`${J??($.index!==void 0?`${$.runId}:${$.index}`:$.runId)}:${$.type}:${$.reason??"idle"}`}function L1($,J,Z,Q){if(!N0($,J))return!1;let X=r2(J,Q);if(Z.has(X))return!1;return Z.add(X),!0}import*as f from"node:fs";import*as k from"node:path";import*as Y$ from"node:fs";import*as l from"node:path";import{fileURLToPath as T8}from"node:url";import*as G$ from"node:fs";import{Compile as a2}from"typebox/compile";var T1="DM_SUBAGENT_STRUCTURED_OUTPUT_SCHEMA",E1="DM_SUBAGENT_STRUCTURED_OUTPUT_CAPTURE";function R1($,J){let Z;try{Z=a2($)}catch(X){return{status:"invalid",message:`invalid outputSchema: ${X instanceof Error?X.message:String(X)}`}}if(Z.Check(J))return{status:"valid"};return{status:"invalid",message:[...Z.Errors(J)].slice(0,8).map((X)=>{return`${X.instancePath?X.instancePath.replace(/^\//,"").replace(/\//g,"."):"root"}: ${X.message}`}).join("; ")||"schema validation failed"}}function M1($){if(!G$.existsSync($.outputPath))return{error:"Missing structured_output call; this step has outputSchema and must finish by calling structured_output."};let J;try{J=JSON.parse(G$.readFileSync($.outputPath,"utf-8"))}catch(Q){return{error:`Failed to read structured output: ${Q instanceof Error?Q.message:String(Q)}`}}let Z=R1($.schema,J);if(Z.status==="invalid")return{error:`Structured output validation failed: ${Z.message}`};return{value:J}}var e2=new Set(["expand","parallel","collect","concurrency","failFast","phase","label","acceptance"]),b4=new Set([...e2,"effectiveAcceptance","sessionFiles","thinkingOverrides"]);var $8=new Set(["agent","task","phase","label","outputSchema","cwd","output","outputMode","reads","progress","skill","model","toolBudget","acceptance"]),k4=new Set([...$8,"outputName","structured","inheritProjectContext","inheritSkills","skills","outputPath","maxSubagentDepth","structuredOutput","structuredOutputSchema","tools","extensions","subagentOnlyExtensions","mcpDirectTools","completionGuard","systemPrompt","systemPromptMode","thinking","modelCandidates","sessionFile","effectiveAcceptance","parentSessionId"]);import{spawn as J8}from"node:child_process";import{spawnSync as Z8}from"node:child_process";import*as w1 from"node:path";var M$={none:0,attested:1,checked:2,verified:3,reviewed:4};var Q8=new Set(["changed-files","tests-added","commands-run","validation-output","residual-risks","no-staged-files","diff-summary","review-findings","manual-notes"]);function X8($){return $??"auto"}function W8($){return[...new Set($)]}function L0($){switch($){case"none":return[];case"attested":return["manual-notes","residual-risks"];case"checked":return["changed-files","tests-added","commands-run","residual-risks","no-staged-files"];case"verified":case"reviewed":return["changed-files","tests-added","commands-run","validation-output","residual-risks","no-staged-files"]}}function B8($){let J=$.agentName.toLowerCase(),Z=$.task?.toLowerCase()??"",Q=[],X=/\b(?:reviewer|scout|context-builder|researcher|analyst)\b/.test(J),B=/\b(?:read[- ]only|review[- ]only|do not edit|don't edit|no edits|without edits|inspect|summari[sz]e)\b/.test(Z),U=/\b(?:fix|implement|update|write|edit|modify|migrate|release|security|delete|remove|refactor|commit)\b/.test(Z)||/\bworker\b/.test(J);if(Boolean($.async&&U)||Boolean($.dynamic)||Boolean($.dynamicGroup)||/\b(?:release|migration|migrate|security|data[- ]loss|destructive|post-review|fix pass)\b/.test(Z)){if(Q.push($.async?"async write-capable or risky run":"risky write-capable run"),$.dynamic||$.dynamicGroup)Q.push("dynamic fanout context");return{level:"reviewed",reasons:Q,criteria:["Implement the requested change without widening scope","Return evidence sufficient for an independent acceptance review"],evidence:L0("reviewed"),review:{agent:"reviewer",required:!0}}}if(U&&!B)return Q.push("write-capable worker/task"),{level:"checked",reasons:Q,criteria:["Implement the requested change without widening scope"],evidence:L0("checked")};if(X||B)return Q.push(X?"read-only/reviewer-style agent":"read-only task wording"),{level:"attested",reasons:Q,criteria:["Return concrete findings with file paths and severity when applicable"],evidence:["review-findings","residual-risks"]};return Q.push("default lightweight attestation"),{level:"attested",reasons:Q,criteria:["Return a concise result and residual risks when applicable"],evidence:["manual-notes","residual-risks"]}}function U8($){if($===void 0||$==="auto")return{level:"auto"};if($===!1)return{level:"none",reason:"disabled by deprecated false shorthand"};if(typeof $==="string")return{level:$};return{...$}}function G8($){return $.level==="none"&&typeof $.reason==="string"&&$.reason.trim().length>0}function Y8($,J){return($??[]).map((Z,Q)=>{if(typeof Z==="string")return{id:`criterion-${Q+1}`,must:Z,evidence:J,severity:"required"};return{id:Z.id?.trim()||`criterion-${Q+1}`,must:Z.must??"",evidence:Z.evidence?.filter((X)=>Q8.has(X))??J,severity:Z.severity??"required"}}).filter((Z)=>Z.must.trim())}function S1($){let J=U8($.explicit),Z=B8($),Q=X8(J.level),X=G8(J)?"none":Q==="auto"?Z.level:M$[Q]>=M$[Z.level]?Q:Z.level,B=W8([...X===Z.level?Z.evidence:L0(X),...J.evidence??[]]),U=Y8(J.criteria?.length?J.criteria:Z.criteria,B),G=J.review!==void 0?J.review:Z.review;if(X==="reviewed"&&Q!=="auto"&&Q!=="reviewed"&&J.review===void 0&&G&&G!==!1)G={...G,required:!1};return{level:X,explicit:$.explicit!==void 0,inferredReason:Z.reasons,criteria:U,evidence:B,verify:J.verify??[],review:G,stopRules:J.stopRules??[],reason:J.reason}}function f1($){if($.level==="none")return"";let J=["","## Acceptance Contract",`Acceptance level: ${$.level}`,"Completion is not accepted from prose alone. End with a structured acceptance report.","","Criteria:",...$.criteria.length?$.criteria.map((Z)=>`- ${Z.id}: ${Z.must}`):["- Return the requested result."],"",`Required evidence: ${$.evidence.join(", ")||"none"}`];if($.verify.length>0){J.push("","Runtime verification commands configured by parent:");for(let Z of $.verify)J.push(`- ${Z.id}: ${Z.command}`)}if($.review&&$.review!==!1){if(J.push("",`Review gate: ${$.review.required===!1?"optional":"required"}${$.review.agent?` by ${$.review.agent}`:""}.`),$.review.focus)J.push(`Review focus: ${$.review.focus}`)}if($.stopRules.length>0)J.push("","Stop rules:",...$.stopRules.map((Z)=>`- ${Z}`));return J.push("","Finish with a fenced JSON block tagged `acceptance-report` in this shape:","Use empty arrays when no items apply; array fields contain strings unless object entries are shown.","```acceptance-report",JSON.stringify({criteriaSatisfied:[{id:"criterion-1",status:"satisfied",evidence:"specific proof"}],changedFiles:["src/file.ts"],testsAddedOrUpdated:["test/file.test.ts"],commandsRun:[{command:"command",result:"passed",summary:"short result"}],validationOutput:["validation output or concise summary"],residualRisks:["none"],noStagedFiles:!0,diffSummary:"short description of the diff",reviewFindings:["blocker: file.ts:12 - issue found, or no blockers"],manualNotes:"anything else the parent should know"},null,2),"```"),J.join(`
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`,W=Buffer.byteLength(q,"utf-8");if(G+W>Y)return;try{let z=X.write(q);if(G+=W,!z&&!B)B=!0,J.pause(),X.once("drain",()=>{if(B=!1,!U)J.resume()})}catch{}},async close(){if(!X||U)return;U=!0;let H=X;X=void 0,await new Promise((q)=>H.end(()=>q()))}}}function s($,J){try{return $.kill(J)}catch{return!1}}function YJ($,J){let{idleMs:Z,hardMs:Q}=J,X=!1,B=!1,U=!1,G,Y,H=()=>{if(!B)try{$.stdout?.destroy()}catch{}if(!U)try{$.stderr?.destroy()}catch{}},q=()=>{if(G)clearTimeout(G),G=void 0;if(Y)clearTimeout(Y),Y=void 0},W=()=>{if(!X)return;if(G)clearTimeout(G);G=setTimeout(H,Z),G.unref?.()};return $.stdout?.on("data",W),$.stderr?.on("data",W),$.stdout?.on("end",()=>{if(B=!0,B&&U)q()}),$.stderr?.on("end",()=>{if(U=!0,B&&U)q()}),$.on("exit",()=>{if(X=!0,W(),Y)return;Y=setTimeout(H,Q),Y.unref?.()}),$.on("close",q),$.on("error",q),q}import*as p from"node:fs";import*as k0 from"node:os";import*as P from"node:path";import{fileURLToPath as yJ}from"node:url";import*as VJ from"node:path";var t8=128,e8=4;function $9($){return typeof $==="string"&&$.length>0&&$.length<=t8&&!VJ.isAbsolute($)&&!$.includes("/")&&!$.includes("\\")&&!$.includes("..")}function HJ($){return typeof $==="number"&&Number.isFinite($)?$:void 0}function qJ($,J){return typeof $==="string"&&$.length>0?$.slice(0,J):void 0}function zJ($){if(!Array.isArray($))return[];return $.map((J)=>{if(!J||typeof J!=="object")return;let Z=J;if(!$9(Z.runId))return;return{runId:Z.runId,...HJ(Z.stepIndex)!==void 0?{stepIndex:HJ(Z.stepIndex)}:{},...qJ(Z.agent,128)?{agent:qJ(Z.agent,128)}:{}}}).filter((J)=>Boolean(J)).slice(0,e8)}function KJ($){if(!$)return[];try{return zJ(JSON.parse($))}catch{return[]}}function _J($){let J=zJ($);return J.length?JSON.stringify(J):""}import{createHash as J9}from"node:crypto";import*as I$ from"node:fs";import*as i from"node:os";import*as g from"node:path";var Z9=1,Q9=604800000,jJ=new Set(["read","bash","edit","write","grep","find","ls","mcp"]),AJ=g.join(i.homedir(),".config","mcp","mcp.json"),NJ={cursor:[g.join(i.homedir(),".cursor","mcp.json")],"claude-code":[g.join(i.homedir(),".claude","mcp.json"),g.join(i.homedir(),".claude.json"),g.join(i.homedir(),".claude","claude_desktop_config.json")],"claude-desktop":[g.join(i.homedir(),"Library","Application Support","Claude","claude_desktop_config.json")],codex:[g.join(i.homedir(),".codex","config.json")],windsurf:[g.join(i.homedir(),".windsurf","mcp.json")],vscode:[".vscode/mcp.json"]};function LJ($,J=process.cwd()){if(!$?.length)return[];try{let Z=W9(J),Q=X9();if(!Q)return[];return z9(Z,Q,A9(Z.settings?.toolPrefix),$)}catch{return[]}}function X9(){let $=g.join(J$(),"mcp-cache.json"),J;try{J=JSON.parse(I$.readFileSync($,"utf-8"))}catch{return null}if(!J||typeof J!=="object")return null;let Z=J;if(Z.version!==Z9||!Z.servers||typeof Z.servers!=="object"||Array.isArray(Z.servers))return null;return Z}function W9($){let J={mcpServers:{}};for(let Z of B9($)){let Q=U9(Z);if(!Q)continue;J=Y9(J,H9(Q,$))}return J}function B9($){let J=g.join(J$(),"mcp.json"),Z=g.resolve($,".mcp.json"),Q=g.resolve(n($),"mcp.json"),X=[];if(AJ!==J)X.push(AJ);if(X.push(J),Z!==J)X.push(Z);if(Q!==J&&Q!==Z)X.push(Q);return X}function U9($){let J;try{J=JSON.parse(I$.readFileSync($,"utf-8"))}catch{return null}return G9(J)}function G9($){if(!$||typeof $!=="object"||Array.isArray($))return{mcpServers:{}};let J=$,Z=J.mcpServers??J["mcp-servers"]??{};return{mcpServers:Z&&typeof Z==="object"&&!Array.isArray(Z)?Z:{},imports:Array.isArray(J.imports)?J.imports.filter((Q)=>F9(Q)):void 0,settings:J.settings&&typeof J.settings==="object"&&!Array.isArray(J.settings)?J.settings:void 0}}function Y9($,J){let Z=[...$.imports??[],...J.imports??[]];return{mcpServers:{...$.mcpServers,...J.mcpServers},imports:Z.length?[...new Set(Z)]:void 0,settings:J.settings?{...$.settings,...J.settings}:$.settings}}function H9($,J){if(!$.imports?.length)return $;let Z={};for(let Q of $.imports){let X=q9(Q,J);if(!X)continue;let B;try{B=JSON.parse(I$.readFileSync(X,"utf-8"))}catch{continue}for(let[U,G]of Object.entries(V9(B,Q)))if(!Z[U])Z[U]=G}return{imports:$.imports,settings:$.settings,mcpServers:{...Z,...$.mcpServers}}}function q9($,J){for(let Z of NJ[$]){let Q=Z.startsWith(".")?g.resolve(J,Z):Z;if(I$.existsSync(Q))return Q}return null}function V9($,J){if(!$||typeof $!=="object"||Array.isArray($))return{};let Z=$,Q=J==="cursor"||J==="windsurf"||J==="vscode"?Z.mcpServers??Z["mcp-servers"]:Z.mcpServers;return Q&&typeof Q==="object"&&!Array.isArray(Q)?Q:{}}function z9($,J,Z,Q){let X=[],B=new Set,{servers:U,tools:G}=K9(Q);for(let[Y,H]of Object.entries($.mcpServers)){let q=J.servers[Y];if(!_9(q,H))continue;let W=U.has(Y)?!0:G.get(Y);if(!W)continue;for(let z of Array.isArray(q.tools)?q.tools:[]){if(typeof z?.name!=="string"||!z.name)continue;if(W!==!0&&!W.has(z.name))continue;if(FJ(z.name,Y,Z,H.excludeTools))continue;let j=l$(z.name,Y,Z);if(jJ.has(j)||B.has(j))continue;B.add(j),X.push(j)}if(H.exposeResources===!1)continue;for(let z of Array.isArray(q.resources)?q.resources:[]){if(typeof z?.name!=="string"||!z.name||typeof z.uri!=="string"||!z.uri)continue;let j=`get_${N9(z.name)}`;if(W!==!0&&!W.has(j))continue;if(FJ(j,Y,Z,H.excludeTools))continue;let L=l$(j,Y,Z);if(jJ.has(L)||B.has(L))continue;B.add(L),X.push(L)}}return X}function K9($){let J=new Set,Z=new Map;for(let Q of $)if(Q=Q.replace(/\/+$/,""),Q.includes("/")){let[X,B]=Q.split("/",2);if(X&&B){if(!Z.has(X))Z.set(X,new Set);Z.get(X).add(B)}else if(X)J.add(X)}else if(Q)J.add(Q);return{servers:J,tools:Z}}function _9($,J){if(!$||$.configHash!==j9(J))return!1;if(!$.cachedAt||typeof $.cachedAt!=="number")return!1;return Date.now()-$.cachedAt<=Q9}function j9($){let J={command:$.command,args:$.args,env:CJ($.env),cwd:L9($.cwd),url:$.url,headers:CJ($.headers),auth:$.auth,bearerToken:O9($),bearerTokenEnv:$.bearerTokenEnv,exposeResources:$.exposeResources,excludeTools:$.excludeTools};return J9("sha256").update(f0(J)).digest("hex")}function A9($){return $==="none"||$==="short"||$==="server"?$:"server"}function F9($){return typeof $==="string"&&Object.hasOwn(NJ,$)}function C9($,J){if(J==="none")return"";if(J==="short")return $.replace(/-?mcp$/i,"").replace(/-/g,"_")||"mcp";return $.replace(/-/g,"_")}function l$($,J,Z){let Q=C9(J,Z);return Q?`${Q}_${$}`:$}function FJ($,J,Z,Q){if(!Array.isArray(Q)||Q.length===0)return!1;let X=new Set([o$($),o$(l$($,J,Z)),o$(l$($,J,"server")),o$(l$($,J,"short"))]);return Q.some((B)=>typeof B==="string"&&X.has(o$(B)))}function o$($){return $.replace(/-/g,"_")}function N9($){let J=$.replace(/[^a-zA-Z0-9]/g,"_").replace(/_+/g,"_").replace(/^_+/,"").replace(/_+$/,"").toLowerCase();if(!J||/^\d/.test(J))J=`resource${J?`_${J}`:""}`;return J}function CJ($){if(!$||typeof $!=="object"||Array.isArray($))return;let J={};for(let[Z,Q]of Object.entries($))if(typeof Q==="string")J[Z]=y0(Q);return J}function y0($){return $.replace(/\$\{(\w+)\}/g,(J,Z)=>process.env[Z]??"").replace(/\$env:(\w+)/g,(J,Z)=>process.env[Z]??"")}function L9($){if(typeof $!=="string")return;let J=y0($);if(J==="~")return i.homedir();if(J.startsWith("~/")||J.startsWith("~\\"))return g.join(i.homedir(),J.slice(2));return J}function O9($){if(typeof $.bearerToken==="string")return y0($.bearerToken);return typeof $.bearerTokenEnv==="string"?process.env[$.bearerTokenEnv]:void 0}function f0($){if($===null||$===void 0||typeof $!=="object"){let Z=JSON.stringify($);return Z===void 0?"undefined":Z}if(Array.isArray($))return`[${$.map((Z)=>f0(Z)).join(",")}]`;let J=$;return`{${Object.keys(J).sort().map((Z)=>`${JSON.stringify(Z)}:${f0(J[Z])}`).join(",")}}`}var T9=["off","minimal","low","medium","high","xhigh"],E9=8000;function DJ($,J){let Z=yJ($),Q=P.extname(Z),X=[".js",".mjs",".cjs",".ts",".mts",".cts"].includes(Q)?Q:".ts";return P.join(P.dirname(Z),`${J}${X}`)}function xJ($){return P.basename(yJ($)).startsWith("dm-args.")}function R9($=import.meta.url){let J=xJ($)?"subagent-prompt-runtime":P.join("..","runs","shared","subagent-prompt-runtime");return DJ($,J)}function M9($=import.meta.url){let J=xJ($)?P.join("..","..","extension","fanout-child"):"fanout-child";return DJ($,J)}var OJ=R9(),I9=M9(),w9="DM_SUBAGENT_CHILD",S9="DM_SUBAGENT_ORCHESTRATOR_TARGET",f9="DM_SUBAGENT_ORCHESTRATOR_SESSION_ID",y9="DM_SUBAGENT_SUPERVISOR_CHANNEL_DIR",TJ="DM_SUBAGENT_RUN_ID",D9="DM_SUBAGENT_CHILD_AGENT",x9="DM_SUBAGENT_CHILD_INDEX",b9="DM_SUBAGENT_FANOUT_CHILD",D0="DM_SUBAGENT_PARENT_EVENT_SINK",EJ="DM_SUBAGENT_PARENT_CONTROL_INBOX",x0="DM_SUBAGENT_PARENT_ROOT_RUN_ID",RJ="DM_SUBAGENT_PARENT_RUN_ID",MJ="DM_SUBAGENT_PARENT_CHILD_INDEX",IJ="DM_SUBAGENT_PARENT_DEPTH",wJ="DM_SUBAGENT_PARENT_PATH",b0="DM_SUBAGENT_PARENT_CAPABILITY_TOKEN",SJ="DM_SUBAGENT_PARENT_SESSION",k9="DM_SUBAGENT_STEER_INBOX";function fJ($){return $.trim().replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"unknown"}function P9($,J,Z){return P.join(O$,"supervisor-channels",`${fJ($)}-${fJ(J)}-${Z}`)}function P0($,J,Z=!1){if(!$||!J)return $;let Q=$.lastIndexOf(":");if(Q!==-1&&T9.includes($.substring(Q+1)))return Z?`${$.slice(0,Q)}:${J}`:$;return`${$}:${J}`}function bJ($){let J=[...$.baseArgs];if($.sessionFile)p.mkdirSync(P.dirname($.sessionFile),{recursive:!0}),J.push("--session",$.sessionFile);else{if(!$.sessionEnabled)J.push("--no-session");if($.sessionDir)p.mkdirSync($.sessionDir,{recursive:!0}),J.push("--session-dir",$.sessionDir)}let Z=P0($.model,$.thinking);if(Z)J.push("--model",Z);let Q=$.tools?.filter((T)=>!(T.includes("/")||T.endsWith(".ts")||T.endsWith(".js")))??[],X=$.requireReadTool&&$.tools?.length&&!Q.includes("read")?["read",...Q]:Q,B=X.includes("subagent"),U=[];if($.tools?.length){let T=[...X];for(let x of $.tools)if(!X.includes(x)&&(x.includes("/")||x.endsWith(".ts")||x.endsWith(".js")))U.push(x);if(T.length>0){if($.mcpDirectTools?.length)T.push(...LJ($.mcpDirectTools,$.cwd));J.push("--tools",T.join(","))}}let G=B?[OJ,I9]:[OJ];if($.extensions!==void 0){J.push("--no-extensions");for(let T of[...new Set([...G,...U,...$.extensions,...$.subagentOnlyExtensions??[]])])J.push("--extension",T)}else for(let T of[...new Set([...G,...U,...$.subagentOnlyExtensions??[]])])J.push("--extension",T);if(!$.inheritSkills)J.push("--no-skills");let Y;if($.systemPrompt!==void 0&&$.systemPrompt!==null){Y=p.mkdtempSync(P.join(k0.tmpdir(),"dm-subagent-"));let T=($.promptFileStem??"prompt").replace(/[^\w.-]/g,"_"),x=P.join(Y,`${T}.md`);p.writeFileSync(x,$.systemPrompt,{mode:384}),J.push($.systemPromptMode==="replace"?"--system-prompt":"--append-system-prompt",x)}if($.task.length>E9){if(!Y)Y=p.mkdtempSync(P.join(k0.tmpdir(),"dm-subagent-"));let T=P.join(Y,"task.md");p.writeFileSync(T,`Task: ${$.task}`,{mode:384}),J.push(`@${T}`)}else J.push(`Task: ${$.task}`);let H={};H[w9]="1",H[b9]=B?"1":"0";let q=Boolean(process.env[D0]&&process.env[x0]&&process.env[b0]),W=$.parentRunId??$.runId??(q?process.env[TJ]:void 0)??process.env[RJ]??"",z=$.parentChildIndex!==void 0?String($.parentChildIndex):$.childIndex!==void 0?String($.childIndex):process.env[MJ]??"",j=Number(process.env[IJ]),L=$.parentDepth??(q&&Number.isFinite(j)?j+1:1),C=$.parentPath??[...KJ(process.env[wJ]),...W?[{runId:W,...z&&/^\d+$/.test(z)?{stepIndex:Number(z)}:{},...$.childAgentName?{agent:$.childAgentName}:{}}]:[]];if(H[D0]=B?$.parentEventSink??process.env[D0]??"":"",H[EJ]=B?$.parentControlInbox??process.env[EJ]??"":"",H[x0]=B?$.parentRootRunId??process.env[x0]??$.runId??"":"",H[RJ]=B?W:"",H[MJ]=B?z:"",H[IJ]=B?String(L):"",H[wJ]=B?_J(C):"",H[b0]=B?$.parentCapabilityToken??process.env[b0]??"":"",H.DM_SUBAGENT_INHERIT_PROJECT_CONTEXT=$.inheritProjectContext?"1":"0",H.DM_SUBAGENT_INHERIT_SKILLS=$.inheritSkills?"1":"0",$.intercomSessionName)H.DM_SUBAGENT_INTERCOM_SESSION_NAME=$.intercomSessionName;if($.orchestratorIntercomTarget)H[S9]=$.orchestratorIntercomTarget;if($.parentSessionId)H[f9]=$.parentSessionId;if($.orchestratorIntercomTarget&&$.parentSessionId&&$.runId&&$.childAgentName){let T=$.childIndex??0,x=P9($.runId,$.childAgentName,T);p.mkdirSync(P.join(x,"requests"),{recursive:!0}),p.mkdirSync(P.join(x,"replies"),{recursive:!0}),H[y9]=x}if($.runId)H[TJ]=$.runId;if($.childAgentName)H[D9]=$.childAgentName;if($.childIndex!==void 0)H[x9]=String($.childIndex);if($.mcpDirectTools?.length)H.MCP_DIRECT_TOOLS=$.mcpDirectTools.join(",");else H.MCP_DIRECT_TOOLS="__none__";if($.structuredOutput)H[E1]=$.structuredOutput.outputPath,H[T1]=$.structuredOutput.schemaPath;if($.steerInboxDir)H[k9]=$.steerInboxDir;let R=v1($.toolBudget);if(R)H[h1]=R;return H[SJ]=$.parentSessionId??process.env[SJ]??"",{args:J,env:H,tempDir:Y}}function h0($){if(!$)return;try{p.rmSync($,{recursive:!0,force:!0})}catch{}}import*as Z$ from"node:fs";import*as s$ from"node:path";function h9($){return[`Write your findings to exactly this path: ${$}`,"This path is authoritative for this run.","Ignore any other output filename or output path mentioned elsewhere, including output destinations in the base agent prompt, system prompt, or task instructions."].join(`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
${J}`:$}function sJ($){return{...$,outcome:"within-budget",turnCount:0}}function m0($,J,Z){return{...$,turnCount:J,outcome:Z?"exceeded":"wrap-up-requested",wrapUpRequestedAtTurn:$.maxTurns,...Z?{exceededAtTurn:J}:{}}}function iJ($,J,Z){let Q=$.maxTurns+$.graceTurns;if(J<Q)return!1;if(J>Q)return!0;return!Z}var aJ=new WeakMap,tJ=new WeakMap;function w$(){return{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0}}function s9($,J){$.input+=J.input,$.output+=J.output,$.cacheRead+=J.cacheRead,$.cacheWrite+=J.cacheWrite,$.cost+=J.cost,$.turns+=J.turns}function eJ($){return`Subagent timed out after ${$}ms.`}function i9($){if($.timeoutMs===void 0)return;let J=$.deadlineAt??Date.now()+$.timeoutMs;return{timeoutMs:$.timeoutMs,remainingMs:Math.max(0,J-Date.now()),message:eJ($.timeoutMs)}}function rJ($,J){return{status:$.level==="none"?"not-required":"rejected",explicit:$.explicit,effectiveAcceptance:$,inferredReason:$.inferredReason,criteria:$.criteria,runtimeChecks:$.level==="none"?[]:[{id:J.id,status:"failed",message:J.message}],verifyRuns:[]}}function c0($,J){if(J.length===0)return;if($.recentOutput.push(...J.filter((Z)=>Z.trim())),$.recentOutput.length>50)$.recentOutput.splice(0,$.recentOutput.length-50)}function r9($){for(let J of $??[]){if(J.role!=="assistant"||!Array.isArray(J.content))continue;for(let Z of J.content)if(Z.type==="text"&&"text"in Z&&typeof Z.text==="string")Z.text=W0(Z.text)}}function u0($){return{...$,skills:$.skills?[...$.skills]:void 0,recentTools:$.recentTools.map((J)=>({...J})),recentOutput:[...$.recentOutput]}}function d0($,J){return{...$,messages:$.outputMode==="file-only"&&$.savedOutputPath?void 0:$.messages?[...$.messages]:void 0,usage:{...$.usage},skills:$.skills?[...$.skills]:void 0,attemptedModels:$.attemptedModels?[...$.attemptedModels]:void 0,modelAttempts:$.modelAttempts?$.modelAttempts.map((Z)=>({...Z,usage:Z.usage?{...Z.usage}:void 0})):void 0,controlEvents:$.controlEvents?$.controlEvents.map((Z)=>({...Z})):void 0,progress:J,progressSummary:$.progressSummary?{...$.progressSummary}:void 0,artifactPaths:$.artifactPaths?{...$.artifactPaths}:void 0,truncation:$.truncation?{...$.truncation}:void 0,outputReference:$.outputReference?{...$.outputReference}:void 0}}async function a9($,J,Z,Q,X,B){let U=X.thinkingOverride??J.thinking,G=P0(Q,U,X.thinkingOverride!==void 0),{args:Y,env:H,tempDir:q}=bJ({baseArgs:["--mode","json","-p"],task:Z,sessionEnabled:B.sessionEnabled,sessionDir:X.sessionDir,sessionFile:X.sessionFile,model:G,thinking:U,systemPromptMode:J.systemPromptMode,inheritProjectContext:J.inheritProjectContext,inheritSkills:J.inheritSkills,requireReadTool:Boolean(B.resolvedSkillNames?.length),tools:J.tools,extensions:J.extensions,subagentOnlyExtensions:J.subagentOnlyExtensions,systemPrompt:oJ(B.systemPrompt,X.turnBudget),mcpDirectTools:J.mcpDirectTools,cwd:X.cwd??$,promptFileStem:J.name,intercomSessionName:X.intercomSessionName,orchestratorIntercomTarget:X.orchestratorIntercomTarget,runId:X.runId,childAgentName:J.name,childIndex:X.index??0,parentEventSink:X.nestedRoute?.eventSink,parentControlInbox:X.nestedRoute?.controlInbox,parentRootRunId:X.nestedRoute?.rootRunId,parentCapabilityToken:X.nestedRoute?.capabilityToken,parentSessionId:X.parentSessionId,structuredOutput:X.structuredOutput,toolBudget:X.toolBudget}),W={agent:J.name,task:B.originalTask??Z,exitCode:0,messages:[],usage:w$(),model:G,artifactPaths:B.artifactPaths,transcriptPath:B.transcriptWriter?B.artifactPaths?.transcriptPath:void 0,skills:B.resolvedSkillNames,skillsWarning:B.skillsWarning,...X.turnBudget?{turnBudget:sJ(X.turnBudget)}:{},...X.toolBudget?{toolBudget:g1(X.toolBudget)}:{}},z=Date.now();if(X.structuredOutput)try{if(p0(X.structuredOutput.outputPath))l9(X.structuredOutput.outputPath)}catch{}let j=X.controlConfig??C1,L=!1,C=[],R=[],T=new Set,x=(N)=>{if(!N0(j,N))return;if(!L1(j,N,T))return;C.push(N),R.push(N),X.onControlEvent?.(N)},V={index:X.index??0,agent:J.name,status:"running",task:Z,skills:B.resolvedSkillNames,recentTools:[],recentOutput:[...B.attemptNotes],toolCount:0,tokens:0,durationMs:0,lastActivityAt:z};W.progress=V;let u=i9(X);if(u?.remainingMs===0)return W.exitCode=1,W.timedOut=!0,W.error=u.message,W.finalOutput=u.message,V.status="failed",V.error=u.message,W.progressSummary={toolCount:V.toolCount,tokens:V.tokens,durationMs:V.durationMs},W;let A$={...process.env,...H,...Q1(X.maxSubagentDepth)},Q$=!1,i$=await new Promise((N)=>{let r=BJ(Y),M=o9(r.command,r.args,{cwd:X.cwd??$,env:A$,stdio:["ignore","pipe","pipe"],windowsHide:!0}),F=GJ(B.jsonlPath,M.stdout),e="",O=!1,w=!1,D=!1,b=!1,X$,f$,r$,y$,D$,x$,b$,n0=!1,k$,P$,$2=()=>{if(k$)clearTimeout(k$),k$=void 0;if(P$)clearTimeout(P$),P$=void 0},o0=()=>{if(D$)clearTimeout(D$),D$=void 0;if(x$)clearTimeout(x$),x$=void 0;if(b$)clearTimeout(b$),b$=void 0},U0=()=>{D=!0,O=!0,W.detached=!0,W.detachedReason="intercom coordination",V.status="detached",V.durationMs=Date.now()-z,W.progressSummary={toolCount:V.toolCount,tokens:V.tokens,durationMs:V.durationMs},t$(-2)},l0=1000,J2=3000,s0=!1,h$=!1,G0=!1,F$,g$,a$=()=>{if(F$)clearTimeout(F$),F$=void 0;if(g$)clearTimeout(g$),g$=void 0},Z2=()=>{if(s0||F$||w||O||D)return;F$=setTimeout(()=>{if(w||O||D)return;if(!s(M,"SIGTERM"))return;if(h$=!0,!G0&&!X$)W.error=W.error??`Subagent process did not exit within ${l0}ms after its final message. Forcing termination.`;g$=setTimeout(()=>{if(w||O||D)return;h$=s(M,"SIGKILL")||h$},J2),g$.unref?.()},l0),F$.unref?.()},Q2=X.intercomEvents?.on?.(J1,(K)=>{if(!X.allowIntercomDetach||D||O||!b)return;if(!K||typeof K!=="object")return;let _=K.requestId;if(typeof _!=="string"||_.length===0)return;X.intercomEvents?.emit(Z1,{requestId:_,accepted:!0}),U0()}),t$=(K)=>{if(w)return;if(w=!0,a$(),H0(),o0(),$2(),y$)clearInterval(y$),y$=void 0;Q2?.(),f$?.(),r$?.(),N(K)},X2=()=>{if(R.length===0)return;let K=R;return R=[],K},i0=!1,v$,e$=$J(),W2=300000,r0=(K)=>V.currentToolStartedAt?Math.max(0,K-V.currentToolStartedAt):void 0,a0=(K,_={})=>{if(!j.enabled)return!1;let E=V.activityState;V.activityState="needs_attention";let y=X0({type:"needs_attention",from:E,to:"needs_attention",runId:X.runId,agent:J.name,index:X.index,ts:K,lastActivityAt:V.lastActivityAt,message:_.message,reason:_.reason??"idle",turns:W.usage.turns,tokens:V.tokens,toolCount:V.toolCount,currentTool:_.currentTool??V.currentTool,currentToolDurationMs:_.currentToolDurationMs??r0(K),currentPath:_.currentPath??V.currentPath,recentFailureSummary:_.recentFailureSummary});return x(y),E!=="needs_attention"},B2=(K,_)=>{if(!j.enabled||i0||V.activityState==="needs_attention")return!1;i0=!0;let E=V.activityState;return V.activityState="active_long_running",x(X0({type:"active_long_running",from:E,to:"active_long_running",runId:X.runId,agent:J.name,index:X.index,ts:K,message:`${J.name} is still active but long-running`,reason:_,turns:W.usage.turns,tokens:V.tokens,toolCount:V.toolCount,currentTool:V.currentTool,currentToolDurationMs:r0(K),currentPath:V.currentPath,elapsedMs:K-z})),!0},U2=(K)=>{let _=X.turnBudget;if(!_||W.timedOut||W.turnBudgetExceeded||L||O||w||D)return;let E=v0(_,K);W.turnBudgetExceeded=!0,W.wrapUpRequested=!0,W.turnBudget=m0(_,K,!0),W.error=E,W.finalOutput=E,V.status="failed",V.error=E,V.durationMs=Date.now()-z,W$(),s(M,"SIGINT"),k$=setTimeout(()=>{if(O||w||D||W.timedOut)return;s(M,"SIGTERM")},1000),k$.unref?.(),P$=setTimeout(()=>{if(O||w||D||W.timedOut)return;s(M,"SIGKILL")},4000),P$.unref?.()},G2=(K,_)=>{let E=X.turnBudget;if(!E||W.timedOut||W.turnBudgetExceeded)return;if(K<E.maxTurns){W.turnBudget={...E,outcome:"within-budget",turnCount:K};return}if(!n0)n0=!0,W.wrapUpRequested=!0,c0(V,[g0(E,K)]);if(W.turnBudget=m0(E,K,!1),iJ(E,K,_))U2(K)},Y0=(K)=>{if(!j.enabled)return!1;if(N1({config:j,startedAt:z,lastActivityAt:V.lastActivityAt,now:K})==="needs_attention")return V.activityState==="needs_attention"?!1:a0(K);let E=t1(j,{startedAt:z,now:K,turns:W.usage.turns,tokens:V.tokens});return E?B2(K,E):!1},Y2=(K)=>{if(!X.onUpdate||O)return;let _=u0(V),E=d0(W,_),y=X2();X.onUpdate({content:[{type:"text",text:K}],details:{mode:"single",results:[E],progress:[_],controlEvents:y}})},W$=()=>{if(!X.onUpdate||O)return;V.durationMs=Date.now()-z;let K=(W.timedOut||W.turnBudgetExceeded)&&W.finalOutput?W.finalOutput:d$(W.messages);Y2(K||"(running...)")},t0=(K)=>{if(!K.trim())return;F.writeLine(K);let _;try{_=JSON.parse(K)}catch{B.transcriptWriter?.writeStdoutLine(K);return}B.transcriptWriter?.writeChildEvent(_);let E=Date.now();if(V.durationMs=E-z,V.lastActivityAt=E,Y0(E),_.type==="tool_execution_start"){let y=_.args&&typeof _.args==="object"&&!Array.isArray(_.args)?_.args:{},v=!1;if(X.allowIntercomDetach&&(_.toolName==="intercom"||_.toolName==="contact_supervisor"))b=!0,v=_.toolName==="intercom"&&y.action==="ask"||_.toolName==="contact_supervisor"&&(y.reason==="need_decision"||y.reason==="interview_request");if(V.toolCount++,X.toolBudget)W.toolBudget=E0(X.toolBudget,V.toolCount);V.currentTool=_.toolName,V.currentToolArgs=Z0(y),V.currentToolStartedAt=E,V.currentPath=i1(_.toolName,y);let z$=r1(_.toolName,y);if(Q$=Q$||z$,v$={tool:_.toolName??"tool",path:V.currentPath,mutates:z$,startedAt:E},W$(),v&&!D&&!O)U0()}if(_.type==="tool_execution_end"){if(V.currentTool)V.recentTools.push({tool:V.currentTool,args:V.currentToolArgs||"",endMs:E});V.currentTool=void 0,V.currentToolArgs=void 0,V.currentToolStartedAt=void 0,V.currentPath=void 0,W$()}if(_.type==="message_end"&&_.message){if(W.messages.push(_.message),_.message.role==="assistant"){W.usage.turns++,V.turnCount=W.usage.turns;let y=_.message.stopReason,v=Array.isArray(_.message.content)&&_.message.content.some((H2)=>H2.type==="toolCall"),z$=y==="stop"&&!v;G2(W.usage.turns,z$);let C$=_.message.usage;if(C$)W.usage.input+=C$.input||0,W.usage.output+=C$.output||0,W.usage.cacheRead+=C$.cacheRead||0,W.usage.cacheWrite+=C$.cacheWrite||0,W.usage.cost+=C$.cost?.total||0,V.tokens=W.usage.input+W.usage.output;if(!W.model&&_.message.model)W.model=_.message.model;if(_.message.errorMessage)X$=_.message.errorMessage;let e0=R$(_.message.content);if(c0(V,e0.split(`
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
3
|
+
import {
|
|
4
|
+
ensureArtifactsDir,
|
|
5
|
+
getArtifactPaths,
|
|
6
|
+
writeArtifact,
|
|
7
|
+
writeMetadata
|
|
8
|
+
} from "../../shared/artifacts.js";
|
|
9
|
+
import { createChildTranscriptWriter } from "../../shared/child-transcript.js";
|
|
10
|
+
import {
|
|
11
|
+
DEFAULT_MAX_OUTPUT,
|
|
12
|
+
INTERCOM_DETACH_REQUEST_EVENT,
|
|
13
|
+
INTERCOM_DETACH_RESPONSE_EVENT,
|
|
14
|
+
truncateOutput,
|
|
15
|
+
getSubagentDepthEnv
|
|
16
|
+
} from "../../shared/types.js";
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_CONTROL_CONFIG,
|
|
19
|
+
buildControlEvent,
|
|
20
|
+
claimControlNotification,
|
|
21
|
+
deriveActivityState,
|
|
22
|
+
shouldNotifyControlEvent
|
|
23
|
+
} from "../shared/subagent-control.js";
|
|
24
|
+
import {
|
|
25
|
+
getFinalOutput,
|
|
26
|
+
findLatestSessionFile,
|
|
27
|
+
detectSubagentError,
|
|
28
|
+
extractToolArgsPreview,
|
|
29
|
+
extractTextFromContent
|
|
30
|
+
} from "../../shared/utils.js";
|
|
31
|
+
import { buildSkillInjection, resolveSkillsWithFallback } from "../../agents/skills.js";
|
|
32
|
+
import { buildAgentMemoryInjection } from "../../agents/agent-memory.js";
|
|
33
|
+
import { evaluateCompletionMutationGuard } from "../shared/completion-guard.js";
|
|
34
|
+
import { getPiSpawnCommand } from "../shared/dm-spawn.js";
|
|
35
|
+
import { createJsonlWriter } from "../../shared/jsonl-writer.js";
|
|
36
|
+
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.js";
|
|
37
|
+
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir } from "../shared/dm-args.js";
|
|
38
|
+
import { readStructuredOutput } from "../shared/structured-output.js";
|
|
39
|
+
import { captureSingleOutputSnapshot, formatSavedOutputReference, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode } from "../shared/single-output.js";
|
|
40
|
+
import {
|
|
41
|
+
buildModelCandidates,
|
|
42
|
+
formatModelAttemptNote,
|
|
43
|
+
isRetryableModelFailure
|
|
44
|
+
} from "../shared/model-fallback.js";
|
|
45
|
+
import {
|
|
46
|
+
createMutatingFailureState,
|
|
47
|
+
didMutatingToolFail,
|
|
48
|
+
isMutatingTool,
|
|
49
|
+
nextLongRunningTrigger,
|
|
50
|
+
recordMutatingFailure,
|
|
51
|
+
resetMutatingFailureState,
|
|
52
|
+
resolveCurrentPath,
|
|
53
|
+
shouldEscalateMutatingFailures,
|
|
54
|
+
summarizeRecentMutatingFailures
|
|
55
|
+
} from "../shared/long-running-guard.js";
|
|
56
|
+
import { acceptanceFailureMessage, evaluateAcceptance, formatAcceptancePrompt, resolveEffectiveAcceptance, stripAcceptanceReport } from "../shared/acceptance.js";
|
|
57
|
+
import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, shouldAbortForTurnBudget, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.js";
|
|
58
|
+
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.js";
|
|
59
|
+
const artifactOutputByResult = new WeakMap;
|
|
60
|
+
const acceptanceOutputByResult = new WeakMap;
|
|
61
|
+
function emptyUsage() {
|
|
62
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
|
|
63
|
+
}
|
|
64
|
+
function sumUsage(target, source) {
|
|
65
|
+
target.input += source.input;
|
|
66
|
+
target.output += source.output;
|
|
67
|
+
target.cacheRead += source.cacheRead;
|
|
68
|
+
target.cacheWrite += source.cacheWrite;
|
|
69
|
+
target.cost += source.cost;
|
|
70
|
+
target.turns += source.turns;
|
|
71
|
+
}
|
|
72
|
+
function formatTimeoutMessage(timeoutMs) {
|
|
73
|
+
return `Subagent timed out after ${timeoutMs}ms.`;
|
|
74
|
+
}
|
|
75
|
+
function resolveAttemptTimeout(options) {
|
|
76
|
+
if (options.timeoutMs === undefined)
|
|
77
|
+
return;
|
|
78
|
+
const deadlineAt = options.deadlineAt ?? Date.now() + options.timeoutMs;
|
|
79
|
+
return {
|
|
80
|
+
timeoutMs: options.timeoutMs,
|
|
81
|
+
remainingMs: Math.max(0, deadlineAt - Date.now()),
|
|
82
|
+
message: formatTimeoutMessage(options.timeoutMs)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function buildSkippedAcceptanceLedger(acceptance, input) {
|
|
86
|
+
return {
|
|
87
|
+
status: acceptance.level === "none" ? "not-required" : "rejected",
|
|
88
|
+
explicit: acceptance.explicit,
|
|
89
|
+
effectiveAcceptance: acceptance,
|
|
90
|
+
inferredReason: acceptance.inferredReason,
|
|
91
|
+
criteria: acceptance.criteria,
|
|
92
|
+
runtimeChecks: acceptance.level === "none" ? [] : [{ id: input.id, status: "failed", message: input.message }],
|
|
93
|
+
verifyRuns: []
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function appendRecentOutput(progress, lines) {
|
|
97
|
+
if (lines.length === 0)
|
|
98
|
+
return;
|
|
99
|
+
progress.recentOutput.push(...lines.filter((line) => line.trim()));
|
|
100
|
+
if (progress.recentOutput.length > 50) {
|
|
101
|
+
progress.recentOutput.splice(0, progress.recentOutput.length - 50);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function stripAcceptanceReportsFromMessages(messages) {
|
|
105
|
+
for (const message of messages ?? []) {
|
|
106
|
+
if (message.role !== "assistant" || !Array.isArray(message.content))
|
|
107
|
+
continue;
|
|
108
|
+
for (const part of message.content) {
|
|
109
|
+
if (part.type === "text" && "text" in part && typeof part.text === "string") {
|
|
110
|
+
part.text = stripAcceptanceReport(part.text);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function snapshotProgress(progress) {
|
|
116
|
+
return {
|
|
117
|
+
...progress,
|
|
118
|
+
skills: progress.skills ? [...progress.skills] : undefined,
|
|
119
|
+
recentTools: progress.recentTools.map((tool) => ({ ...tool })),
|
|
120
|
+
recentOutput: [...progress.recentOutput]
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function snapshotResult(result, progress) {
|
|
124
|
+
return {
|
|
125
|
+
...result,
|
|
126
|
+
messages: result.outputMode === "file-only" && result.savedOutputPath ? undefined : result.messages ? [...result.messages] : undefined,
|
|
127
|
+
usage: { ...result.usage },
|
|
128
|
+
skills: result.skills ? [...result.skills] : undefined,
|
|
129
|
+
attemptedModels: result.attemptedModels ? [...result.attemptedModels] : undefined,
|
|
130
|
+
modelAttempts: result.modelAttempts ? result.modelAttempts.map((attempt) => ({
|
|
131
|
+
...attempt,
|
|
132
|
+
usage: attempt.usage ? { ...attempt.usage } : undefined
|
|
133
|
+
})) : undefined,
|
|
134
|
+
controlEvents: result.controlEvents ? result.controlEvents.map((event) => ({ ...event })) : undefined,
|
|
135
|
+
progress,
|
|
136
|
+
progressSummary: result.progressSummary ? { ...result.progressSummary } : undefined,
|
|
137
|
+
artifactPaths: result.artifactPaths ? { ...result.artifactPaths } : undefined,
|
|
138
|
+
truncation: result.truncation ? { ...result.truncation } : undefined,
|
|
139
|
+
outputReference: result.outputReference ? { ...result.outputReference } : undefined
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared) {
|
|
143
|
+
const effectiveThinking = options.thinkingOverride ?? agent.thinking;
|
|
144
|
+
const modelArg = applyThinkingSuffix(model, effectiveThinking, options.thinkingOverride !== undefined);
|
|
145
|
+
const { args, env: sharedEnv, tempDir } = buildPiArgs({
|
|
146
|
+
baseArgs: ["--mode", "json", "-p"],
|
|
147
|
+
task,
|
|
148
|
+
sessionEnabled: shared.sessionEnabled,
|
|
149
|
+
sessionDir: options.sessionDir,
|
|
150
|
+
sessionFile: options.sessionFile,
|
|
151
|
+
model: modelArg,
|
|
152
|
+
thinking: effectiveThinking,
|
|
153
|
+
systemPromptMode: agent.systemPromptMode,
|
|
154
|
+
inheritProjectContext: agent.inheritProjectContext,
|
|
155
|
+
inheritSkills: agent.inheritSkills,
|
|
156
|
+
requireReadTool: Boolean(shared.resolvedSkillNames?.length),
|
|
157
|
+
tools: agent.tools,
|
|
158
|
+
extensions: agent.extensions,
|
|
159
|
+
subagentOnlyExtensions: agent.subagentOnlyExtensions,
|
|
160
|
+
systemPrompt: appendTurnBudgetSystemPrompt(shared.systemPrompt, options.turnBudget),
|
|
161
|
+
mcpDirectTools: agent.mcpDirectTools,
|
|
162
|
+
cwd: options.cwd ?? runtimeCwd,
|
|
163
|
+
promptFileStem: agent.name,
|
|
164
|
+
intercomSessionName: options.intercomSessionName,
|
|
165
|
+
orchestratorIntercomTarget: options.orchestratorIntercomTarget,
|
|
166
|
+
runId: options.runId,
|
|
167
|
+
childAgentName: agent.name,
|
|
168
|
+
childIndex: options.index ?? 0,
|
|
169
|
+
parentEventSink: options.nestedRoute?.eventSink,
|
|
170
|
+
parentControlInbox: options.nestedRoute?.controlInbox,
|
|
171
|
+
parentRootRunId: options.nestedRoute?.rootRunId,
|
|
172
|
+
parentCapabilityToken: options.nestedRoute?.capabilityToken,
|
|
173
|
+
parentSessionId: options.parentSessionId,
|
|
174
|
+
structuredOutput: options.structuredOutput,
|
|
175
|
+
toolBudget: options.toolBudget
|
|
176
|
+
});
|
|
177
|
+
const result = {
|
|
178
|
+
agent: agent.name,
|
|
179
|
+
task: shared.originalTask ?? task,
|
|
180
|
+
exitCode: 0,
|
|
181
|
+
messages: [],
|
|
182
|
+
usage: emptyUsage(),
|
|
183
|
+
model: modelArg,
|
|
184
|
+
artifactPaths: shared.artifactPaths,
|
|
185
|
+
transcriptPath: shared.transcriptWriter ? shared.artifactPaths?.transcriptPath : undefined,
|
|
186
|
+
skills: shared.resolvedSkillNames,
|
|
187
|
+
skillsWarning: shared.skillsWarning,
|
|
188
|
+
...options.turnBudget ? { turnBudget: initialTurnBudgetState(options.turnBudget) } : {},
|
|
189
|
+
...options.toolBudget ? { toolBudget: initialToolBudgetState(options.toolBudget) } : {}
|
|
190
|
+
};
|
|
191
|
+
const startTime = Date.now();
|
|
192
|
+
if (options.structuredOutput) {
|
|
193
|
+
try {
|
|
194
|
+
if (existsSync(options.structuredOutput.outputPath))
|
|
195
|
+
unlinkSync(options.structuredOutput.outputPath);
|
|
196
|
+
} catch {}
|
|
197
|
+
}
|
|
198
|
+
const controlConfig = options.controlConfig ?? DEFAULT_CONTROL_CONFIG;
|
|
199
|
+
let interruptedByControl = false;
|
|
200
|
+
const allControlEvents = [];
|
|
201
|
+
let pendingControlEvents = [];
|
|
202
|
+
const emittedControlEventKeys = new Set;
|
|
203
|
+
const emitControlEvent = (event) => {
|
|
204
|
+
if (!shouldNotifyControlEvent(controlConfig, event))
|
|
205
|
+
return;
|
|
206
|
+
if (!claimControlNotification(controlConfig, event, emittedControlEventKeys))
|
|
207
|
+
return;
|
|
208
|
+
allControlEvents.push(event);
|
|
209
|
+
pendingControlEvents.push(event);
|
|
210
|
+
options.onControlEvent?.(event);
|
|
211
|
+
};
|
|
212
|
+
const progress = {
|
|
213
|
+
index: options.index ?? 0,
|
|
214
|
+
agent: agent.name,
|
|
215
|
+
status: "running",
|
|
216
|
+
task,
|
|
217
|
+
skills: shared.resolvedSkillNames,
|
|
218
|
+
recentTools: [],
|
|
219
|
+
recentOutput: [...shared.attemptNotes],
|
|
220
|
+
toolCount: 0,
|
|
221
|
+
tokens: 0,
|
|
222
|
+
durationMs: 0,
|
|
223
|
+
lastActivityAt: startTime
|
|
224
|
+
};
|
|
225
|
+
result.progress = progress;
|
|
226
|
+
const attemptTimeout = resolveAttemptTimeout(options);
|
|
227
|
+
if (attemptTimeout?.remainingMs === 0) {
|
|
228
|
+
result.exitCode = 1;
|
|
229
|
+
result.timedOut = true;
|
|
230
|
+
result.error = attemptTimeout.message;
|
|
231
|
+
result.finalOutput = attemptTimeout.message;
|
|
232
|
+
progress.status = "failed";
|
|
233
|
+
progress.error = attemptTimeout.message;
|
|
234
|
+
result.progressSummary = {
|
|
235
|
+
toolCount: progress.toolCount,
|
|
236
|
+
tokens: progress.tokens,
|
|
237
|
+
durationMs: progress.durationMs
|
|
238
|
+
};
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
const spawnEnv = { ...process.env, ...sharedEnv, ...getSubagentDepthEnv(options.maxSubagentDepth) };
|
|
242
|
+
let observedMutationAttempt = false;
|
|
243
|
+
const exitCode = await new Promise((resolve) => {
|
|
244
|
+
const spawnSpec = getPiSpawnCommand(args);
|
|
245
|
+
const proc = spawn(spawnSpec.command, spawnSpec.args, {
|
|
246
|
+
cwd: options.cwd ?? runtimeCwd,
|
|
247
|
+
env: spawnEnv,
|
|
248
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
249
|
+
windowsHide: true
|
|
250
|
+
});
|
|
251
|
+
const jsonlWriter = createJsonlWriter(shared.jsonlPath, proc.stdout);
|
|
252
|
+
let buf = "";
|
|
253
|
+
let processClosed = false;
|
|
254
|
+
let settled = false;
|
|
255
|
+
let detached = false;
|
|
256
|
+
let intercomStarted = false;
|
|
257
|
+
let assistantError;
|
|
258
|
+
let removeAbortListener;
|
|
259
|
+
let removeInterruptListener;
|
|
260
|
+
let activityTimer;
|
|
261
|
+
let timeoutTimer;
|
|
262
|
+
let timeoutTerminationTimer;
|
|
263
|
+
let timeoutHardKillTimer;
|
|
264
|
+
let turnBudgetSoftReached = false;
|
|
265
|
+
let turnBudgetTerminationTimer;
|
|
266
|
+
let turnBudgetHardKillTimer;
|
|
267
|
+
const clearTurnBudgetTimers = () => {
|
|
268
|
+
if (turnBudgetTerminationTimer) {
|
|
269
|
+
clearTimeout(turnBudgetTerminationTimer);
|
|
270
|
+
turnBudgetTerminationTimer = undefined;
|
|
271
|
+
}
|
|
272
|
+
if (turnBudgetHardKillTimer) {
|
|
273
|
+
clearTimeout(turnBudgetHardKillTimer);
|
|
274
|
+
turnBudgetHardKillTimer = undefined;
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
const clearTimeoutTimers = () => {
|
|
278
|
+
if (timeoutTimer) {
|
|
279
|
+
clearTimeout(timeoutTimer);
|
|
280
|
+
timeoutTimer = undefined;
|
|
281
|
+
}
|
|
282
|
+
if (timeoutTerminationTimer) {
|
|
283
|
+
clearTimeout(timeoutTerminationTimer);
|
|
284
|
+
timeoutTerminationTimer = undefined;
|
|
285
|
+
}
|
|
286
|
+
if (timeoutHardKillTimer) {
|
|
287
|
+
clearTimeout(timeoutHardKillTimer);
|
|
288
|
+
timeoutHardKillTimer = undefined;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const detachForIntercom = () => {
|
|
292
|
+
detached = true;
|
|
293
|
+
processClosed = true;
|
|
294
|
+
result.detached = true;
|
|
295
|
+
result.detachedReason = "intercom coordination";
|
|
296
|
+
progress.status = "detached";
|
|
297
|
+
progress.durationMs = Date.now() - startTime;
|
|
298
|
+
result.progressSummary = {
|
|
299
|
+
toolCount: progress.toolCount,
|
|
300
|
+
tokens: progress.tokens,
|
|
301
|
+
durationMs: progress.durationMs
|
|
302
|
+
};
|
|
303
|
+
finish(-2);
|
|
304
|
+
};
|
|
305
|
+
const FINAL_STOP_GRACE_MS = 1000;
|
|
306
|
+
const HARD_KILL_MS = 3000;
|
|
307
|
+
let childExited = false;
|
|
308
|
+
let forcedTerminationSignal = false;
|
|
309
|
+
let cleanTerminalAssistantStopReceived = false;
|
|
310
|
+
let finalDrainTimer;
|
|
311
|
+
let finalHardKillTimer;
|
|
312
|
+
const clearFinalDrainTimers = () => {
|
|
313
|
+
if (finalDrainTimer) {
|
|
314
|
+
clearTimeout(finalDrainTimer);
|
|
315
|
+
finalDrainTimer = undefined;
|
|
316
|
+
}
|
|
317
|
+
if (finalHardKillTimer) {
|
|
318
|
+
clearTimeout(finalHardKillTimer);
|
|
319
|
+
finalHardKillTimer = undefined;
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
const startFinalDrain = () => {
|
|
323
|
+
if (childExited || finalDrainTimer || settled || processClosed || detached)
|
|
324
|
+
return;
|
|
325
|
+
finalDrainTimer = setTimeout(() => {
|
|
326
|
+
if (settled || processClosed || detached)
|
|
327
|
+
return;
|
|
328
|
+
const termSent = trySignalChild(proc, "SIGTERM");
|
|
329
|
+
if (!termSent)
|
|
330
|
+
return;
|
|
331
|
+
forcedTerminationSignal = true;
|
|
332
|
+
if (!cleanTerminalAssistantStopReceived && !assistantError) {
|
|
333
|
+
result.error = result.error ?? `Subagent process did not exit within ${FINAL_STOP_GRACE_MS}ms after its final message. Forcing termination.`;
|
|
334
|
+
}
|
|
335
|
+
finalHardKillTimer = setTimeout(() => {
|
|
336
|
+
if (settled || processClosed || detached)
|
|
337
|
+
return;
|
|
338
|
+
forcedTerminationSignal = trySignalChild(proc, "SIGKILL") || forcedTerminationSignal;
|
|
339
|
+
}, HARD_KILL_MS);
|
|
340
|
+
finalHardKillTimer.unref?.();
|
|
341
|
+
}, FINAL_STOP_GRACE_MS);
|
|
342
|
+
finalDrainTimer.unref?.();
|
|
343
|
+
};
|
|
344
|
+
const unsubscribeIntercomDetach = options.intercomEvents?.on?.(INTERCOM_DETACH_REQUEST_EVENT, (payload) => {
|
|
345
|
+
if (!options.allowIntercomDetach || detached || processClosed || !intercomStarted)
|
|
346
|
+
return;
|
|
347
|
+
if (!payload || typeof payload !== "object")
|
|
348
|
+
return;
|
|
349
|
+
const requestId = payload.requestId;
|
|
350
|
+
if (typeof requestId !== "string" || requestId.length === 0)
|
|
351
|
+
return;
|
|
352
|
+
options.intercomEvents?.emit(INTERCOM_DETACH_RESPONSE_EVENT, { requestId, accepted: true });
|
|
353
|
+
detachForIntercom();
|
|
354
|
+
});
|
|
355
|
+
const finish = (code) => {
|
|
356
|
+
if (settled)
|
|
357
|
+
return;
|
|
358
|
+
settled = true;
|
|
359
|
+
clearFinalDrainTimers();
|
|
360
|
+
clearStdioGuard();
|
|
361
|
+
clearTimeoutTimers();
|
|
362
|
+
clearTurnBudgetTimers();
|
|
363
|
+
if (activityTimer) {
|
|
364
|
+
clearInterval(activityTimer);
|
|
365
|
+
activityTimer = undefined;
|
|
366
|
+
}
|
|
367
|
+
unsubscribeIntercomDetach?.();
|
|
368
|
+
removeAbortListener?.();
|
|
369
|
+
removeInterruptListener?.();
|
|
370
|
+
resolve(code);
|
|
371
|
+
};
|
|
372
|
+
const drainPendingControlEvents = () => {
|
|
373
|
+
if (pendingControlEvents.length === 0)
|
|
374
|
+
return;
|
|
375
|
+
const events = pendingControlEvents;
|
|
376
|
+
pendingControlEvents = [];
|
|
377
|
+
return events;
|
|
378
|
+
};
|
|
379
|
+
let activeLongRunningNotified = false;
|
|
380
|
+
let pendingToolResult;
|
|
381
|
+
const mutatingFailures = createMutatingFailureState();
|
|
382
|
+
const mutatingFailureWindowMs = 5 * 60000;
|
|
383
|
+
const currentToolDurationMs = (now) => progress.currentToolStartedAt ? Math.max(0, now - progress.currentToolStartedAt) : undefined;
|
|
384
|
+
const emitNeedsAttention = (now, input = {}) => {
|
|
385
|
+
if (!controlConfig.enabled)
|
|
386
|
+
return false;
|
|
387
|
+
const previous = progress.activityState;
|
|
388
|
+
progress.activityState = "needs_attention";
|
|
389
|
+
const event = buildControlEvent({
|
|
390
|
+
type: "needs_attention",
|
|
391
|
+
from: previous,
|
|
392
|
+
to: "needs_attention",
|
|
393
|
+
runId: options.runId,
|
|
394
|
+
agent: agent.name,
|
|
395
|
+
index: options.index,
|
|
396
|
+
ts: now,
|
|
397
|
+
lastActivityAt: progress.lastActivityAt,
|
|
398
|
+
message: input.message,
|
|
399
|
+
reason: input.reason ?? "idle",
|
|
400
|
+
turns: result.usage.turns,
|
|
401
|
+
tokens: progress.tokens,
|
|
402
|
+
toolCount: progress.toolCount,
|
|
403
|
+
currentTool: input.currentTool ?? progress.currentTool,
|
|
404
|
+
currentToolDurationMs: input.currentToolDurationMs ?? currentToolDurationMs(now),
|
|
405
|
+
currentPath: input.currentPath ?? progress.currentPath,
|
|
406
|
+
recentFailureSummary: input.recentFailureSummary
|
|
407
|
+
});
|
|
408
|
+
emitControlEvent(event);
|
|
409
|
+
return previous !== "needs_attention";
|
|
410
|
+
};
|
|
411
|
+
const emitActiveLongRunning = (now, reason) => {
|
|
412
|
+
if (!controlConfig.enabled || activeLongRunningNotified || progress.activityState === "needs_attention")
|
|
413
|
+
return false;
|
|
414
|
+
activeLongRunningNotified = true;
|
|
415
|
+
const previous = progress.activityState;
|
|
416
|
+
progress.activityState = "active_long_running";
|
|
417
|
+
emitControlEvent(buildControlEvent({
|
|
418
|
+
type: "active_long_running",
|
|
419
|
+
from: previous,
|
|
420
|
+
to: "active_long_running",
|
|
421
|
+
runId: options.runId,
|
|
422
|
+
agent: agent.name,
|
|
423
|
+
index: options.index,
|
|
424
|
+
ts: now,
|
|
425
|
+
message: `${agent.name} is still active but long-running`,
|
|
426
|
+
reason,
|
|
427
|
+
turns: result.usage.turns,
|
|
428
|
+
tokens: progress.tokens,
|
|
429
|
+
toolCount: progress.toolCount,
|
|
430
|
+
currentTool: progress.currentTool,
|
|
431
|
+
currentToolDurationMs: currentToolDurationMs(now),
|
|
432
|
+
currentPath: progress.currentPath,
|
|
433
|
+
elapsedMs: now - startTime
|
|
434
|
+
}));
|
|
435
|
+
return true;
|
|
436
|
+
};
|
|
437
|
+
const requestTurnBudgetAbort = (turnCount) => {
|
|
438
|
+
const budget = options.turnBudget;
|
|
439
|
+
if (!budget || result.timedOut || result.turnBudgetExceeded || interruptedByControl || processClosed || settled || detached)
|
|
440
|
+
return;
|
|
441
|
+
const message = turnBudgetExceededMessage(budget, turnCount);
|
|
442
|
+
result.turnBudgetExceeded = true;
|
|
443
|
+
result.wrapUpRequested = true;
|
|
444
|
+
result.turnBudget = turnBudgetState(budget, turnCount, true);
|
|
445
|
+
result.error = message;
|
|
446
|
+
result.finalOutput = message;
|
|
447
|
+
progress.status = "failed";
|
|
448
|
+
progress.error = message;
|
|
449
|
+
progress.durationMs = Date.now() - startTime;
|
|
450
|
+
fireUpdate();
|
|
451
|
+
trySignalChild(proc, "SIGINT");
|
|
452
|
+
turnBudgetTerminationTimer = setTimeout(() => {
|
|
453
|
+
if (processClosed || settled || detached || result.timedOut)
|
|
454
|
+
return;
|
|
455
|
+
trySignalChild(proc, "SIGTERM");
|
|
456
|
+
}, 1000);
|
|
457
|
+
turnBudgetTerminationTimer.unref?.();
|
|
458
|
+
turnBudgetHardKillTimer = setTimeout(() => {
|
|
459
|
+
if (processClosed || settled || detached || result.timedOut)
|
|
460
|
+
return;
|
|
461
|
+
trySignalChild(proc, "SIGKILL");
|
|
462
|
+
}, 4000);
|
|
463
|
+
turnBudgetHardKillTimer.unref?.();
|
|
464
|
+
};
|
|
465
|
+
const updateTurnBudget = (turnCount, terminalAssistantStop) => {
|
|
466
|
+
const budget = options.turnBudget;
|
|
467
|
+
if (!budget || result.timedOut || result.turnBudgetExceeded)
|
|
468
|
+
return;
|
|
469
|
+
if (turnCount < budget.maxTurns) {
|
|
470
|
+
result.turnBudget = { ...budget, outcome: "within-budget", turnCount };
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (!turnBudgetSoftReached) {
|
|
474
|
+
turnBudgetSoftReached = true;
|
|
475
|
+
result.wrapUpRequested = true;
|
|
476
|
+
appendRecentOutput(progress, [turnBudgetSoftNote(budget, turnCount)]);
|
|
477
|
+
}
|
|
478
|
+
result.turnBudget = turnBudgetState(budget, turnCount, false);
|
|
479
|
+
if (shouldAbortForTurnBudget(budget, turnCount, terminalAssistantStop)) {
|
|
480
|
+
requestTurnBudgetAbort(turnCount);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const updateActivityState = (now) => {
|
|
484
|
+
if (!controlConfig.enabled)
|
|
485
|
+
return false;
|
|
486
|
+
const idleState = deriveActivityState({
|
|
487
|
+
config: controlConfig,
|
|
488
|
+
startedAt: startTime,
|
|
489
|
+
lastActivityAt: progress.lastActivityAt,
|
|
490
|
+
now
|
|
491
|
+
});
|
|
492
|
+
if (idleState === "needs_attention") {
|
|
493
|
+
return progress.activityState === "needs_attention" ? false : emitNeedsAttention(now);
|
|
494
|
+
}
|
|
495
|
+
const activeReason = nextLongRunningTrigger(controlConfig, {
|
|
496
|
+
startedAt: startTime,
|
|
497
|
+
now,
|
|
498
|
+
turns: result.usage.turns,
|
|
499
|
+
tokens: progress.tokens
|
|
500
|
+
});
|
|
501
|
+
return activeReason ? emitActiveLongRunning(now, activeReason) : false;
|
|
502
|
+
};
|
|
503
|
+
const emitUpdateSnapshot = (text) => {
|
|
504
|
+
if (!options.onUpdate || processClosed)
|
|
505
|
+
return;
|
|
506
|
+
const progressSnapshot = snapshotProgress(progress);
|
|
507
|
+
const resultSnapshot = snapshotResult(result, progressSnapshot);
|
|
508
|
+
const controlEvents = drainPendingControlEvents();
|
|
509
|
+
options.onUpdate({
|
|
510
|
+
content: [{ type: "text", text }],
|
|
511
|
+
details: {
|
|
512
|
+
mode: "single",
|
|
513
|
+
results: [resultSnapshot],
|
|
514
|
+
progress: [progressSnapshot],
|
|
515
|
+
controlEvents
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
};
|
|
519
|
+
const fireUpdate = () => {
|
|
520
|
+
if (!options.onUpdate || processClosed)
|
|
521
|
+
return;
|
|
522
|
+
progress.durationMs = Date.now() - startTime;
|
|
523
|
+
const output = (result.timedOut || result.turnBudgetExceeded) && result.finalOutput ? result.finalOutput : getFinalOutput(result.messages);
|
|
524
|
+
emitUpdateSnapshot(output || "(running...)");
|
|
525
|
+
};
|
|
526
|
+
const processLine = (line) => {
|
|
527
|
+
if (!line.trim())
|
|
528
|
+
return;
|
|
529
|
+
jsonlWriter.writeLine(line);
|
|
530
|
+
let evt;
|
|
531
|
+
try {
|
|
532
|
+
evt = JSON.parse(line);
|
|
533
|
+
} catch {
|
|
534
|
+
shared.transcriptWriter?.writeStdoutLine(line);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
shared.transcriptWriter?.writeChildEvent(evt);
|
|
538
|
+
const now = Date.now();
|
|
539
|
+
progress.durationMs = now - startTime;
|
|
540
|
+
progress.lastActivityAt = now;
|
|
541
|
+
updateActivityState(now);
|
|
542
|
+
if (evt.type === "tool_execution_start") {
|
|
543
|
+
const toolArgs = evt.args && typeof evt.args === "object" && !Array.isArray(evt.args) ? evt.args : {};
|
|
544
|
+
let shouldDetachForBlockingIntercom = false;
|
|
545
|
+
if (options.allowIntercomDetach && (evt.toolName === "intercom" || evt.toolName === "contact_supervisor")) {
|
|
546
|
+
intercomStarted = true;
|
|
547
|
+
shouldDetachForBlockingIntercom = evt.toolName === "intercom" && toolArgs.action === "ask" || evt.toolName === "contact_supervisor" && (toolArgs.reason === "need_decision" || toolArgs.reason === "interview_request");
|
|
548
|
+
}
|
|
549
|
+
progress.toolCount++;
|
|
550
|
+
if (options.toolBudget) {
|
|
551
|
+
result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount);
|
|
552
|
+
}
|
|
553
|
+
progress.currentTool = evt.toolName;
|
|
554
|
+
progress.currentToolArgs = extractToolArgsPreview(toolArgs);
|
|
555
|
+
progress.currentToolStartedAt = now;
|
|
556
|
+
progress.currentPath = resolveCurrentPath(evt.toolName, toolArgs);
|
|
557
|
+
const mutates = isMutatingTool(evt.toolName, toolArgs);
|
|
558
|
+
observedMutationAttempt = observedMutationAttempt || mutates;
|
|
559
|
+
pendingToolResult = { tool: evt.toolName ?? "tool", path: progress.currentPath, mutates, startedAt: now };
|
|
560
|
+
fireUpdate();
|
|
561
|
+
if (shouldDetachForBlockingIntercom && !detached && !processClosed) {
|
|
562
|
+
detachForIntercom();
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
if (evt.type === "tool_execution_end") {
|
|
566
|
+
if (progress.currentTool) {
|
|
567
|
+
progress.recentTools.push({
|
|
568
|
+
tool: progress.currentTool,
|
|
569
|
+
args: progress.currentToolArgs || "",
|
|
570
|
+
endMs: now
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
progress.currentTool = undefined;
|
|
574
|
+
progress.currentToolArgs = undefined;
|
|
575
|
+
progress.currentToolStartedAt = undefined;
|
|
576
|
+
progress.currentPath = undefined;
|
|
577
|
+
fireUpdate();
|
|
578
|
+
}
|
|
579
|
+
if (evt.type === "message_end" && evt.message) {
|
|
580
|
+
result.messages.push(evt.message);
|
|
581
|
+
if (evt.message.role === "assistant") {
|
|
582
|
+
result.usage.turns++;
|
|
583
|
+
progress.turnCount = result.usage.turns;
|
|
584
|
+
const stopReason = evt.message.stopReason;
|
|
585
|
+
const hasToolCall = Array.isArray(evt.message.content) && evt.message.content.some((part) => part.type === "toolCall");
|
|
586
|
+
const terminalAssistantStop = stopReason === "stop" && !hasToolCall;
|
|
587
|
+
updateTurnBudget(result.usage.turns, terminalAssistantStop);
|
|
588
|
+
const u = evt.message.usage;
|
|
589
|
+
if (u) {
|
|
590
|
+
result.usage.input += u.input || 0;
|
|
591
|
+
result.usage.output += u.output || 0;
|
|
592
|
+
result.usage.cacheRead += u.cacheRead || 0;
|
|
593
|
+
result.usage.cacheWrite += u.cacheWrite || 0;
|
|
594
|
+
result.usage.cost += u.cost?.total || 0;
|
|
595
|
+
progress.tokens = result.usage.input + result.usage.output;
|
|
596
|
+
}
|
|
597
|
+
if (!result.model && evt.message.model)
|
|
598
|
+
result.model = evt.message.model;
|
|
599
|
+
if (evt.message.errorMessage)
|
|
600
|
+
assistantError = evt.message.errorMessage;
|
|
601
|
+
const assistantText = extractTextFromContent(evt.message.content);
|
|
602
|
+
appendRecentOutput(progress, assistantText.split(`
|
|
603
|
+
`).slice(-10));
|
|
604
|
+
if (terminalAssistantStop) {
|
|
605
|
+
if (!evt.message.errorMessage && assistantText.trim())
|
|
606
|
+
assistantError = undefined;
|
|
607
|
+
cleanTerminalAssistantStopReceived ||= !evt.message.errorMessage;
|
|
608
|
+
startFinalDrain();
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
updateActivityState(now);
|
|
612
|
+
fireUpdate();
|
|
613
|
+
}
|
|
614
|
+
if (evt.type === "tool_result_end" && evt.message) {
|
|
615
|
+
result.messages.push(evt.message);
|
|
616
|
+
const resultText = extractTextFromContent(evt.message.content);
|
|
617
|
+
if (options.toolBudget && pendingToolResult && resultText.includes("Tool budget hard limit reached")) {
|
|
618
|
+
result.toolBudgetBlocked = true;
|
|
619
|
+
result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount, pendingToolResult.tool);
|
|
620
|
+
}
|
|
621
|
+
appendRecentOutput(progress, resultText.split(`
|
|
622
|
+
`).slice(-10));
|
|
623
|
+
const toolSnapshot = pendingToolResult;
|
|
624
|
+
pendingToolResult = undefined;
|
|
625
|
+
if (toolSnapshot?.mutates && didMutatingToolFail(resultText)) {
|
|
626
|
+
recordMutatingFailure(mutatingFailures, {
|
|
627
|
+
tool: toolSnapshot.tool,
|
|
628
|
+
path: toolSnapshot.path,
|
|
629
|
+
error: resultText.split(`
|
|
630
|
+
`).find((line) => line.trim())?.trim().slice(0, 180) ?? "mutating tool failed",
|
|
631
|
+
ts: now
|
|
632
|
+
}, mutatingFailureWindowMs);
|
|
633
|
+
if (shouldEscalateMutatingFailures(mutatingFailures, controlConfig.failedToolAttemptsBeforeAttention)) {
|
|
634
|
+
emitNeedsAttention(now, {
|
|
635
|
+
message: `${agent.name} needs attention after repeated mutating tool failures`,
|
|
636
|
+
reason: "tool_failures",
|
|
637
|
+
currentTool: toolSnapshot.tool,
|
|
638
|
+
currentPath: toolSnapshot.path,
|
|
639
|
+
currentToolDurationMs: toolSnapshot.startedAt ? Math.max(0, now - toolSnapshot.startedAt) : undefined,
|
|
640
|
+
recentFailureSummary: summarizeRecentMutatingFailures(mutatingFailures)
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
} else if (toolSnapshot?.mutates) {
|
|
644
|
+
resetMutatingFailureState(mutatingFailures);
|
|
645
|
+
}
|
|
646
|
+
fireUpdate();
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
if (controlConfig.enabled) {
|
|
650
|
+
activityTimer = setInterval(() => {
|
|
651
|
+
if (processClosed || settled || detached)
|
|
652
|
+
return;
|
|
653
|
+
const now = Date.now();
|
|
654
|
+
if (updateActivityState(now)) {
|
|
655
|
+
progress.durationMs = now - startTime;
|
|
656
|
+
fireUpdate();
|
|
657
|
+
}
|
|
658
|
+
}, 1000);
|
|
659
|
+
activityTimer.unref?.();
|
|
660
|
+
}
|
|
661
|
+
if (attemptTimeout) {
|
|
662
|
+
timeoutTimer = setTimeout(() => {
|
|
663
|
+
if (processClosed || settled || detached || interruptedByControl)
|
|
664
|
+
return;
|
|
665
|
+
result.timedOut = true;
|
|
666
|
+
result.error = attemptTimeout.message;
|
|
667
|
+
result.finalOutput = attemptTimeout.message;
|
|
668
|
+
progress.status = "failed";
|
|
669
|
+
progress.error = attemptTimeout.message;
|
|
670
|
+
progress.durationMs = Date.now() - startTime;
|
|
671
|
+
fireUpdate();
|
|
672
|
+
trySignalChild(proc, "SIGINT");
|
|
673
|
+
timeoutTerminationTimer = setTimeout(() => {
|
|
674
|
+
if (processClosed || settled || detached)
|
|
675
|
+
return;
|
|
676
|
+
trySignalChild(proc, "SIGTERM");
|
|
677
|
+
}, 1000);
|
|
678
|
+
timeoutTerminationTimer.unref?.();
|
|
679
|
+
timeoutHardKillTimer = setTimeout(() => {
|
|
680
|
+
if (processClosed || settled || detached)
|
|
681
|
+
return;
|
|
682
|
+
trySignalChild(proc, "SIGKILL");
|
|
683
|
+
}, 4000);
|
|
684
|
+
timeoutHardKillTimer.unref?.();
|
|
685
|
+
}, attemptTimeout.remainingMs);
|
|
686
|
+
timeoutTimer.unref?.();
|
|
687
|
+
}
|
|
688
|
+
let stderrBuf = "";
|
|
689
|
+
const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
|
|
690
|
+
proc.stdout.on("data", (d) => {
|
|
691
|
+
buf += d.toString();
|
|
692
|
+
const lines = buf.split(`
|
|
693
|
+
`);
|
|
694
|
+
buf = lines.pop() || "";
|
|
695
|
+
lines.forEach(processLine);
|
|
696
|
+
});
|
|
697
|
+
proc.stderr.on("data", (d) => {
|
|
698
|
+
stderrBuf += d.toString();
|
|
699
|
+
});
|
|
700
|
+
proc.on("exit", () => {
|
|
701
|
+
childExited = true;
|
|
702
|
+
clearFinalDrainTimers();
|
|
703
|
+
});
|
|
704
|
+
proc.on("close", (code, signal) => {
|
|
705
|
+
clearFinalDrainTimers();
|
|
706
|
+
clearStdioGuard();
|
|
707
|
+
jsonlWriter.close().catch(() => {});
|
|
708
|
+
cleanupTempDir(tempDir);
|
|
709
|
+
if (buf.trim())
|
|
710
|
+
processLine(buf);
|
|
711
|
+
if (stderrBuf.trim())
|
|
712
|
+
shared.transcriptWriter?.writeStderrText(stderrBuf);
|
|
713
|
+
if (!result.error && assistantError)
|
|
714
|
+
result.error = assistantError;
|
|
715
|
+
const forcedDrainAfterFinalSuccess = forcedTerminationSignal && cleanTerminalAssistantStopReceived && !result.error;
|
|
716
|
+
if (code !== 0 && stderrBuf.trim() && !result.error && !forcedDrainAfterFinalSuccess) {
|
|
717
|
+
result.error = stderrBuf.trim();
|
|
718
|
+
}
|
|
719
|
+
const finalCode = forcedDrainAfterFinalSuccess ? 0 : forcedTerminationSignal || signal ? code ?? 1 : code ?? 0;
|
|
720
|
+
if (detached) {
|
|
721
|
+
result.exitCode = result.error && finalCode === 0 ? 1 : finalCode;
|
|
722
|
+
progress.status = result.exitCode === 0 ? "completed" : "failed";
|
|
723
|
+
progress.durationMs = Date.now() - startTime;
|
|
724
|
+
if (result.error)
|
|
725
|
+
progress.error = result.error;
|
|
726
|
+
result.progressSummary = {
|
|
727
|
+
toolCount: progress.toolCount,
|
|
728
|
+
tokens: progress.tokens,
|
|
729
|
+
durationMs: progress.durationMs
|
|
730
|
+
};
|
|
731
|
+
const finalOutput = getFinalOutput(result.messages);
|
|
732
|
+
result.finalOutput = finalOutput.trim() || result.error || result.finalOutput || "Detached child exited without final output.";
|
|
733
|
+
if (result.artifactPaths && options.artifactConfig?.enabled !== false && options.artifactConfig?.includeOutput !== false) {
|
|
734
|
+
try {
|
|
735
|
+
writeArtifact(result.artifactPaths.outputPath, result.finalOutput);
|
|
736
|
+
} catch {}
|
|
737
|
+
}
|
|
738
|
+
options.onDetachedExit?.(snapshotResult(result, snapshotProgress(progress)));
|
|
739
|
+
finish(-2);
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
processClosed = true;
|
|
743
|
+
finish(finalCode);
|
|
744
|
+
});
|
|
745
|
+
proc.on("error", (error) => {
|
|
746
|
+
clearFinalDrainTimers();
|
|
747
|
+
clearStdioGuard();
|
|
748
|
+
jsonlWriter.close().catch(() => {});
|
|
749
|
+
cleanupTempDir(tempDir);
|
|
750
|
+
if (stderrBuf.trim())
|
|
751
|
+
shared.transcriptWriter?.writeStderrText(stderrBuf);
|
|
752
|
+
if (!result.error) {
|
|
753
|
+
result.error = error instanceof Error ? error.message : String(error);
|
|
754
|
+
}
|
|
755
|
+
finish(1);
|
|
756
|
+
});
|
|
757
|
+
if (options.signal) {
|
|
758
|
+
const kill = () => {
|
|
759
|
+
if (processClosed || detached)
|
|
760
|
+
return;
|
|
761
|
+
if (options.allowIntercomDetach && intercomStarted && !detached) {
|
|
762
|
+
detachForIntercom();
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
proc.kill("SIGTERM");
|
|
766
|
+
setTimeout(() => !proc.killed && proc.kill("SIGKILL"), 3000);
|
|
767
|
+
};
|
|
768
|
+
if (options.signal.aborted)
|
|
769
|
+
kill();
|
|
770
|
+
else {
|
|
771
|
+
options.signal.addEventListener("abort", kill, { once: true });
|
|
772
|
+
removeAbortListener = () => options.signal?.removeEventListener("abort", kill);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
if (options.interruptSignal) {
|
|
776
|
+
const interrupt = () => {
|
|
777
|
+
if (processClosed || detached || settled)
|
|
778
|
+
return;
|
|
779
|
+
if (result.timedOut)
|
|
780
|
+
return;
|
|
781
|
+
interruptedByControl = true;
|
|
782
|
+
clearTimeoutTimers();
|
|
783
|
+
progress.status = "running";
|
|
784
|
+
progress.durationMs = Date.now() - startTime;
|
|
785
|
+
result.interrupted = true;
|
|
786
|
+
result.finalOutput = "Interrupted. Waiting for explicit next action.";
|
|
787
|
+
progress.activityState = undefined;
|
|
788
|
+
fireUpdate();
|
|
789
|
+
trySignalChild(proc, "SIGINT");
|
|
790
|
+
setTimeout(() => {
|
|
791
|
+
if (settled || processClosed || detached)
|
|
792
|
+
return;
|
|
793
|
+
trySignalChild(proc, "SIGTERM");
|
|
794
|
+
}, 1000).unref?.();
|
|
795
|
+
};
|
|
796
|
+
if (options.interruptSignal.aborted)
|
|
797
|
+
interrupt();
|
|
798
|
+
else {
|
|
799
|
+
options.interruptSignal.addEventListener("abort", interrupt, { once: true });
|
|
800
|
+
removeInterruptListener = () => options.interruptSignal?.removeEventListener("abort", interrupt);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
result.exitCode = exitCode;
|
|
805
|
+
if (interruptedByControl) {
|
|
806
|
+
result.exitCode = 0;
|
|
807
|
+
result.interrupted = true;
|
|
808
|
+
result.error = undefined;
|
|
809
|
+
result.finalOutput = result.finalOutput || "Interrupted. Waiting for explicit next action.";
|
|
810
|
+
result.controlEvents = allControlEvents.length ? allControlEvents : undefined;
|
|
811
|
+
progress.activityState = undefined;
|
|
812
|
+
progress.durationMs = Date.now() - startTime;
|
|
813
|
+
result.progressSummary = {
|
|
814
|
+
toolCount: progress.toolCount,
|
|
815
|
+
tokens: progress.tokens,
|
|
816
|
+
durationMs: progress.durationMs
|
|
817
|
+
};
|
|
818
|
+
return result;
|
|
819
|
+
}
|
|
820
|
+
if (result.detached) {
|
|
821
|
+
result.exitCode = 0;
|
|
822
|
+
result.finalOutput = "Detached for intercom coordination.";
|
|
823
|
+
return result;
|
|
824
|
+
}
|
|
825
|
+
if (result.error && result.exitCode === 0) {
|
|
826
|
+
result.exitCode = 1;
|
|
827
|
+
}
|
|
828
|
+
if (result.exitCode === 0 && !result.error) {
|
|
829
|
+
const errInfo = detectSubagentError(result.messages);
|
|
830
|
+
if (errInfo.hasError) {
|
|
831
|
+
result.exitCode = errInfo.exitCode ?? 1;
|
|
832
|
+
result.error = errInfo.details ? `${errInfo.errorType} failed (exit ${errInfo.exitCode}): ${errInfo.details}` : `${errInfo.errorType} failed with exit code ${errInfo.exitCode}`;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (result.exitCode === 0 && !result.error) {
|
|
836
|
+
const finalText = getFinalOutput(result.messages);
|
|
837
|
+
const missingStructuredOutput = options.structuredOutput ? !existsSync(options.structuredOutput.outputPath) : false;
|
|
838
|
+
if (!finalText?.trim() && (!options.structuredOutput || missingStructuredOutput)) {
|
|
839
|
+
result.exitCode = 1;
|
|
840
|
+
result.error = "Subagent produced no output (possible model cold-start or empty response).";
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
if (options.structuredOutput && result.exitCode === 0 && !result.error) {
|
|
844
|
+
const structured = readStructuredOutput({
|
|
845
|
+
schema: options.structuredOutput.schema,
|
|
846
|
+
schemaPath: options.structuredOutput.schemaPath,
|
|
847
|
+
outputPath: options.structuredOutput.outputPath
|
|
848
|
+
});
|
|
849
|
+
result.structuredOutputSchemaPath = options.structuredOutput.schemaPath;
|
|
850
|
+
result.structuredOutputPath = options.structuredOutput.outputPath;
|
|
851
|
+
if (structured.error) {
|
|
852
|
+
result.exitCode = 1;
|
|
853
|
+
result.error = structured.error;
|
|
854
|
+
} else {
|
|
855
|
+
result.structuredOutput = structured.value;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
progress.status = result.exitCode === 0 ? "completed" : "failed";
|
|
859
|
+
progress.durationMs = Date.now() - startTime;
|
|
860
|
+
if (result.error) {
|
|
861
|
+
progress.error = result.error;
|
|
862
|
+
if (progress.currentTool) {
|
|
863
|
+
progress.failedTool = progress.currentTool;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
result.progressSummary = {
|
|
867
|
+
toolCount: progress.toolCount,
|
|
868
|
+
tokens: progress.tokens,
|
|
869
|
+
durationMs: progress.durationMs
|
|
870
|
+
};
|
|
871
|
+
const acceptanceOutput = getFinalOutput(result.messages);
|
|
872
|
+
let fullOutput = stripAcceptanceReport(acceptanceOutput);
|
|
873
|
+
if (result.timedOut) {
|
|
874
|
+
const timeoutMessage = formatTimeoutMessage(options.timeoutMs ?? 0);
|
|
875
|
+
fullOutput = fullOutput.trim() ? `${timeoutMessage}
|
|
38
876
|
|
|
39
877
|
Partial output before timeout:
|
|
40
|
-
${
|
|
878
|
+
${fullOutput}` : timeoutMessage;
|
|
879
|
+
} else if (result.turnBudgetExceeded && result.turnBudget) {
|
|
880
|
+
fullOutput = formatTurnBudgetOutput(turnBudgetExceededMessage(result.turnBudget, result.turnBudget.turnCount), fullOutput);
|
|
881
|
+
} else if (result.wrapUpRequested && result.turnBudget?.outcome === "wrap-up-requested") {
|
|
882
|
+
const note = turnBudgetSoftNote(result.turnBudget, result.turnBudget.wrapUpRequestedAtTurn ?? result.turnBudget.turnCount);
|
|
883
|
+
fullOutput = fullOutput.trim() ? `${note}
|
|
41
884
|
|
|
42
|
-
${
|
|
43
|
-
|
|
44
|
-
|
|
885
|
+
${fullOutput}` : note;
|
|
886
|
+
}
|
|
887
|
+
const completionGuard = result.exitCode === 0 && !result.error && agent.completionGuard !== false ? evaluateCompletionMutationGuard({
|
|
888
|
+
agent: agent.name,
|
|
889
|
+
task: shared.originalTask ?? task,
|
|
890
|
+
messages: result.messages,
|
|
891
|
+
tools: agent.tools,
|
|
892
|
+
mcpDirectTools: agent.mcpDirectTools
|
|
893
|
+
}) : undefined;
|
|
894
|
+
if (completionGuard?.triggered && !observedMutationAttempt) {
|
|
895
|
+
result.exitCode = 1;
|
|
896
|
+
result.error = `Subagent completed without making edits for an implementation task.
|
|
897
|
+
It appears to have returned planning or scratchpad output instead of applying changes.`;
|
|
898
|
+
progress.status = "failed";
|
|
899
|
+
progress.error = result.error;
|
|
900
|
+
emitControlEvent(buildControlEvent({
|
|
901
|
+
from: progress.activityState,
|
|
902
|
+
to: "needs_attention",
|
|
903
|
+
runId: options.runId ?? agent.name,
|
|
904
|
+
agent: agent.name,
|
|
905
|
+
index: options.index,
|
|
906
|
+
ts: Date.now(),
|
|
907
|
+
message: `${agent.name} completed without making edits for an implementation task`,
|
|
908
|
+
reason: "completion_guard"
|
|
909
|
+
}));
|
|
910
|
+
}
|
|
911
|
+
if (options.outputPath && result.exitCode === 0) {
|
|
912
|
+
const resolvedOutput = resolveSingleOutput(options.outputPath, fullOutput, shared.outputSnapshot);
|
|
913
|
+
fullOutput = stripAcceptanceReport(resolvedOutput.fullOutput);
|
|
914
|
+
result.savedOutputPath = resolvedOutput.savedPath;
|
|
915
|
+
result.outputSaveError = resolvedOutput.saveError;
|
|
916
|
+
if (resolvedOutput.savedPath) {
|
|
917
|
+
result.outputReference = formatSavedOutputReference(resolvedOutput.savedPath, fullOutput);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
artifactOutputByResult.set(result, fullOutput);
|
|
921
|
+
acceptanceOutputByResult.set(result, acceptanceOutput);
|
|
922
|
+
result.outputMode = options.outputMode ?? "inline";
|
|
923
|
+
result.finalOutput = options.outputMode === "file-only" && result.savedOutputPath && result.outputReference ? result.outputReference.message : fullOutput;
|
|
924
|
+
result.controlEvents = allControlEvents.length ? allControlEvents : undefined;
|
|
925
|
+
if (options.onUpdate) {
|
|
926
|
+
const finalText = result.finalOutput || result.error || "(no output)";
|
|
927
|
+
const progressSnapshot = snapshotProgress(progress);
|
|
928
|
+
const resultSnapshot = snapshotResult(result, progressSnapshot);
|
|
929
|
+
options.onUpdate({
|
|
930
|
+
content: [{ type: "text", text: finalText }],
|
|
931
|
+
details: {
|
|
932
|
+
mode: "single",
|
|
933
|
+
results: [resultSnapshot],
|
|
934
|
+
progress: [progressSnapshot],
|
|
935
|
+
controlEvents: allControlEvents.length ? allControlEvents : undefined
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
return result;
|
|
940
|
+
}
|
|
941
|
+
export async function runSync(runtimeCwd, agents, agentName, task, options) {
|
|
942
|
+
const agent = agents.find((a) => a.name === agentName);
|
|
943
|
+
if (!agent) {
|
|
944
|
+
return {
|
|
945
|
+
agent: agentName,
|
|
946
|
+
task,
|
|
947
|
+
exitCode: 1,
|
|
948
|
+
messages: [],
|
|
949
|
+
usage: emptyUsage(),
|
|
950
|
+
error: `Unknown agent: ${agentName}`
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
const outputModeValidationError = validateFileOnlyOutputMode(options.outputMode, options.outputPath, `Single run (${agentName})`);
|
|
954
|
+
if (outputModeValidationError) {
|
|
955
|
+
return {
|
|
956
|
+
agent: agentName,
|
|
957
|
+
task,
|
|
958
|
+
exitCode: 1,
|
|
959
|
+
messages: [],
|
|
960
|
+
usage: emptyUsage(),
|
|
961
|
+
outputMode: options.outputMode,
|
|
962
|
+
error: outputModeValidationError
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
const shareEnabled = options.share === true;
|
|
966
|
+
const effectiveAcceptance = resolveEffectiveAcceptance({
|
|
967
|
+
explicit: options.acceptance,
|
|
968
|
+
agentName,
|
|
969
|
+
task,
|
|
970
|
+
mode: options.acceptanceContext?.mode ?? "single",
|
|
971
|
+
async: options.acceptanceContext?.async,
|
|
972
|
+
dynamic: options.acceptanceContext?.dynamic,
|
|
973
|
+
dynamicGroup: options.acceptanceContext?.dynamicGroup
|
|
974
|
+
});
|
|
975
|
+
const acceptancePrompt = formatAcceptancePrompt(effectiveAcceptance);
|
|
976
|
+
const taskWithAcceptance = acceptancePrompt ? `${task}
|
|
977
|
+
${acceptancePrompt}` : task;
|
|
978
|
+
const sessionEnabled = Boolean(options.sessionFile || options.sessionDir) || shareEnabled;
|
|
979
|
+
const skillNames = options.skills ?? agent.skills ?? [];
|
|
980
|
+
const skillCwd = options.cwd ?? runtimeCwd;
|
|
981
|
+
const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(skillNames, skillCwd, runtimeCwd);
|
|
982
|
+
if (skillNames.some((skill) => skill.trim() === "dm-subagents") && missingSkills.includes("dm-subagents")) {
|
|
983
|
+
return {
|
|
984
|
+
agent: agentName,
|
|
985
|
+
task,
|
|
986
|
+
exitCode: 1,
|
|
987
|
+
messages: [],
|
|
988
|
+
usage: emptyUsage(),
|
|
989
|
+
error: "Skills not found: dm-subagents"
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
let systemPrompt = agent.systemPrompt?.trim() || "";
|
|
993
|
+
if (resolvedSkills.length > 0) {
|
|
994
|
+
const skillInjection = buildSkillInjection(resolvedSkills);
|
|
995
|
+
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
45
996
|
|
|
46
|
-
${
|
|
997
|
+
${skillInjection}` : skillInjection;
|
|
998
|
+
}
|
|
999
|
+
const memoryInjection = buildAgentMemoryInjection(agent, skillCwd);
|
|
1000
|
+
if (memoryInjection) {
|
|
1001
|
+
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
47
1002
|
|
|
48
|
-
${
|
|
1003
|
+
${memoryInjection}` : memoryInjection;
|
|
1004
|
+
}
|
|
1005
|
+
systemPrompt = injectOutputPathSystemPrompt(systemPrompt, options.outputPath);
|
|
1006
|
+
const candidates = buildModelCandidates(options.modelOverride ?? agent.model, agent.fallbackModels, options.availableModels, options.preferredModelProvider, { scope: options.modelScope });
|
|
1007
|
+
const attemptedModels = [];
|
|
1008
|
+
const modelAttempts = [];
|
|
1009
|
+
const aggregateUsage = emptyUsage();
|
|
1010
|
+
const attemptNotes = [];
|
|
1011
|
+
let totalToolCount = 0;
|
|
1012
|
+
let totalDurationMs = 0;
|
|
1013
|
+
let artifactPathsResult;
|
|
1014
|
+
let jsonlPath;
|
|
1015
|
+
let transcriptWriter;
|
|
1016
|
+
if (options.artifactsDir && options.artifactConfig?.enabled !== false) {
|
|
1017
|
+
artifactPathsResult = getArtifactPaths(options.artifactsDir, options.runId, agentName, options.index);
|
|
1018
|
+
ensureArtifactsDir(options.artifactsDir);
|
|
1019
|
+
if (options.artifactConfig?.includeInput !== false) {
|
|
1020
|
+
writeArtifact(artifactPathsResult.inputPath, `# Task for ${agentName}
|
|
49
1021
|
|
|
50
|
-
${
|
|
51
|
-
|
|
1022
|
+
${taskWithAcceptance}`);
|
|
1023
|
+
}
|
|
1024
|
+
if (options.artifactConfig?.includeJsonl !== false) {
|
|
1025
|
+
jsonlPath = artifactPathsResult.jsonlPath;
|
|
1026
|
+
}
|
|
1027
|
+
if (options.artifactConfig?.includeTranscript !== false) {
|
|
1028
|
+
transcriptWriter = createChildTranscriptWriter({
|
|
1029
|
+
transcriptPath: artifactPathsResult.transcriptPath,
|
|
1030
|
+
source: "foreground",
|
|
1031
|
+
runId: options.runId,
|
|
1032
|
+
agent: agentName,
|
|
1033
|
+
childIndex: options.index,
|
|
1034
|
+
cwd: options.cwd ?? runtimeCwd
|
|
1035
|
+
});
|
|
1036
|
+
transcriptWriter.writeInitialUserMessage(taskWithAcceptance);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
let lastResult;
|
|
1040
|
+
const modelsToTry = candidates.length > 0 ? candidates : [undefined];
|
|
1041
|
+
for (let i = 0;i < modelsToTry.length; i++) {
|
|
1042
|
+
const candidate = modelsToTry[i];
|
|
1043
|
+
const outputSnapshot = captureSingleOutputSnapshot(options.outputPath);
|
|
1044
|
+
const result = await runSingleAttempt(runtimeCwd, agent, taskWithAcceptance, candidate, options, {
|
|
1045
|
+
sessionEnabled,
|
|
1046
|
+
systemPrompt,
|
|
1047
|
+
resolvedSkillNames: resolvedSkills.length > 0 ? resolvedSkills.map((skill) => skill.name) : undefined,
|
|
1048
|
+
skillsWarning: missingSkills.length > 0 ? `Skills not found: ${missingSkills.join(", ")}` : undefined,
|
|
1049
|
+
jsonlPath,
|
|
1050
|
+
artifactPaths: artifactPathsResult,
|
|
1051
|
+
transcriptWriter,
|
|
1052
|
+
attemptNotes,
|
|
1053
|
+
outputSnapshot,
|
|
1054
|
+
originalTask: task
|
|
1055
|
+
});
|
|
1056
|
+
lastResult = result;
|
|
1057
|
+
if (result.model)
|
|
1058
|
+
attemptedModels.push(result.model);
|
|
1059
|
+
else if (candidate)
|
|
1060
|
+
attemptedModels.push(candidate);
|
|
1061
|
+
sumUsage(aggregateUsage, result.usage);
|
|
1062
|
+
totalToolCount += result.progressSummary?.toolCount ?? 0;
|
|
1063
|
+
totalDurationMs += result.progressSummary?.durationMs ?? 0;
|
|
1064
|
+
const attemptSucceeded = result.exitCode === 0 && !result.error;
|
|
1065
|
+
const attempt = {
|
|
1066
|
+
model: result.model ?? candidate ?? agent.model ?? "default",
|
|
1067
|
+
success: attemptSucceeded,
|
|
1068
|
+
exitCode: result.exitCode,
|
|
1069
|
+
error: result.error,
|
|
1070
|
+
usage: { ...result.usage }
|
|
1071
|
+
};
|
|
1072
|
+
modelAttempts.push(attempt);
|
|
1073
|
+
if (result.timedOut || result.turnBudgetExceeded) {
|
|
1074
|
+
break;
|
|
1075
|
+
}
|
|
1076
|
+
if (attemptSucceeded) {
|
|
1077
|
+
break;
|
|
1078
|
+
}
|
|
1079
|
+
if (!isRetryableModelFailure(result.error) || i === modelsToTry.length - 1) {
|
|
1080
|
+
break;
|
|
1081
|
+
}
|
|
1082
|
+
attemptNotes.push(formatModelAttemptNote(attempt, modelsToTry[i + 1]));
|
|
1083
|
+
}
|
|
1084
|
+
const result = lastResult ?? {
|
|
1085
|
+
agent: agentName,
|
|
1086
|
+
task,
|
|
1087
|
+
exitCode: 1,
|
|
1088
|
+
messages: [],
|
|
1089
|
+
usage: emptyUsage(),
|
|
1090
|
+
error: "Subagent did not produce a result."
|
|
1091
|
+
};
|
|
1092
|
+
result.usage = aggregateUsage;
|
|
1093
|
+
result.attemptedModels = attemptedModels.length > 0 ? attemptedModels : undefined;
|
|
1094
|
+
result.modelAttempts = modelAttempts.length > 0 ? modelAttempts : undefined;
|
|
1095
|
+
result.progressSummary = {
|
|
1096
|
+
toolCount: totalToolCount,
|
|
1097
|
+
tokens: aggregateUsage.input + aggregateUsage.output,
|
|
1098
|
+
durationMs: totalDurationMs
|
|
1099
|
+
};
|
|
1100
|
+
if (attemptNotes.length > 0 && result.progress) {
|
|
1101
|
+
result.progress.recentOutput = [...attemptNotes, ...result.progress.recentOutput];
|
|
1102
|
+
if (result.progress.recentOutput.length > 50) {
|
|
1103
|
+
result.progress.recentOutput.splice(50);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (transcriptWriter)
|
|
1107
|
+
result.transcriptPath = artifactPathsResult?.transcriptPath;
|
|
1108
|
+
if (transcriptWriter?.getError())
|
|
1109
|
+
result.transcriptError = transcriptWriter.getError();
|
|
1110
|
+
if (artifactPathsResult && options.artifactConfig?.enabled !== false) {
|
|
1111
|
+
result.artifactPaths = artifactPathsResult;
|
|
1112
|
+
if (options.artifactConfig?.includeOutput !== false) {
|
|
1113
|
+
writeArtifact(artifactPathsResult.outputPath, artifactOutputByResult.get(result) ?? result.finalOutput ?? "");
|
|
1114
|
+
}
|
|
1115
|
+
if (options.artifactConfig?.includeMetadata !== false) {
|
|
1116
|
+
writeMetadata(artifactPathsResult.metadataPath, {
|
|
1117
|
+
runId: options.runId,
|
|
1118
|
+
agent: agentName,
|
|
1119
|
+
task,
|
|
1120
|
+
exitCode: result.exitCode,
|
|
1121
|
+
usage: result.usage,
|
|
1122
|
+
model: result.model,
|
|
1123
|
+
attemptedModels: result.attemptedModels,
|
|
1124
|
+
modelAttempts: result.modelAttempts,
|
|
1125
|
+
durationMs: result.progressSummary?.durationMs,
|
|
1126
|
+
toolCount: result.progressSummary?.toolCount,
|
|
1127
|
+
error: result.error,
|
|
1128
|
+
...transcriptWriter ? { transcriptPath: artifactPathsResult.transcriptPath } : {},
|
|
1129
|
+
transcriptError: result.transcriptError,
|
|
1130
|
+
skills: result.skills,
|
|
1131
|
+
skillsWarning: result.skillsWarning,
|
|
1132
|
+
timestamp: Date.now()
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
if (options.maxOutput) {
|
|
1136
|
+
const config = { ...DEFAULT_MAX_OUTPUT, ...options.maxOutput };
|
|
1137
|
+
const truncationResult = truncateOutput(result.finalOutput ?? "", config, artifactPathsResult.outputPath);
|
|
1138
|
+
if (truncationResult.truncated)
|
|
1139
|
+
result.truncation = truncationResult;
|
|
1140
|
+
}
|
|
1141
|
+
} else if (options.maxOutput) {
|
|
1142
|
+
const config = { ...DEFAULT_MAX_OUTPUT, ...options.maxOutput };
|
|
1143
|
+
const truncationResult = truncateOutput(result.finalOutput ?? "", config);
|
|
1144
|
+
if (truncationResult.truncated)
|
|
1145
|
+
result.truncation = truncationResult;
|
|
1146
|
+
}
|
|
1147
|
+
if (options.sessionFile && (existsSync(options.sessionFile) || result.messages?.length)) {
|
|
1148
|
+
result.sessionFile = options.sessionFile;
|
|
1149
|
+
} else if (shareEnabled && options.sessionDir) {
|
|
1150
|
+
const sessionFile = findLatestSessionFile(options.sessionDir);
|
|
1151
|
+
if (sessionFile)
|
|
1152
|
+
result.sessionFile = sessionFile;
|
|
1153
|
+
}
|
|
1154
|
+
result.acceptance = result.timedOut ? buildSkippedAcceptanceLedger(effectiveAcceptance, { id: "timeout", message: "Acceptance was not evaluated because the subagent timed out." }) : result.turnBudgetExceeded ? buildSkippedAcceptanceLedger(effectiveAcceptance, { id: "turn-budget", message: "Acceptance was not evaluated because the subagent exceeded its turn budget." }) : await evaluateAcceptance({
|
|
1155
|
+
acceptance: effectiveAcceptance,
|
|
1156
|
+
output: acceptanceOutputByResult.get(result) ?? result.finalOutput ?? "",
|
|
1157
|
+
cwd: options.cwd ?? runtimeCwd
|
|
1158
|
+
});
|
|
1159
|
+
const acceptanceFailure = acceptanceFailureMessage(result.acceptance);
|
|
1160
|
+
stripAcceptanceReportsFromMessages(result.messages);
|
|
1161
|
+
if (acceptanceFailure && result.acceptance.explicit && result.exitCode === 0 && !result.detached && !result.interrupted && !result.timedOut) {
|
|
1162
|
+
result.exitCode = 1;
|
|
1163
|
+
result.error = result.error ? `${result.error}
|
|
1164
|
+
${acceptanceFailure}` : acceptanceFailure;
|
|
1165
|
+
if (result.progress) {
|
|
1166
|
+
result.progress.status = "failed";
|
|
1167
|
+
result.progress.error = result.error;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
return result;
|
|
1171
|
+
}
|