@duckmind/dm-windows-x64 0.61.4 → 0.61.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 +211 -67
- package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
- package/extensions/dm-subagents/agents/claude-code.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec.md +15 -0
- package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
- package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
- package/extensions/dm-subagents/agents/delegate.md +3 -2
- package/extensions/dm-subagents/agents/oracle.md +10 -5
- package/extensions/dm-subagents/agents/researcher.md +2 -2
- package/extensions/dm-subagents/agents/reviewer.md +17 -7
- package/extensions/dm-subagents/agents/scout.md +5 -5
- package/extensions/dm-subagents/agents/worker.md +6 -2
- package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
- package/extensions/dm-subagents/index.js +4 -0
- package/extensions/dm-subagents/inspector-runner.mjs +10 -0
- package/extensions/dm-subagents/install.mjs +3 -2
- package/extensions/dm-subagents/package.json +2 -2
- package/extensions/dm-subagents/prompts/council.md +60 -0
- package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
- package/extensions/dm-subagents/prompts/review-loop.md +13 -7
- package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
- package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
- package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
- package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
- package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
- package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
- package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
- package/extensions/dm-subagents/src/agents/agents.js +1447 -299
- package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
- package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
- package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
- package/extensions/dm-subagents/src/agents/identity.js +1 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
- package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
- package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
- package/extensions/dm-subagents/src/agents/skills.js +52 -35
- package/extensions/dm-subagents/src/api/agents.js +6 -0
- package/extensions/dm-subagents/src/api/background-work.js +151 -0
- package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
- package/extensions/dm-subagents/src/api/control-channel.js +3 -0
- package/extensions/dm-subagents/src/api/delegation.js +5 -0
- package/extensions/dm-subagents/src/api/dm-args.js +3 -0
- package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
- package/extensions/dm-subagents/src/api/external-runs.js +233 -0
- package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
- package/extensions/dm-subagents/src/api/preflight.js +322 -0
- package/extensions/dm-subagents/src/api/project-panes.js +11 -0
- package/extensions/dm-subagents/src/api/shared-types.js +4 -0
- package/extensions/dm-subagents/src/extension/config.js +175 -0
- package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
- package/extensions/dm-subagents/src/extension/doctor.js +71 -17
- package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
- package/extensions/dm-subagents/src/extension/index.js +711 -265
- package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
- package/extensions/dm-subagents/src/extension/rpc.js +427 -22
- package/extensions/dm-subagents/src/extension/schemas.js +158 -65
- package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
- package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
- package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
- package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
- package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
- package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
- package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
- package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
- package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
- package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
- package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
- package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
- package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
- package/extensions/dm-subagents/src/missions/actions.js +394 -0
- package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
- package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
- package/extensions/dm-subagents/src/missions/store.js +548 -0
- package/extensions/dm-subagents/src/missions/types.js +9 -0
- package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
- package/extensions/dm-subagents/src/policy/authority.js +37 -0
- package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
- package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
- package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
- package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
- package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
- package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
- package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
- package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
- package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
- package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
- package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
- package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
- package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
- package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
- package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
- package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
- package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
- package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
- package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
- package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
- package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
- package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
- package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
- package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
- package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
- package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
- package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
- package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
- package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
- package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
- package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
- package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
- package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
- package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
- package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
- package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
- package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
- package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
- package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
- package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
- package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
- package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
- package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
- package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
- package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
- package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
- package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
- package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
- package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
- package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
- package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
- package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
- package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
- package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
- package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
- package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
- package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
- package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
- package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
- package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
- package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
- package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
- package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
- package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
- package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
- package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
- package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
- package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
- package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
- package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
- package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
- package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
- package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
- package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
- package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
- package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
- package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
- package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
- package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
- package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
- package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
- package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
- package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
- package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
- package/extensions/dm-subagents/src/shared/display-text.js +142 -0
- package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
- package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
- package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
- package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
- package/extensions/dm-subagents/src/shared/formatters.js +21 -7
- package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
- package/extensions/dm-subagents/src/shared/model-info.js +10 -5
- package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
- package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
- package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
- package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
- package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
- package/extensions/dm-subagents/src/shared/settings.js +39 -47
- package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
- package/extensions/dm-subagents/src/shared/status-format.js +9 -2
- package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
- package/extensions/dm-subagents/src/shared/types.js +47 -7
- package/extensions/dm-subagents/src/shared/utf8.js +12 -0
- package/extensions/dm-subagents/src/shared/utils.js +151 -131
- package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
- package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
- package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
- package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
- package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
- package/extensions/dm-subagents/src/slash/selector.js +101 -0
- package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
- package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
- package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
- package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
- package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
- package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
- package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
- package/extensions/dm-subagents/src/tui/render.js +1511 -261
- package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
- package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
- package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
- package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
- package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
- package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
- package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
- package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
- package/extensions/dm-subagents/src/watchdog/render.js +54 -0
- package/extensions/dm-subagents/src/watchdog/review.js +251 -0
- package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
- package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
- package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
- package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
- package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
- package/extensions/dm-subagents/src/watchdog/types.js +29 -0
- package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
- package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
- package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
- package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
- package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
- package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
- package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
- package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
- package/package.json +4 -3
- package/extensions/dm-fff/package.json +0 -21
- package/extensions/dm-fff/src/index.js +0 -691
- package/extensions/dm-fff/src/query.js +0 -60
- package/extensions/dm-subagents/agents/context-builder.md +0 -46
- package/extensions/dm-subagents/agents/planner.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
- package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
|
@@ -1,34 +1,56 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
2
3
|
import * as fs from "node:fs";
|
|
3
4
|
import * as path from "node:path";
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { discoverAgents, formatUnknownAgentError, unknownAgentDiagnosticContext } from "../../agents/agents.js";
|
|
8
|
+
import { appendAgentRefinementOverlay } from "../../agents/agent-refinements.js";
|
|
9
|
+
import { writePrivateAtomicJson } from "../../shared/atomic-json.js";
|
|
10
|
+
import { currentCompletionOwnerId } from "../../shared/completion-owner.js";
|
|
11
|
+
import { planChildLaunch, resolveStepBehavior, suppressProgressForReadOnlyTask } from "../shared/child-launch-plan.js";
|
|
12
|
+
import { applyThinkingSuffix, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan } from "../shared/dm-args.js";
|
|
7
13
|
import { injectOutputPathSystemPrompt, injectSingleOutputInstruction, normalizeSingleOutputOverride, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.js";
|
|
8
|
-
import { buildChainInstructions, isDynamicParallelStep, isParallelStep,
|
|
14
|
+
import { buildChainInstructions, isDynamicParallelStep, isParallelStep, resolveExistingReadPaths, writeInitialProgressFile } from "../../shared/settings.js";
|
|
9
15
|
import { resolvePiPackageRoot } from "../shared/dm-spawn.js";
|
|
16
|
+
import { preflightLaunchCwd } from "../shared/launch-cwd.js";
|
|
17
|
+
import { resolveNodeExecutable } from "../../shared/node-executable.js";
|
|
18
|
+
import { backgroundProcessOptions } from "../shared/background-process-options.js";
|
|
10
19
|
import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } from "../../agents/skills.js";
|
|
11
20
|
import { buildAgentMemoryInjection } from "../../agents/agent-memory.js";
|
|
12
|
-
import {
|
|
13
|
-
import { buildModelCandidates, resolveSubagentModelOverride } from "../shared/model-fallback.js";
|
|
14
|
-
import {
|
|
21
|
+
import { DM_CODING_AGENT_PACKAGE_ROOT_ENV, PROMPT_REDACTED, resolveChildCwd } from "../../shared/utils.js";
|
|
22
|
+
import { buildModelCandidates, inheritsParentModel, resolveEffectiveSubagentModel, resolveSubagentModelOverride } from "../shared/model-fallback.js";
|
|
23
|
+
import { resolveToolTimeoutMs, toolTimeoutFromEnv } from "../shared/tool-timeout.js";
|
|
24
|
+
import { resolveModelScopesForAgent } from "../shared/model-scope.js";
|
|
25
|
+
import { findModelInfo, resolveEffectiveThinking } from "../../shared/model-info.js";
|
|
26
|
+
import { assertThinkingWithinCeiling, decodeThinkingCeiling, intersectThinkingCeilings, SUBAGENT_THINKING_CEILING_ENV } from "../../shared/thinking-ceiling.js";
|
|
15
27
|
import { resolveExpectedWorktreeAgentCwd } from "../shared/worktree.js";
|
|
16
28
|
import { buildWorkflowGraphSnapshot } from "../shared/workflow-graph.js";
|
|
17
29
|
import { ChainOutputValidationError, validateChainOutputBindings } from "../shared/chain-outputs.js";
|
|
18
30
|
import { createStructuredOutputRuntime } from "../shared/structured-output.js";
|
|
19
|
-
import { resolveEffectiveAcceptance } from "../shared/acceptance.js";
|
|
31
|
+
import { resolveEffectiveAcceptance, validateAcceptanceInput, validateExecutionAcceptance } from "../shared/acceptance.js";
|
|
32
|
+
import { createRunFanoutBudget, writeRunFanoutBudgetDescriptor } from "../shared/run-fanout-budget.js";
|
|
33
|
+
import { validateImplementationToolContract } from "../shared/completion-guard.js";
|
|
20
34
|
import {
|
|
21
|
-
|
|
22
|
-
RESULTS_DIR,
|
|
35
|
+
DIRS,
|
|
23
36
|
SUBAGENT_ASYNC_STARTED_EVENT,
|
|
24
37
|
SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
25
38
|
TEMP_ROOT_DIR,
|
|
26
39
|
getAsyncConfigPath,
|
|
27
40
|
resolveChildMaxSubagentDepth
|
|
28
41
|
} from "../../shared/types.js";
|
|
29
|
-
import { nestedResultsPath, resolveInheritedNestedRouteFromEnv, resolveNestedParentAddressFromEnv, writeNestedEvent } from "../shared/nested-events.js";
|
|
30
|
-
import {
|
|
42
|
+
import { nestedResultsPath, nestedSummaryFromAsyncStatus, resolveInheritedNestedRouteFromEnv, resolveNestedParentAddressFromEnv, writeNestedEvent } from "../shared/nested-events.js";
|
|
43
|
+
import { resultFilePath } from "./result-files.js";
|
|
31
44
|
import { validateToolBudgetConfig } from "../shared/tool-budget.js";
|
|
45
|
+
import { usageBudgetState } from "../shared/usage-budget.js";
|
|
46
|
+
import { finalizeProcessTerminal, readProcessTerminal } from "./process-terminal.js";
|
|
47
|
+
import { statusStepDescription } from "./chain-append.js";
|
|
48
|
+
import { SUBAGENT_PROCESS_TERMINAL_EVENT } from "../../shared/types.js";
|
|
49
|
+
import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV } from "../shared/capability-ceiling.js";
|
|
50
|
+
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.js";
|
|
51
|
+
import { resolvePermissionRules } from "../shared/permissions.js";
|
|
52
|
+
import { normalizeExtensionBindings, omitExtensionBindingsEnv } from "../shared/extension-bindings.js";
|
|
53
|
+
import { assertWorkflowLaneKey, normalizeWorkflowLaneMetadata } from "../shared/lane-metadata.js";
|
|
32
54
|
const require = createRequire(import.meta.url);
|
|
33
55
|
const piPackageRoot = resolvePiPackageRoot();
|
|
34
56
|
function resolveJitiCliFromPackageJson(packageJsonPath) {
|
|
@@ -71,37 +93,25 @@ function resolveJitiCliPath() {
|
|
|
71
93
|
return;
|
|
72
94
|
}
|
|
73
95
|
const jitiCliPath = resolveJitiCliPath();
|
|
74
|
-
export
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"",
|
|
96
|
+
export const DEFAULT_ASYNC_TIMEOUT_MS = 30 * 60 * 1000;
|
|
97
|
+
export function formatAsyncStartedMessage(headline, interactive) {
|
|
98
|
+
const guidance = interactive ? [
|
|
99
|
+
"The async run is detached and running in the background.",
|
|
100
|
+
"You are in an interactive session. Return control to the user now; DM will wake you through the native completion notification when this subagent completes or needs attention. Do not run sleep/polling loops to wait for this async subagent; it does not need a wait call.",
|
|
101
|
+
"Use bg_wait only for provider, detached, or other background work that lacks a native completion notification.",
|
|
102
|
+
"If the current turn must receive results from work without a native notification before it ends, call blocking bg_wait(); ordinary async subagent runs do not need a wait call because their completion is delivered natively.",
|
|
103
|
+
'Otherwise, continue any independent work or return control to the user. Use subagent({ action: "status", id: "..." }) for a one-shot status/result or to inspect a blocked/stale run, never as a wait loop.'
|
|
104
|
+
] : [
|
|
78
105
|
"The async run is detached. Do not run sleep timers or polling loops just to wait for it.",
|
|
79
|
-
"
|
|
80
|
-
'Use subagent({ action: "status", id: "..." }) when you need a one-shot status/result or to inspect a blocked/stale run
|
|
81
|
-
]
|
|
106
|
+
"This is a non-interactive run: DM auto-drains current-session subagent work at agent_end so detached children are not abandoned. Use bg_wait only when this turn must receive provider, detached, or other background-work results that have no native completion notification.",
|
|
107
|
+
'Use subagent({ action: "status", id: "..." }) when you need a one-shot status/result or to inspect a blocked/stale run; do not poll in a loop.'
|
|
108
|
+
];
|
|
109
|
+
return [headline, "", ...guidance].join(`
|
|
82
110
|
`);
|
|
83
111
|
}
|
|
84
112
|
export function isAsyncAvailable() {
|
|
85
113
|
return jitiCliPath !== undefined;
|
|
86
114
|
}
|
|
87
|
-
function isNodeExecutableName(execPath) {
|
|
88
|
-
const basename = path.basename(execPath).toLowerCase();
|
|
89
|
-
return basename === "node" || basename === "node.exe" || basename === "nodejs" || basename === "nodejs.exe";
|
|
90
|
-
}
|
|
91
|
-
function canUseCurrentNodeExecutable(execPath) {
|
|
92
|
-
try {
|
|
93
|
-
fs.accessSync(execPath, process.platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
|
|
94
|
-
return true;
|
|
95
|
-
} catch {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
function resolveAsyncRunnerNodeCommand() {
|
|
100
|
-
if (isNodeExecutableName(process.execPath) && canUseCurrentNodeExecutable(process.execPath)) {
|
|
101
|
-
return process.execPath;
|
|
102
|
-
}
|
|
103
|
-
return process.platform === "win32" ? "node.exe" : "node";
|
|
104
|
-
}
|
|
105
115
|
export function resolveAsyncRunnerLogPaths(cfg) {
|
|
106
116
|
const asyncDir = typeof cfg.asyncDir === "string" ? cfg.asyncDir : undefined;
|
|
107
117
|
if (!asyncDir)
|
|
@@ -118,29 +128,151 @@ function closeFd(fd) {
|
|
|
118
128
|
fs.closeSync(fd);
|
|
119
129
|
} catch {}
|
|
120
130
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
const RUNNER_STARTUP_TIMEOUT_MS = 1e4;
|
|
132
|
+
const RUNNER_STARTUP_WAIT_BUFFER = typeof SharedArrayBuffer !== "undefined" ? new SharedArrayBuffer(4) : undefined;
|
|
133
|
+
const RUNNER_STARTUP_WAIT_VIEW = RUNNER_STARTUP_WAIT_BUFFER ? new Int32Array(RUNNER_STARTUP_WAIT_BUFFER) : undefined;
|
|
134
|
+
function waitForStartupInterval(delayMs = 20) {
|
|
135
|
+
if (RUNNER_STARTUP_WAIT_VIEW) {
|
|
136
|
+
Atomics.wait(RUNNER_STARTUP_WAIT_VIEW, 0, 0, delayMs);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const waitUntil = Date.now() + delayMs;
|
|
140
|
+
while (Date.now() < waitUntil) {}
|
|
125
141
|
}
|
|
126
|
-
function
|
|
127
|
-
if (!
|
|
128
|
-
return
|
|
142
|
+
function readRunnerStartup(startupPath, expectedState, expectedToken) {
|
|
143
|
+
if (!fs.existsSync(startupPath))
|
|
144
|
+
return;
|
|
145
|
+
try {
|
|
146
|
+
const payload = JSON.parse(fs.readFileSync(startupPath, "utf-8"));
|
|
147
|
+
if (payload.state === "error" && typeof payload.error === "string")
|
|
148
|
+
return { ok: false, error: payload.error, startupDidNotProceed: true };
|
|
149
|
+
if (payload.state !== expectedState)
|
|
150
|
+
return;
|
|
151
|
+
if (typeof payload.token !== "string" || expectedToken !== undefined && payload.token !== expectedToken) {
|
|
152
|
+
return { ok: false, error: `Async runner wrote an invalid ${expectedState} startup handshake: ${startupPath}`, startupDidNotProceed: true };
|
|
153
|
+
}
|
|
154
|
+
return { ok: true, token: payload.token };
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return { ok: false, error: `Failed to read async runner startup handshake '${startupPath}': ${error instanceof Error ? error.message : String(error)}`, startupDidNotProceed: true };
|
|
129
157
|
}
|
|
158
|
+
}
|
|
159
|
+
function waitForRunnerStartup(startupPath, expectedState, timeoutMs, expectedToken) {
|
|
160
|
+
const deadline = Date.now() + timeoutMs;
|
|
161
|
+
for (;; ) {
|
|
162
|
+
const result = readRunnerStartup(startupPath, expectedState, expectedToken);
|
|
163
|
+
if (result)
|
|
164
|
+
return result;
|
|
165
|
+
if (Date.now() >= deadline)
|
|
166
|
+
break;
|
|
167
|
+
waitForStartupInterval(Math.min(20, Math.max(1, deadline - Date.now())));
|
|
168
|
+
}
|
|
169
|
+
const finalResult = readRunnerStartup(startupPath, expectedState, expectedToken);
|
|
170
|
+
if (finalResult)
|
|
171
|
+
return finalResult;
|
|
172
|
+
return { ok: false, error: `Timed out after ${timeoutMs}ms waiting for the async runner startup state '${expectedState}'.`, startupDidNotProceed: true };
|
|
173
|
+
}
|
|
174
|
+
function writeRunnerStartupControl(filePath, payload) {
|
|
175
|
+
writePrivateAtomicJson(filePath, payload);
|
|
176
|
+
}
|
|
177
|
+
function runnerIsAlive(pid) {
|
|
130
178
|
try {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
179
|
+
process.kill(pid, 0);
|
|
180
|
+
return true;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
return error.code === "EPERM";
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function terminateRunnerBeforeProceed(pid) {
|
|
186
|
+
for (const signal of ["SIGTERM", "SIGKILL"]) {
|
|
187
|
+
if (!runnerIsAlive(pid))
|
|
188
|
+
return true;
|
|
189
|
+
try {
|
|
190
|
+
process.kill(pid, signal);
|
|
191
|
+
} catch {
|
|
192
|
+
if (!runnerIsAlive(pid))
|
|
193
|
+
return true;
|
|
134
194
|
}
|
|
135
|
-
|
|
136
|
-
|
|
195
|
+
const deadline = Date.now() + 1000;
|
|
196
|
+
while (runnerIsAlive(pid) && Date.now() < deadline)
|
|
197
|
+
waitForStartupInterval();
|
|
198
|
+
}
|
|
199
|
+
return !runnerIsAlive(pid);
|
|
200
|
+
}
|
|
201
|
+
function persistPreProceedStartupFailure(asyncDir, runId, runnerProcessInstanceId, sessionId, completionOwnerId, message) {
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
try {
|
|
204
|
+
const statusPath = path.join(asyncDir, "status.json");
|
|
205
|
+
let status = {};
|
|
206
|
+
try {
|
|
207
|
+
status = JSON.parse(fs.readFileSync(statusPath, "utf-8"));
|
|
208
|
+
} catch {}
|
|
209
|
+
writePrivateAtomicJson(statusPath, {
|
|
210
|
+
...status,
|
|
211
|
+
runId,
|
|
212
|
+
...sessionId ? { sessionId } : {},
|
|
213
|
+
...completionOwnerId ? { completionOwnerId } : {},
|
|
214
|
+
state: "failed",
|
|
215
|
+
lastUpdate: now,
|
|
216
|
+
error: message,
|
|
217
|
+
processTerminal: {
|
|
218
|
+
version: 1,
|
|
219
|
+
state: "not-started",
|
|
220
|
+
runId,
|
|
221
|
+
runnerProcessInstanceId
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
writePrivateAtomicJson(path.join(asyncDir, "process-terminal-candidate.json"), {
|
|
225
|
+
version: 1,
|
|
226
|
+
runId,
|
|
227
|
+
runnerProcessInstanceId,
|
|
228
|
+
writers: {},
|
|
229
|
+
expectedWriters: { 0: 0 }
|
|
230
|
+
});
|
|
231
|
+
} catch {}
|
|
232
|
+
}
|
|
233
|
+
function isStaleExtensionContextError(error) {
|
|
234
|
+
return error instanceof Error && /extension ctx is stale|stale after session replacement or reload/i.test(error.message);
|
|
235
|
+
}
|
|
236
|
+
export function emitProcessTerminalEvent(ctx, proof) {
|
|
237
|
+
try {
|
|
238
|
+
ctx.dm.events.emit(SUBAGENT_PROCESS_TERMINAL_EVENT, proof);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
if (isStaleExtensionContextError(error))
|
|
241
|
+
return;
|
|
242
|
+
console.error("Failed to emit subagent process-terminal event:", error);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function spawnRunner(cfg, suffix, cwd, initialStatus, initialStatusPath, onProcessTerminal, requestedCwd = cwd) {
|
|
246
|
+
const cwdError = preflightLaunchCwd(requestedCwd, cwd);
|
|
247
|
+
if (cwdError)
|
|
248
|
+
return { error: cwdError };
|
|
249
|
+
if (!jitiCliPath) {
|
|
250
|
+
return { error: "upstream jiti for TypeScript execution could not be found; ensure package dependencies are installed" };
|
|
137
251
|
}
|
|
138
252
|
fs.mkdirSync(TEMP_ROOT_DIR, { recursive: true });
|
|
139
253
|
const cfgPath = getAsyncConfigPath(suffix);
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
const
|
|
254
|
+
const runnerProcessInstanceId = randomUUID();
|
|
255
|
+
const hasRevivalLease = typeof cfg.revivalLease === "object";
|
|
256
|
+
const launchBarrierToken = hasRevivalLease ? undefined : runnerProcessInstanceId;
|
|
257
|
+
const launchConfig = { ...cfg, runnerProcessInstanceId, ...launchBarrierToken ? { launchBarrierToken } : {} };
|
|
258
|
+
writePrivateAtomicJson(cfgPath, launchConfig);
|
|
259
|
+
const runner = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-runner.js");
|
|
260
|
+
const nodeCommand = resolveNodeExecutable();
|
|
261
|
+
const launchForStartup = launchConfig;
|
|
262
|
+
const launchAsyncDir = typeof launchForStartup.asyncDir === "string" ? launchForStartup.asyncDir : undefined;
|
|
263
|
+
const launchRunId = typeof launchForStartup.id === "string" ? launchForStartup.id : suffix;
|
|
264
|
+
const launchSessionId = typeof launchForStartup.sessionId === "string" ? launchForStartup.sessionId : undefined;
|
|
265
|
+
const launchCompletionOwnerId = typeof launchForStartup.completionOwnerId === "string" ? launchForStartup.completionOwnerId : undefined;
|
|
266
|
+
const startupPath = typeof launchForStartup.revivalLease === "object" && launchAsyncDir ? path.join(launchAsyncDir, "runner-startup.json") : undefined;
|
|
267
|
+
const startupAckPath = startupPath ? path.join(path.dirname(startupPath), "runner-startup-ack.json") : undefined;
|
|
268
|
+
const startupProceedPath = launchAsyncDir && (startupPath || launchBarrierToken) ? path.join(launchAsyncDir, "runner-startup-proceed.json") : undefined;
|
|
269
|
+
if (startupPath)
|
|
270
|
+
fs.rmSync(startupPath, { force: true });
|
|
271
|
+
if (startupAckPath)
|
|
272
|
+
fs.rmSync(startupAckPath, { force: true });
|
|
273
|
+
if (startupProceedPath)
|
|
274
|
+
fs.rmSync(startupProceedPath, { force: true });
|
|
275
|
+
const logPaths = resolveAsyncRunnerLogPaths(launchConfig);
|
|
144
276
|
let stdoutFd;
|
|
145
277
|
let stderrFd;
|
|
146
278
|
try {
|
|
@@ -151,12 +283,11 @@ function spawnRunner(cfg, suffix, cwd) {
|
|
|
151
283
|
}
|
|
152
284
|
const proc = spawn(nodeCommand, [jitiCliPath, runner, cfgPath], {
|
|
153
285
|
cwd,
|
|
154
|
-
|
|
286
|
+
...backgroundProcessOptions(),
|
|
155
287
|
stdio: ["ignore", stdoutFd ?? "ignore", stderrFd ?? "ignore"],
|
|
156
|
-
windowsHide: true,
|
|
157
288
|
env: {
|
|
158
|
-
...process.env,
|
|
159
|
-
...piPackageRoot ? { [
|
|
289
|
+
...omitExtensionBindingsEnv(process.env),
|
|
290
|
+
...piPackageRoot ? { [DM_CODING_AGENT_PACKAGE_ROOT_ENV]: piPackageRoot } : {}
|
|
160
291
|
}
|
|
161
292
|
});
|
|
162
293
|
closeFd(stdoutFd);
|
|
@@ -164,11 +295,122 @@ function spawnRunner(cfg, suffix, cwd) {
|
|
|
164
295
|
proc.on("error", (error) => {
|
|
165
296
|
console.error(`[dm-subagents] async spawn failed: ${error.message}`);
|
|
166
297
|
});
|
|
298
|
+
proc.once("close", (exitCode, signal) => {
|
|
299
|
+
const launch = launchConfig;
|
|
300
|
+
const asyncDir = launch.asyncDir;
|
|
301
|
+
const runId = launch.id;
|
|
302
|
+
if (typeof asyncDir !== "string" || typeof runId !== "string")
|
|
303
|
+
return;
|
|
304
|
+
finalizeProcessTerminal(asyncDir, runId, {
|
|
305
|
+
processInstanceId: runnerProcessInstanceId,
|
|
306
|
+
closeObservedAt: Date.now(),
|
|
307
|
+
exitCode,
|
|
308
|
+
signal
|
|
309
|
+
});
|
|
310
|
+
const persisted = readProcessTerminal(asyncDir, { runId, runnerProcessInstanceId });
|
|
311
|
+
if (!persisted)
|
|
312
|
+
return;
|
|
313
|
+
if (launch.nestedRoute && launch.nestedSelf) {
|
|
314
|
+
try {
|
|
315
|
+
let status;
|
|
316
|
+
try {
|
|
317
|
+
status = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8"));
|
|
318
|
+
status.processTerminal = persisted;
|
|
319
|
+
} catch {
|
|
320
|
+
status = {
|
|
321
|
+
runId,
|
|
322
|
+
mode: "single",
|
|
323
|
+
state: persisted.state === "observed" ? "complete" : "failed",
|
|
324
|
+
startedAt: persisted.observedAt ?? Date.now(),
|
|
325
|
+
lastUpdate: Date.now(),
|
|
326
|
+
processTerminal: persisted
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
writeNestedEvent(launch.nestedRoute, {
|
|
330
|
+
type: "subagent.nested.completed",
|
|
331
|
+
ts: Date.now(),
|
|
332
|
+
parentRunId: launch.nestedSelf.parentRunId,
|
|
333
|
+
parentStepIndex: launch.nestedSelf.parentStepIndex,
|
|
334
|
+
child: nestedSummaryFromAsyncStatus(status, asyncDir, {
|
|
335
|
+
id: runId,
|
|
336
|
+
parentRunId: launch.nestedSelf.parentRunId,
|
|
337
|
+
parentStepIndex: launch.nestedSelf.parentStepIndex,
|
|
338
|
+
depth: launch.nestedSelf.depth,
|
|
339
|
+
path: launch.nestedSelf.path,
|
|
340
|
+
mode: status.mode,
|
|
341
|
+
ts: Date.now()
|
|
342
|
+
})
|
|
343
|
+
});
|
|
344
|
+
} catch (error) {
|
|
345
|
+
console.error("Failed to emit final nested process-terminal status:", error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
onProcessTerminal?.(persisted);
|
|
349
|
+
});
|
|
167
350
|
if (typeof proc.pid !== "number") {
|
|
168
351
|
return { error: `async runner did not produce a pid for cwd: ${cwd}` };
|
|
169
352
|
}
|
|
353
|
+
try {
|
|
354
|
+
writePrivateAtomicJson(initialStatusPath, {
|
|
355
|
+
...initialStatus,
|
|
356
|
+
pid: proc.pid,
|
|
357
|
+
processTerminal: { version: 1, state: "pending", runId: initialStatus.runId, runnerProcessInstanceId }
|
|
358
|
+
});
|
|
359
|
+
} catch (error) {
|
|
360
|
+
const message = `Failed to persist initial async status: ${error instanceof Error ? error.message : String(error)}`;
|
|
361
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
362
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: message, terminationObserved, startupDidNotProceed: true };
|
|
363
|
+
}
|
|
364
|
+
if (launchBarrierToken && startupProceedPath) {
|
|
365
|
+
try {
|
|
366
|
+
writeRunnerStartupControl(startupProceedPath, { action: "proceed", token: launchBarrierToken });
|
|
367
|
+
} catch (error) {
|
|
368
|
+
const message = `Failed to authorize async runner startup: ${error instanceof Error ? error.message : String(error)}`;
|
|
369
|
+
if (launchAsyncDir)
|
|
370
|
+
persistPreProceedStartupFailure(launchAsyncDir, launchRunId, runnerProcessInstanceId, launchSessionId, launchCompletionOwnerId, message);
|
|
371
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
372
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: message, terminationObserved, startupDidNotProceed: true };
|
|
373
|
+
}
|
|
374
|
+
}
|
|
170
375
|
proc.unref();
|
|
171
|
-
|
|
376
|
+
if (startupPath && startupAckPath && startupProceedPath) {
|
|
377
|
+
const persistStartupFailure = (message) => {
|
|
378
|
+
if (launchAsyncDir)
|
|
379
|
+
persistPreProceedStartupFailure(launchAsyncDir, launchRunId, runnerProcessInstanceId, launchSessionId, launchCompletionOwnerId, message);
|
|
380
|
+
};
|
|
381
|
+
const ready = waitForRunnerStartup(startupPath, "ready", RUNNER_STARTUP_TIMEOUT_MS);
|
|
382
|
+
if (ready.ok === false) {
|
|
383
|
+
persistStartupFailure(ready.error);
|
|
384
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
385
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: ready.error, terminationObserved, startupDidNotProceed: ready.startupDidNotProceed };
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
writeRunnerStartupControl(startupAckPath, { action: "ack", token: ready.token });
|
|
389
|
+
} catch (error) {
|
|
390
|
+
const message = `Failed to acknowledge async runner startup: ${error instanceof Error ? error.message : String(error)}`;
|
|
391
|
+
persistStartupFailure(message);
|
|
392
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
393
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: message, terminationObserved, startupDidNotProceed: true };
|
|
394
|
+
}
|
|
395
|
+
const acknowledged = waitForRunnerStartup(startupPath, "acknowledged", RUNNER_STARTUP_TIMEOUT_MS, ready.token);
|
|
396
|
+
if (acknowledged.ok === false) {
|
|
397
|
+
persistStartupFailure(acknowledged.error);
|
|
398
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
399
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: acknowledged.error, terminationObserved, startupDidNotProceed: acknowledged.startupDidNotProceed };
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
writeRunnerStartupControl(startupProceedPath, { action: "proceed", token: ready.token });
|
|
403
|
+
} catch (error) {
|
|
404
|
+
const message = `Failed to authorize async runner startup: ${error instanceof Error ? error.message : String(error)}`;
|
|
405
|
+
persistStartupFailure(message);
|
|
406
|
+
const terminationObserved = terminateRunnerBeforeProceed(proc.pid);
|
|
407
|
+
return { pid: proc.pid, runnerProcessInstanceId, error: message, terminationObserved, startupDidNotProceed: true };
|
|
408
|
+
}
|
|
409
|
+
try {
|
|
410
|
+
fs.rmSync(startupPath, { force: true });
|
|
411
|
+
} catch {}
|
|
412
|
+
}
|
|
413
|
+
return { pid: proc.pid, runnerProcessInstanceId };
|
|
172
414
|
} catch (error) {
|
|
173
415
|
closeFd(stdoutFd);
|
|
174
416
|
closeFd(stderrFd);
|
|
@@ -225,12 +467,12 @@ export function buildAsyncRunnerSteps(id, params) {
|
|
|
225
467
|
throw error;
|
|
226
468
|
}
|
|
227
469
|
const workflowGraph = buildWorkflowGraphSnapshot({ runId: id, mode: resultMode, steps: graphChain });
|
|
470
|
+
const diagnosticContext = params.unknownAgentDiagnosticContext ?? unknownAgentDiagnosticContext(discoverAgents(path.resolve(runnerCwd), "both"));
|
|
228
471
|
for (const s of chain) {
|
|
229
472
|
const stepAgents = isParallelStep(s) ? s.parallel.map((t) => t.agent) : isDynamicParallelStep(s) ? [s.parallel.agent] : [s.agent];
|
|
230
473
|
for (const agentName of stepAgents) {
|
|
231
|
-
if (!agents.find((x) => x.name === agentName))
|
|
232
|
-
return { error:
|
|
233
|
-
}
|
|
474
|
+
if (!agents.find((x) => x.name === agentName))
|
|
475
|
+
return { error: formatUnknownAgentError(agentName, diagnosticContext) };
|
|
234
476
|
}
|
|
235
477
|
}
|
|
236
478
|
let progressInstructionCreated = false;
|
|
@@ -242,20 +484,64 @@ export function buildAsyncRunnerSteps(id, params) {
|
|
|
242
484
|
...s.reads !== undefined ? { reads: s.reads } : {},
|
|
243
485
|
...s.progress !== undefined ? { progress: s.progress } : {},
|
|
244
486
|
...stepSkillInput !== undefined ? { skills: stepSkillInput } : {},
|
|
245
|
-
...s.model ? { model: s.model } : {}
|
|
487
|
+
...s.model !== undefined ? { model: s.model } : {},
|
|
488
|
+
...s.fast !== undefined ? { fast: s.fast } : {}
|
|
246
489
|
};
|
|
247
490
|
};
|
|
248
|
-
const buildSeqStep = (s, sessionFile, behaviorCwd, progressPrecreated = false, resolvedBehavior, flatIndex) => {
|
|
491
|
+
const buildSeqStep = (s, sessionFile, behaviorCwd, progressPrecreated = false, resolvedBehavior, flatIndex, parallelOutputNamespace, runFanoutPath) => {
|
|
249
492
|
const a = agents.find((x) => x.name === s.agent);
|
|
493
|
+
const externalRunner = a.runner?.type === "external-cli" || a.runner?.type === "external-job";
|
|
494
|
+
const externalRunnerType = a.runner?.type;
|
|
495
|
+
if (externalRunner) {
|
|
496
|
+
const unsupported = [];
|
|
497
|
+
if (s.model !== undefined)
|
|
498
|
+
unsupported.push("model override");
|
|
499
|
+
if (s.outputSchema !== undefined)
|
|
500
|
+
unsupported.push("structured output");
|
|
501
|
+
if (s.acceptance !== undefined || params.agentContract !== undefined || s.agentContract !== undefined)
|
|
502
|
+
unsupported.push("acceptance/agent contract");
|
|
503
|
+
if (s.toolBudget !== undefined || params.toolBudget !== undefined || a.toolBudget !== undefined || params.configToolBudget !== undefined)
|
|
504
|
+
unsupported.push("tool budget");
|
|
505
|
+
if ((s.fast ?? params.fast ?? a.fast) === true)
|
|
506
|
+
unsupported.push("fast mode");
|
|
507
|
+
if (params.contextForAgent?.(s.agent) === "fork")
|
|
508
|
+
unsupported.push("fork context");
|
|
509
|
+
if (unsupported.length > 0)
|
|
510
|
+
throw new AsyncStartValidationError(`Agent '${a.name}' uses runner.type='${externalRunnerType}' and does not support: ${unsupported.join(", ")}.`);
|
|
511
|
+
}
|
|
512
|
+
try {
|
|
513
|
+
assertAgentAllowedByCapabilityCeiling(a.name, intersectSubagentCapabilityCeilings(params.capabilityCeiling, decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV])));
|
|
514
|
+
} catch (error) {
|
|
515
|
+
throw new AsyncStartValidationError(error instanceof Error ? error.message : String(error));
|
|
516
|
+
}
|
|
250
517
|
const toolBudgetInput = s.toolBudget ?? params.toolBudget ?? a.toolBudget ?? params.configToolBudget;
|
|
251
518
|
const resolvedToolBudget = validateToolBudgetConfig(toolBudgetInput, s.toolBudget ? "toolBudget" : a.toolBudget ? "agent.toolBudget" : "config.toolBudget");
|
|
252
519
|
if (resolvedToolBudget.error)
|
|
253
520
|
throw new AsyncStartValidationError(resolvedToolBudget.error);
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
521
|
+
const resolvedToolTimeout = resolveToolTimeoutMs({
|
|
522
|
+
callValue: params.callToolTimeoutMs,
|
|
523
|
+
agentValue: a.defaultToolTimeoutMs,
|
|
524
|
+
configValue: params.configToolTimeoutMs,
|
|
525
|
+
envValue: params.toolTimeoutMsEnv ?? toolTimeoutFromEnv()
|
|
526
|
+
});
|
|
527
|
+
if (resolvedToolTimeout.error)
|
|
528
|
+
throw new AsyncStartValidationError(resolvedToolTimeout.error);
|
|
529
|
+
const launchPlan = planChildLaunch({
|
|
530
|
+
agentConfig: a,
|
|
531
|
+
stepOverrides: buildStepOverrides(s),
|
|
532
|
+
task: s.task,
|
|
533
|
+
originalTask,
|
|
534
|
+
runnerCwd,
|
|
535
|
+
runtimeCwd: ctx.cwd,
|
|
536
|
+
stepCwdInput: s.cwd,
|
|
537
|
+
behaviorCwd,
|
|
538
|
+
chainSkills,
|
|
539
|
+
outputBaseDir,
|
|
540
|
+
parallelOutputNamespace,
|
|
541
|
+
resolvedBehavior
|
|
542
|
+
});
|
|
543
|
+
const { stepCwd, instructionCwd, readExistenceCwd, behavior, namespaceOutputPath, outputPath, skillNames } = launchPlan;
|
|
544
|
+
const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(skillNames, stepCwd, ctx.cwd, a.skillPath, a.filePath ? path.dirname(a.filePath) : stepCwd);
|
|
259
545
|
if (missingSkills.includes("dm-subagents"))
|
|
260
546
|
throw new UnavailableSubagentSkillError(UNAVAILABLE_SUBAGENT_SKILL_ERROR);
|
|
261
547
|
let systemPrompt = a.systemPrompt?.trim() ?? "";
|
|
@@ -271,62 +557,158 @@ ${injection}` : injection;
|
|
|
271
557
|
|
|
272
558
|
${memoryInjection}` : memoryInjection;
|
|
273
559
|
}
|
|
274
|
-
|
|
560
|
+
systemPrompt = appendAgentRefinementOverlay(systemPrompt, { cwd: stepCwd, agentName: a.name });
|
|
561
|
+
const readInstructions = buildChainInstructions({ ...behavior, output: false, progress: false }, instructionCwd, false, undefined, readExistenceCwd);
|
|
275
562
|
const isFirstProgressAgent = behavior.progress && !progressPrecreated && !progressInstructionCreated;
|
|
276
563
|
if (behavior.progress)
|
|
277
564
|
progressInstructionCreated = true;
|
|
278
565
|
const progressInstructions = buildChainInstructions({ ...behavior, output: false, reads: false }, progressDir, isFirstProgressAgent);
|
|
279
|
-
|
|
280
|
-
|
|
566
|
+
if (!namespaceOutputPath)
|
|
567
|
+
systemPrompt = injectOutputPathSystemPrompt(systemPrompt, outputPath, a);
|
|
281
568
|
const validationError = validateFileOnlyOutputMode(behavior.outputMode, outputPath, `Async step (${s.agent})`);
|
|
282
569
|
if (validationError)
|
|
283
570
|
throw new AsyncStartValidationError(validationError);
|
|
284
571
|
let taskTemplate = s.task ?? "{previous}";
|
|
285
572
|
taskTemplate = taskTemplate.replace(/\{task\}/g, originalTask ?? "");
|
|
286
573
|
taskTemplate = taskTemplate.replace(/\{chain_dir\}/g, runnerCwd);
|
|
287
|
-
const
|
|
288
|
-
const
|
|
289
|
-
const
|
|
574
|
+
const taskText = `${readInstructions.prefix}${taskTemplate}${progressInstructions.suffix}`;
|
|
575
|
+
const task = namespaceOutputPath ? taskText : injectSingleOutputInstruction(taskText, outputPath, a);
|
|
576
|
+
const modelScopes = resolveModelScopesForAgent(ctx.modelScope, a.name, ctx.currentModel);
|
|
577
|
+
const primaryModelFromParent = inheritsParentModel(s.model, a.model, ctx.currentModel);
|
|
578
|
+
const primaryModel = externalRunner ? undefined : resolveEffectiveSubagentModel(s.model, a.model, ctx.currentModel, availableModels, a.modelProvider ?? ctx.currentModelProvider, { scope: modelScopes });
|
|
290
579
|
const thinkingOverride = flatIndex === undefined ? undefined : thinkingOverridesByFlatIndex?.[flatIndex];
|
|
291
|
-
const effectiveThinking = thinkingOverride ?? a.thinking;
|
|
292
|
-
const model = applyThinkingSuffix(primaryModel, effectiveThinking, thinkingOverride !== undefined);
|
|
580
|
+
const effectiveThinking = externalRunner ? undefined : thinkingOverride ?? a.thinking;
|
|
581
|
+
const model = externalRunner ? undefined : applyThinkingSuffix(primaryModel, effectiveThinking, thinkingOverride !== undefined);
|
|
582
|
+
const contextLimit = model ? findModelInfo(model, availableModels, a.modelProvider ?? ctx.currentModelProvider)?.contextWindow : undefined;
|
|
583
|
+
const thinkingCeiling = externalRunner ? undefined : intersectThinkingCeilings(params.thinkingCeiling, a.maxThinking, decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]));
|
|
584
|
+
if (!externalRunner) {
|
|
585
|
+
try {
|
|
586
|
+
assertThinkingWithinCeiling({ model, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: a.name, runId: id });
|
|
587
|
+
} catch (error) {
|
|
588
|
+
throw new AsyncStartValidationError(error instanceof Error ? error.message : String(error));
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
const agentContract = s.agentContract ?? params.agentContract;
|
|
592
|
+
const permissionRules = resolvePermissionRules(ctx.permissions, a.permissions);
|
|
593
|
+
const modelCandidates = externalRunner ? [] : buildModelCandidates(primaryModel, a.fallbackModels, availableModels, a.modelProvider ?? ctx.currentModelProvider, {
|
|
594
|
+
scope: modelScopes,
|
|
595
|
+
primaryModelFromParent
|
|
596
|
+
}).flatMap((candidate) => {
|
|
597
|
+
const resolved = applyThinkingSuffix(candidate, effectiveThinking, thinkingOverride !== undefined);
|
|
598
|
+
return resolved ? [resolved] : [];
|
|
599
|
+
});
|
|
600
|
+
if (!externalRunner) {
|
|
601
|
+
try {
|
|
602
|
+
for (const candidate of modelCandidates)
|
|
603
|
+
assertThinkingWithinCeiling({ model: candidate, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: a.name, runId: id });
|
|
604
|
+
} catch (error) {
|
|
605
|
+
throw new AsyncStartValidationError(error instanceof Error ? error.message : String(error));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const fast = s.fast ?? params.fast ?? a.fast;
|
|
609
|
+
const toolPlan = resolvePiLaunchToolPlan({
|
|
610
|
+
tools: a.tools,
|
|
611
|
+
allowNestedSubagents: a.allowNestedSubagents,
|
|
612
|
+
extensions: a.extensions,
|
|
613
|
+
subagentOnlyExtensions: a.subagentOnlyExtensions,
|
|
614
|
+
mcpDirectTools: a.mcpDirectTools,
|
|
615
|
+
cwd: stepCwd,
|
|
616
|
+
requireReadTool: Boolean(resolvedSkills.length),
|
|
617
|
+
structuredOutput: Boolean(s.outputSchema),
|
|
618
|
+
fast,
|
|
619
|
+
model,
|
|
620
|
+
modelCandidates,
|
|
621
|
+
capabilityCeiling: params.capabilityCeiling,
|
|
622
|
+
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
623
|
+
agentName: a.name,
|
|
624
|
+
permissionRules,
|
|
625
|
+
runtimeSnapshotHost: ctx.dm
|
|
626
|
+
});
|
|
627
|
+
const launchResolvedExtensions = externalRunner ? undefined : projectLaunchResolvedChildExtensions(toolPlan);
|
|
628
|
+
if (externalRunner && permissionRules) {
|
|
629
|
+
throw new AsyncStartValidationError(`Agent '${a.name}' uses runner.type='${externalRunnerType}', which cannot enforce native DM child permission rules.`);
|
|
630
|
+
}
|
|
631
|
+
if (!externalRunner) {
|
|
632
|
+
const contractTools = toolPlan.explicitToolAllowlist ? toolPlan.effectiveToolAllowlist : undefined;
|
|
633
|
+
const contractError = validateImplementationToolContract({
|
|
634
|
+
agent: a.name,
|
|
635
|
+
task,
|
|
636
|
+
tools: contractTools,
|
|
637
|
+
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
638
|
+
configuredExtensions: toolPlan.configuredExtensions,
|
|
639
|
+
requestedTools: toolPlan.requestedBuiltinTools,
|
|
640
|
+
acceptanceRole: a.acceptanceRole,
|
|
641
|
+
completionGuard: a.completionGuard
|
|
642
|
+
});
|
|
643
|
+
if (contractError)
|
|
644
|
+
throw new AsyncStartValidationError(contractError);
|
|
645
|
+
}
|
|
293
646
|
return {
|
|
294
647
|
parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
|
|
648
|
+
permissionRules,
|
|
649
|
+
...params.capabilityCeiling ? { capabilityCeiling: params.capabilityCeiling } : {},
|
|
650
|
+
...runFanoutPath ? { runFanoutPath } : {},
|
|
295
651
|
agent: s.agent,
|
|
296
652
|
task,
|
|
653
|
+
...a.runner ? { runner: a.runner } : {},
|
|
654
|
+
...params.contextForAgent ? { context: params.contextForAgent(s.agent) } : {},
|
|
655
|
+
...agentContract ? { agentContract } : {},
|
|
297
656
|
phase: s.phase,
|
|
298
657
|
label: s.label,
|
|
299
658
|
outputName: s.as,
|
|
300
659
|
structured: Boolean(s.outputSchema),
|
|
301
660
|
cwd: stepCwd,
|
|
661
|
+
requestedCwd: s.cwd ?? stepCwd,
|
|
302
662
|
model,
|
|
663
|
+
...contextLimit !== undefined ? { contextLimit } : {},
|
|
664
|
+
...fast !== undefined ? { fast } : {},
|
|
303
665
|
thinking: resolveEffectiveThinking(model, effectiveThinking),
|
|
304
|
-
|
|
666
|
+
...thinkingCeiling ? { thinkingCeiling } : {},
|
|
667
|
+
launchResolvedExtensions,
|
|
668
|
+
...toolPlan.mcpConfig ? { mcpConfig: toolPlan.mcpConfig } : {},
|
|
669
|
+
...toolPlan.runtimeServerNames ? { runtimeServerNames: toolPlan.runtimeServerNames } : {},
|
|
670
|
+
modelCandidates: externalRunner ? undefined : modelCandidates,
|
|
671
|
+
...primaryModelFromParent ? { skipPrimaryModelVerification: true } : {},
|
|
672
|
+
...availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {},
|
|
305
673
|
tools: a.tools,
|
|
674
|
+
allowNestedSubagents: a.allowNestedSubagents,
|
|
306
675
|
extensions: a.extensions,
|
|
307
676
|
subagentOnlyExtensions: a.subagentOnlyExtensions,
|
|
308
677
|
mcpDirectTools: a.mcpDirectTools,
|
|
678
|
+
mutationTools: a.mutationTools,
|
|
309
679
|
completionGuard: a.completionGuard,
|
|
310
680
|
systemPrompt,
|
|
311
681
|
systemPromptMode: a.systemPromptMode,
|
|
312
682
|
inheritProjectContext: a.inheritProjectContext,
|
|
683
|
+
inheritGlobalContext: a.inheritGlobalContext,
|
|
313
684
|
inheritSkills: a.inheritSkills,
|
|
314
685
|
skills: resolvedSkills.map((r) => r.name),
|
|
315
686
|
outputPath,
|
|
687
|
+
...namespaceOutputPath ? { namespaceOutputPath: true } : {},
|
|
316
688
|
outputMode: behavior.outputMode,
|
|
317
689
|
sessionFile,
|
|
318
690
|
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, a.maxSubagentDepth),
|
|
691
|
+
timeoutMs: a.defaultTimeoutMs ?? DEFAULT_ASYNC_TIMEOUT_MS,
|
|
692
|
+
toolTimeoutMs: resolvedToolTimeout.toolTimeoutMs,
|
|
693
|
+
waitToolEnabled: params.waitToolEnabled,
|
|
694
|
+
waitToolDefaultTimeoutMs: params.waitToolDefaultTimeoutMs,
|
|
319
695
|
effectiveAcceptance: resolveEffectiveAcceptance({
|
|
320
696
|
explicit: s.acceptance,
|
|
321
697
|
agentName: s.agent,
|
|
322
|
-
|
|
698
|
+
acceptanceRole: a.acceptanceRole,
|
|
699
|
+
task,
|
|
323
700
|
mode: resultMode,
|
|
324
701
|
async: true,
|
|
325
|
-
dynamic: false
|
|
702
|
+
dynamic: false,
|
|
703
|
+
agentContract
|
|
326
704
|
}),
|
|
705
|
+
acceptanceInput: s.acceptance,
|
|
706
|
+
acceptanceRole: a.acceptanceRole,
|
|
707
|
+
...s.gateOn ? { gateOn: s.gateOn } : {},
|
|
327
708
|
...s.outputSchema ? { structuredOutputSchema: s.outputSchema } : {},
|
|
328
|
-
...s.outputSchema ? { structuredOutput: createStructuredOutputRuntime(s.outputSchema, path.join(asyncDir, "structured-output")) } : {},
|
|
329
|
-
...resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {}
|
|
709
|
+
...s.outputSchema ? { structuredOutput: createStructuredOutputRuntime(s.outputSchema, path.join(asyncDir, "structured-output"), { captureAcceptanceReport: s.acceptance !== false }) } : {},
|
|
710
|
+
...resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {},
|
|
711
|
+
...s.worktree ? { worktree: true } : {}
|
|
330
712
|
};
|
|
331
713
|
};
|
|
332
714
|
let flatStepIndex = 0;
|
|
@@ -365,7 +747,7 @@ ${memoryInjection}` : memoryInjection;
|
|
|
365
747
|
}
|
|
366
748
|
}
|
|
367
749
|
const staticStep = nextFlatStep();
|
|
368
|
-
return buildSeqStep(t, staticStep.sessionFile, behaviorCwd, progressPrecreated, parallelBehaviors[taskIndex], staticStep.index);
|
|
750
|
+
return buildSeqStep({ ...t, agentContract: t.agentContract ?? s.agentContract, gateOn: t.gateOn ?? s.gateOn }, staticStep.sessionFile, behaviorCwd, progressPrecreated, parallelBehaviors[taskIndex], staticStep.index, { stepIndex, taskIndex }, resultMode === "parallel" ? `tasks[${taskIndex}]` : `chain[${stepIndex}].parallel[${taskIndex}]`);
|
|
369
751
|
}),
|
|
370
752
|
concurrency: s.concurrency,
|
|
371
753
|
failFast: s.failFast,
|
|
@@ -382,9 +764,10 @@ ${memoryInjection}` : memoryInjection;
|
|
|
382
764
|
}
|
|
383
765
|
const maxItems = s.expand.maxItems ?? params.dynamicFanoutMaxItems ?? 0;
|
|
384
766
|
const dynamicFlatSteps = Array.from({ length: maxItems }, () => nextFlatStep());
|
|
767
|
+
const parallel = buildSeqStep({ ...s.parallel, agentContract: s.parallel.agentContract ?? s.agentContract, gateOn: s.parallel.gateOn ?? s.gateOn }, undefined, undefined, progressPrecreated, behavior, undefined, { stepIndex });
|
|
385
768
|
return {
|
|
386
769
|
expand: s.expand,
|
|
387
|
-
parallel
|
|
770
|
+
parallel,
|
|
388
771
|
collect: s.collect,
|
|
389
772
|
concurrency: s.concurrency,
|
|
390
773
|
failFast: s.failFast,
|
|
@@ -395,15 +778,31 @@ ${memoryInjection}` : memoryInjection;
|
|
|
395
778
|
effectiveAcceptance: resolveEffectiveAcceptance({
|
|
396
779
|
explicit: s.acceptance,
|
|
397
780
|
agentName: s.parallel.agent,
|
|
398
|
-
|
|
781
|
+
acceptanceRole: agent.acceptanceRole,
|
|
782
|
+
task: parallel.task,
|
|
399
783
|
mode: resultMode,
|
|
400
784
|
async: true,
|
|
401
|
-
dynamicGroup: true
|
|
402
|
-
|
|
785
|
+
dynamicGroup: true,
|
|
786
|
+
agentContract: s.agentContract ?? params.agentContract
|
|
787
|
+
}),
|
|
788
|
+
acceptanceInput: s.acceptance,
|
|
789
|
+
acceptanceRole: agent.acceptanceRole,
|
|
790
|
+
...s.agentContract ?? params.agentContract ? { agentContract: s.agentContract ?? params.agentContract } : {},
|
|
791
|
+
...s.gateOn ? { gateOn: s.gateOn } : {},
|
|
792
|
+
...parallel.thinkingCeiling ? { thinkingCeiling: parallel.thinkingCeiling } : {}
|
|
403
793
|
};
|
|
404
794
|
}
|
|
795
|
+
const sequential = s;
|
|
796
|
+
let behaviorCwd;
|
|
797
|
+
if (sequential.worktree) {
|
|
798
|
+
try {
|
|
799
|
+
behaviorCwd = resolveExpectedWorktreeAgentCwd(runnerCwd, `${id}-s${stepIndex}`, 0, worktreeBaseDir);
|
|
800
|
+
} catch {
|
|
801
|
+
behaviorCwd = undefined;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
405
804
|
const staticStep = nextFlatStep();
|
|
406
|
-
return buildSeqStep(
|
|
805
|
+
return buildSeqStep(sequential, staticStep.sessionFile, behaviorCwd, false, undefined, staticStep.index, undefined, `chain[${stepIndex}]`);
|
|
407
806
|
});
|
|
408
807
|
const steps = params.attachRoot ? [{
|
|
409
808
|
agent: params.attachRoot.agent,
|
|
@@ -417,8 +816,24 @@ ${memoryInjection}` : memoryInjection;
|
|
|
417
816
|
index: params.attachRoot.index
|
|
418
817
|
},
|
|
419
818
|
inheritProjectContext: false,
|
|
819
|
+
inheritGlobalContext: false,
|
|
420
820
|
inheritSkills: false
|
|
421
821
|
}, ...builtSteps] : builtSteps;
|
|
822
|
+
for (const step of steps) {
|
|
823
|
+
if (!("parallel" in step) || !Array.isArray(step.parallel))
|
|
824
|
+
continue;
|
|
825
|
+
const seen = new Map;
|
|
826
|
+
for (let index = 0;index < step.parallel.length; index++) {
|
|
827
|
+
const task = step.parallel[index];
|
|
828
|
+
if (!task.outputPath)
|
|
829
|
+
continue;
|
|
830
|
+
const previous = seen.get(task.outputPath);
|
|
831
|
+
if (previous) {
|
|
832
|
+
throw new AsyncStartValidationError(`Parallel tasks ${previous.index + 1} (${previous.agent}) and ${index + 1} (${task.agent}) resolve output to the same path: ${task.outputPath}. Use distinct output paths.`);
|
|
833
|
+
}
|
|
834
|
+
seen.set(task.outputPath, { index, agent: task.agent });
|
|
835
|
+
}
|
|
836
|
+
}
|
|
422
837
|
return { steps, runnerCwd, workflowGraph, eventChain: graphChain, ...originalTask !== undefined ? { originalTask } : {} };
|
|
423
838
|
} catch (error) {
|
|
424
839
|
if (error instanceof UnavailableSubagentSkillError || error instanceof AsyncStartValidationError)
|
|
@@ -449,11 +864,26 @@ export function executeAsyncChain(id, params) {
|
|
|
449
864
|
nestedRoute
|
|
450
865
|
} = params;
|
|
451
866
|
const resultMode = params.resultMode ?? "chain";
|
|
867
|
+
const acceptanceErrors = validateExecutionAcceptance({
|
|
868
|
+
chain: chain.map((step) => {
|
|
869
|
+
if (isParallelStep(step))
|
|
870
|
+
return { parallel: step.parallel };
|
|
871
|
+
if (isDynamicParallelStep(step))
|
|
872
|
+
return { acceptance: step.acceptance, parallel: step.parallel };
|
|
873
|
+
return { acceptance: step.acceptance };
|
|
874
|
+
})
|
|
875
|
+
});
|
|
876
|
+
if (acceptanceErrors.length > 0)
|
|
877
|
+
return formatAsyncStartError(resultMode, acceptanceErrors.join(" "));
|
|
878
|
+
const capabilityCeiling = params.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId);
|
|
452
879
|
const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
|
|
453
880
|
const nestedAddress = inheritedNestedRoute ? resolveNestedParentAddressFromEnv() : undefined;
|
|
454
|
-
const asyncDir = inheritedNestedRoute ? path.join(TEMP_ROOT_DIR, "nested-subagent-runs", inheritedNestedRoute.rootRunId, id) : path.join(
|
|
881
|
+
const asyncDir = inheritedNestedRoute ? path.join(TEMP_ROOT_DIR, "nested-subagent-runs", inheritedNestedRoute.rootRunId, id) : path.join(DIRS.async, id);
|
|
882
|
+
let runFanoutBudget;
|
|
455
883
|
try {
|
|
884
|
+
runFanoutBudget = params.runFanoutBudget ?? createRunFanoutBudget(id, 64);
|
|
456
885
|
fs.mkdirSync(asyncDir, { recursive: true });
|
|
886
|
+
writeRunFanoutBudgetDescriptor(asyncDir, runFanoutBudget);
|
|
457
887
|
} catch (error) {
|
|
458
888
|
const message = error instanceof Error ? error.message : String(error);
|
|
459
889
|
return {
|
|
@@ -468,20 +898,31 @@ export function executeAsyncChain(id, params) {
|
|
|
468
898
|
attachRoot: params.attachRoot,
|
|
469
899
|
resultMode,
|
|
470
900
|
agents,
|
|
901
|
+
unknownAgentDiagnosticContext: params.unknownAgentDiagnosticContext,
|
|
471
902
|
ctx,
|
|
472
903
|
availableModels: params.availableModels,
|
|
473
904
|
cwd,
|
|
474
905
|
chainSkills: params.chainSkills,
|
|
475
906
|
sessionFilesByFlatIndex,
|
|
476
907
|
thinkingOverridesByFlatIndex,
|
|
908
|
+
contextForAgent: params.contextForAgent,
|
|
477
909
|
progressDir: params.progressDir ?? (artifactsDir ? path.join(artifactsDir, "progress", id) : resultMode === "parallel" ? path.join(asyncDir, "progress") : undefined),
|
|
910
|
+
agentContract: params.agentContract,
|
|
478
911
|
outputBaseDir: artifactsDir ? path.join(artifactsDir, "outputs", id) : undefined,
|
|
479
912
|
dynamicFanoutMaxItems: params.dynamicFanoutMaxItems,
|
|
480
913
|
maxSubagentDepth,
|
|
914
|
+
waitToolEnabled: params.waitToolEnabled,
|
|
915
|
+
waitToolDefaultTimeoutMs: params.waitToolDefaultTimeoutMs,
|
|
481
916
|
worktreeBaseDir,
|
|
482
917
|
asyncDir,
|
|
918
|
+
fast: params.fast,
|
|
483
919
|
toolBudget: params.toolBudget,
|
|
484
|
-
configToolBudget: params.configToolBudget
|
|
920
|
+
configToolBudget: params.configToolBudget,
|
|
921
|
+
callToolTimeoutMs: params.callToolTimeoutMs,
|
|
922
|
+
configToolTimeoutMs: params.configToolTimeoutMs,
|
|
923
|
+
toolTimeoutMsEnv: params.toolTimeoutMsEnv ?? toolTimeoutFromEnv(),
|
|
924
|
+
capabilityCeiling,
|
|
925
|
+
thinkingCeiling: params.thinkingCeiling
|
|
485
926
|
});
|
|
486
927
|
if ("error" in built) {
|
|
487
928
|
try {
|
|
@@ -491,10 +932,10 @@ export function executeAsyncChain(id, params) {
|
|
|
491
932
|
}
|
|
492
933
|
const { steps, runnerCwd, workflowGraph, eventChain } = built;
|
|
493
934
|
const deadlineAt = params.timeoutMs !== undefined ? Date.now() + params.timeoutMs : undefined;
|
|
494
|
-
const
|
|
935
|
+
const initialUsageBudget = usageBudgetState(params.usageBudget, undefined);
|
|
495
936
|
let childTargetIndex = 0;
|
|
496
937
|
const childIntercomTargets = childIntercomTarget ? steps.flatMap((step) => {
|
|
497
|
-
if (!("parallel" in step) && step.importAsyncRoot) {
|
|
938
|
+
if (!("parallel" in step) && "importAsyncRoot" in step && step.importAsyncRoot) {
|
|
498
939
|
childTargetIndex++;
|
|
499
940
|
return [undefined];
|
|
500
941
|
}
|
|
@@ -505,14 +946,27 @@ export function executeAsyncChain(id, params) {
|
|
|
505
946
|
}
|
|
506
947
|
return step.parallel.map((task) => childIntercomTarget(task.agent, childTargetIndex++));
|
|
507
948
|
}
|
|
508
|
-
return [childIntercomTarget(step.agent, childTargetIndex++)];
|
|
949
|
+
return "agent" in step ? [childIntercomTarget(step.agent, childTargetIndex++)] : [undefined];
|
|
509
950
|
}) : undefined;
|
|
951
|
+
const initialStatusSteps = eventChain.flatMap((step) => isParallelStep(step) ? step.parallel.map((task) => ({ agent: task.agent, ...statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}, ...task.label ? { label: task.label } : {}, ...task.as ? { outputName: task.as } : {}, status: "pending" })) : isDynamicParallelStep(step) ? [{ agent: `expand:${step.parallel.agent}`, label: step.label ?? step.parallel.label ?? `Dynamic fanout (${step.collect.as})`, outputName: step.collect.as, status: "pending" }] : [{ agent: step.agent, ...statusStepDescription(step.task) ? { description: statusStepDescription(step.task) } : {}, ...step.label ? { label: step.label } : {}, ...step.as ? { outputName: step.as } : {}, status: "pending" }]);
|
|
952
|
+
const initialParallelGroups = [];
|
|
953
|
+
let initialFlatIndex = 0;
|
|
954
|
+
for (let stepIndex = 0;stepIndex < eventChain.length; stepIndex++) {
|
|
955
|
+
const step = eventChain[stepIndex];
|
|
956
|
+
if (isParallelStep(step))
|
|
957
|
+
initialParallelGroups.push({ start: initialFlatIndex, count: step.parallel.length, stepIndex });
|
|
958
|
+
else if (isDynamicParallelStep(step))
|
|
959
|
+
initialParallelGroups.push({ start: initialFlatIndex, count: 1, stepIndex });
|
|
960
|
+
initialFlatIndex += isParallelStep(step) ? step.parallel.length : 1;
|
|
961
|
+
}
|
|
962
|
+
const initialStatusAt = Date.now();
|
|
963
|
+
const initialCompletionOwnerId = ctx.completionOwnerId ?? currentCompletionOwnerId();
|
|
510
964
|
let spawnResult = {};
|
|
511
965
|
try {
|
|
512
966
|
spawnResult = spawnRunner({
|
|
513
967
|
id,
|
|
514
968
|
steps,
|
|
515
|
-
resultPath: inheritedNestedRoute ? nestedResultsPath(inheritedNestedRoute.rootRunId, id) :
|
|
969
|
+
resultPath: inheritedNestedRoute ? nestedResultsPath(inheritedNestedRoute.rootRunId, id) : resultFilePath(DIRS.results, id),
|
|
516
970
|
cwd: runnerCwd,
|
|
517
971
|
placeholder: "{previous}",
|
|
518
972
|
maxOutput,
|
|
@@ -522,14 +976,16 @@ export function executeAsyncChain(id, params) {
|
|
|
522
976
|
sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
|
|
523
977
|
asyncDir,
|
|
524
978
|
sessionId: ctx.currentSessionId,
|
|
979
|
+
completionOwnerId: ctx.completionOwnerId ?? currentCompletionOwnerId(),
|
|
980
|
+
...capabilityCeiling ? { capabilityCeiling } : {},
|
|
525
981
|
piPackageRoot,
|
|
526
982
|
piArgv1: process.argv[1],
|
|
527
983
|
worktreeSetupHook,
|
|
528
984
|
worktreeSetupHookTimeoutMs,
|
|
529
985
|
worktreeBaseDir,
|
|
530
986
|
controlConfig,
|
|
531
|
-
turnBudget: params.turnBudget,
|
|
532
987
|
toolBudget: params.toolBudget,
|
|
988
|
+
usageBudget: params.usageBudget,
|
|
533
989
|
controlIntercomTarget,
|
|
534
990
|
childIntercomTargets,
|
|
535
991
|
resultMode,
|
|
@@ -537,7 +993,10 @@ export function executeAsyncChain(id, params) {
|
|
|
537
993
|
timeoutMs: params.timeoutMs,
|
|
538
994
|
deadlineAt,
|
|
539
995
|
globalConcurrencyLimit: params.globalConcurrencyLimit,
|
|
996
|
+
runFanoutBudget,
|
|
540
997
|
workflowGraph,
|
|
998
|
+
...params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {},
|
|
999
|
+
...params.workflowKey ? { workflowKey: params.workflowKey } : {},
|
|
541
1000
|
nestedRoute: nestedRoute ?? inheritedNestedRoute,
|
|
542
1001
|
nestedSelf: inheritedNestedRoute && nestedAddress ? {
|
|
543
1002
|
parentRunId: nestedAddress.parentRunId,
|
|
@@ -545,17 +1004,45 @@ export function executeAsyncChain(id, params) {
|
|
|
545
1004
|
depth: nestedAddress.depth,
|
|
546
1005
|
path: nestedAddress.path
|
|
547
1006
|
} : undefined
|
|
548
|
-
}, id, runnerCwd
|
|
1007
|
+
}, id, runnerCwd, {
|
|
1008
|
+
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
1009
|
+
runId: id,
|
|
1010
|
+
...ctx.currentSessionId ? { sessionId: ctx.currentSessionId } : {},
|
|
1011
|
+
...initialCompletionOwnerId ? { completionOwnerId: initialCompletionOwnerId } : {},
|
|
1012
|
+
mode: resultMode,
|
|
1013
|
+
state: "running",
|
|
1014
|
+
startedAt: initialStatusAt,
|
|
1015
|
+
lastUpdate: initialStatusAt,
|
|
1016
|
+
currentStep: 0,
|
|
1017
|
+
chainStepCount: eventChain.length,
|
|
1018
|
+
...initialParallelGroups.length ? { parallelGroups: initialParallelGroups } : {},
|
|
1019
|
+
steps: initialStatusSteps
|
|
1020
|
+
}, path.join(asyncDir, "status.json"), (proof) => emitProcessTerminalEvent(ctx, proof));
|
|
549
1021
|
} catch (error) {
|
|
1022
|
+
params.activeAsyncCapacity?.rollback();
|
|
550
1023
|
const message = error instanceof Error ? error.message : String(error);
|
|
551
1024
|
return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': ${message}`);
|
|
552
1025
|
}
|
|
553
1026
|
if (spawnResult.error) {
|
|
1027
|
+
if (!spawnResult.pid || !spawnResult.runnerProcessInstanceId || spawnResult.startupDidNotProceed && spawnResult.terminationObserved)
|
|
1028
|
+
params.activeAsyncCapacity?.rollback();
|
|
1029
|
+
else
|
|
1030
|
+
params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
554
1031
|
return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': ${spawnResult.error}`);
|
|
555
1032
|
}
|
|
1033
|
+
if (!spawnResult.pid || !spawnResult.runnerProcessInstanceId) {
|
|
1034
|
+
params.activeAsyncCapacity?.rollback();
|
|
1035
|
+
return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': runner identity unavailable`);
|
|
1036
|
+
}
|
|
1037
|
+
params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
556
1038
|
if (spawnResult.pid) {
|
|
557
1039
|
const eventFirstStep = eventChain[0];
|
|
1040
|
+
if (!eventFirstStep) {
|
|
1041
|
+
return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': event chain has no steps`);
|
|
1042
|
+
}
|
|
558
1043
|
const firstAgents = isParallelStep(eventFirstStep) ? eventFirstStep.parallel.map((t) => t.agent) : isDynamicParallelStep(eventFirstStep) ? [eventFirstStep.parallel.agent] : [eventFirstStep.agent];
|
|
1044
|
+
const firstTask = isParallelStep(eventFirstStep) ? eventFirstStep.parallel[0]?.task : isDynamicParallelStep(eventFirstStep) ? eventFirstStep.parallel.task : eventFirstStep.task;
|
|
1045
|
+
const workflowGoal = params.goal ?? (params.task?.trim() || firstTask);
|
|
559
1046
|
const parallelGroups = [];
|
|
560
1047
|
const flatAgents = [];
|
|
561
1048
|
let flatStepStart = 0;
|
|
@@ -601,41 +1088,50 @@ export function executeAsyncChain(id, params) {
|
|
|
601
1088
|
chainStepCount: eventChain.length,
|
|
602
1089
|
parallelGroups,
|
|
603
1090
|
...params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {},
|
|
604
|
-
...initialTurnBudget ? { turnBudget: initialTurnBudget } : {},
|
|
605
1091
|
startedAt: now,
|
|
606
|
-
lastUpdate: now
|
|
1092
|
+
lastUpdate: now,
|
|
1093
|
+
...capabilityCeiling ? { capabilityCeiling } : {}
|
|
607
1094
|
}
|
|
608
1095
|
});
|
|
609
1096
|
} catch (error) {
|
|
610
1097
|
console.error("Failed to emit nested async start event:", error);
|
|
611
1098
|
}
|
|
612
1099
|
}
|
|
613
|
-
ctx.
|
|
1100
|
+
ctx.dm.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
|
|
614
1101
|
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
615
1102
|
id,
|
|
616
1103
|
pid: spawnResult.pid,
|
|
617
1104
|
sessionId: ctx.currentSessionId,
|
|
1105
|
+
completionOwnerId: ctx.completionOwnerId ?? currentCompletionOwnerId(),
|
|
618
1106
|
mode: resultMode,
|
|
619
1107
|
agent: firstAgents[0],
|
|
620
1108
|
agents: flatAgents,
|
|
621
|
-
task:
|
|
1109
|
+
task: firstTask?.trim() ? PROMPT_REDACTED : undefined,
|
|
1110
|
+
goal: workflowGoal?.trim() ? PROMPT_REDACTED : undefined,
|
|
622
1111
|
chain: eventChain.map((s) => isParallelStep(s) ? `[${s.parallel.map((t) => t.agent).join("+")}]` : isDynamicParallelStep(s) ? `expand:${s.parallel.agent}` : s.agent),
|
|
623
1112
|
chainStepCount: eventChain.length,
|
|
624
1113
|
parallelGroups,
|
|
625
1114
|
workflowGraph,
|
|
626
1115
|
cwd: runnerCwd,
|
|
627
1116
|
asyncDir,
|
|
1117
|
+
...sessionRoot ? { sessionRoot } : {},
|
|
628
1118
|
...params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {},
|
|
629
|
-
...
|
|
1119
|
+
...initialUsageBudget ? { usageBudget: initialUsageBudget } : {},
|
|
1120
|
+
...capabilityCeiling ? { capabilityCeiling } : {},
|
|
1121
|
+
...params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {},
|
|
1122
|
+
...params.workflowKey ? { workflowKey: params.workflowKey } : {},
|
|
630
1123
|
nestedRoute
|
|
631
1124
|
});
|
|
632
1125
|
}
|
|
633
1126
|
const chainDesc = chain.map((s) => isParallelStep(s) ? `[${s.parallel.map((t) => t.agent).join("+")}]` : isDynamicParallelStep(s) ? `expand:${s.parallel.agent}` : s.agent).join(" -> ");
|
|
634
1127
|
return {
|
|
635
|
-
content: [{ type: "text", text: formatAsyncStartedMessage(`Async ${resultMode}: ${chainDesc} [${id}]
|
|
636
|
-
details: { mode: resultMode, runId: id, results: [], asyncId: id, asyncDir, workflowGraph, ...params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}, ...params.
|
|
1128
|
+
content: [{ type: "text", text: formatAsyncStartedMessage(`Async ${resultMode}: ${chainDesc} [${id}]`, ctx.interactive === true) }],
|
|
1129
|
+
details: { mode: resultMode, runId: id, results: [], asyncId: id, asyncDir, workflowGraph, ...capabilityCeiling ? { capabilityCeiling } : {}, ...params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {}, ...params.workflowKey ? { workflowKey: params.workflowKey } : {}, ...params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}, ...params.toolBudget ? { toolBudget: params.toolBudget } : {}, ...initialUsageBudget ? { usageBudget: initialUsageBudget } : {} }
|
|
637
1130
|
};
|
|
638
1131
|
}
|
|
1132
|
+
export function workflowAwaitedAsyncResultPath(asyncDir) {
|
|
1133
|
+
return path.join(asyncDir, "workflow-result.json");
|
|
1134
|
+
}
|
|
639
1135
|
export function executeAsyncSingle(id, params) {
|
|
640
1136
|
const {
|
|
641
1137
|
agent,
|
|
@@ -657,11 +1153,63 @@ export function executeAsyncSingle(id, params) {
|
|
|
657
1153
|
childIntercomTarget,
|
|
658
1154
|
nestedRoute
|
|
659
1155
|
} = params;
|
|
1156
|
+
let lane;
|
|
1157
|
+
try {
|
|
1158
|
+
lane = normalizeWorkflowLaneMetadata(params.lane, "lane");
|
|
1159
|
+
assertWorkflowLaneKey(lane, params.workflowKey, "lane");
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1162
|
+
}
|
|
660
1163
|
const task = params.task ?? "";
|
|
1164
|
+
let extensionBindings;
|
|
1165
|
+
try {
|
|
1166
|
+
extensionBindings = normalizeExtensionBindings(params.extensionBindings)?.value;
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1169
|
+
}
|
|
1170
|
+
const acceptanceErrors = validateAcceptanceInput(params.acceptance);
|
|
1171
|
+
if (acceptanceErrors.length > 0)
|
|
1172
|
+
return formatAsyncStartError("single", acceptanceErrors.join(" "));
|
|
1173
|
+
const externalRunner = agentConfig.runner?.type === "external-cli" || agentConfig.runner?.type === "external-job";
|
|
1174
|
+
const externalRunnerType = agentConfig.runner?.type;
|
|
1175
|
+
const permissionRules = resolvePermissionRules(ctx.permissions, agentConfig.permissions);
|
|
1176
|
+
if (externalRunner) {
|
|
1177
|
+
const unsupported = [];
|
|
1178
|
+
if (params.modelOverride !== undefined)
|
|
1179
|
+
unsupported.push("model override");
|
|
1180
|
+
if ((params.fast ?? agentConfig.fast) === true)
|
|
1181
|
+
unsupported.push("fast mode");
|
|
1182
|
+
if (params.thinkingOverride !== undefined)
|
|
1183
|
+
unsupported.push("thinking override");
|
|
1184
|
+
if (params.structuredOutputSchema !== undefined)
|
|
1185
|
+
unsupported.push("structured output");
|
|
1186
|
+
if (params.acceptance !== undefined || params.agentContract !== undefined)
|
|
1187
|
+
unsupported.push("acceptance/agent contract");
|
|
1188
|
+
if (params.toolBudget !== undefined || agentConfig.toolBudget !== undefined || params.configToolBudget !== undefined)
|
|
1189
|
+
unsupported.push("tool budget");
|
|
1190
|
+
if (params.context === "fork")
|
|
1191
|
+
unsupported.push("fork context");
|
|
1192
|
+
if ((params.skills?.length ?? 0) > 0)
|
|
1193
|
+
unsupported.push("skills");
|
|
1194
|
+
if (permissionRules)
|
|
1195
|
+
unsupported.push("native DM child permissions");
|
|
1196
|
+
if (extensionBindings !== undefined)
|
|
1197
|
+
unsupported.push("extension bindings");
|
|
1198
|
+
if (unsupported.length > 0)
|
|
1199
|
+
return formatAsyncStartError("single", `Agent '${agentConfig.name}' uses runner.type='${externalRunnerType}' and does not support: ${unsupported.join(", ")}.`);
|
|
1200
|
+
}
|
|
1201
|
+
const capabilityCeiling = intersectSubagentCapabilityCeilings(params.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId), decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]));
|
|
1202
|
+
try {
|
|
1203
|
+
assertAgentAllowedByCapabilityCeiling(agentConfig.name, capabilityCeiling);
|
|
1204
|
+
} catch (error) {
|
|
1205
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1206
|
+
}
|
|
661
1207
|
const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
|
|
1208
|
+
const instructionCwd = params.worktree === true ? resolveExpectedWorktreeAgentCwd(runnerCwd, `${id}-s0`, 0, worktreeBaseDir) : runnerCwd;
|
|
1209
|
+
const readExistenceCwd = params.worktree === true ? runnerCwd : instructionCwd;
|
|
662
1210
|
const skillNames = params.skills ?? agentConfig.skills ?? [];
|
|
663
1211
|
const availableModels = params.availableModels;
|
|
664
|
-
const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(skillNames, runnerCwd, ctx.cwd);
|
|
1212
|
+
const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(skillNames, runnerCwd, ctx.cwd, agentConfig.skillPath, agentConfig.filePath ? path.dirname(agentConfig.filePath) : runnerCwd);
|
|
665
1213
|
if (missingSkills.includes("dm-subagents"))
|
|
666
1214
|
return formatAsyncStartError("single", UNAVAILABLE_SUBAGENT_SKILL_ERROR);
|
|
667
1215
|
let systemPrompt = agentConfig.systemPrompt?.trim() ?? "";
|
|
@@ -677,11 +1225,15 @@ ${injection}` : injection;
|
|
|
677
1225
|
|
|
678
1226
|
${memoryInjection}` : memoryInjection;
|
|
679
1227
|
}
|
|
1228
|
+
systemPrompt = appendAgentRefinementOverlay(systemPrompt, { cwd: runnerCwd, agentName: agentConfig.name });
|
|
680
1229
|
const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
|
|
681
1230
|
const nestedAddress = inheritedNestedRoute ? resolveNestedParentAddressFromEnv() : undefined;
|
|
682
|
-
const asyncDir = inheritedNestedRoute ? path.join(TEMP_ROOT_DIR, "nested-subagent-runs", inheritedNestedRoute.rootRunId, id) : path.join(
|
|
1231
|
+
const asyncDir = inheritedNestedRoute ? path.join(TEMP_ROOT_DIR, "nested-subagent-runs", inheritedNestedRoute.rootRunId, id) : path.join(DIRS.async, id);
|
|
1232
|
+
let runFanoutBudget;
|
|
683
1233
|
try {
|
|
1234
|
+
runFanoutBudget = params.runFanoutBudget ?? createRunFanoutBudget(id, 64);
|
|
684
1235
|
fs.mkdirSync(asyncDir, { recursive: true });
|
|
1236
|
+
writeRunFanoutBudgetDescriptor(asyncDir, runFanoutBudget);
|
|
685
1237
|
} catch (error) {
|
|
686
1238
|
const message = error instanceof Error ? error.message : String(error);
|
|
687
1239
|
return {
|
|
@@ -691,82 +1243,287 @@ ${memoryInjection}` : memoryInjection;
|
|
|
691
1243
|
};
|
|
692
1244
|
}
|
|
693
1245
|
const effectiveOutput = normalizeSingleOutputOverride(params.output, agentConfig.output);
|
|
694
|
-
const outputPath = resolveSingleOutputPath(effectiveOutput, ctx.cwd,
|
|
695
|
-
systemPrompt = injectOutputPathSystemPrompt(systemPrompt, outputPath);
|
|
696
|
-
const outputMode = params.outputMode ?? "inline";
|
|
1246
|
+
const outputPath = resolveSingleOutputPath(effectiveOutput, ctx.cwd, instructionCwd, params.outputBaseDir ?? (artifactsDir ? path.join(artifactsDir, "outputs", id) : undefined));
|
|
1247
|
+
systemPrompt = injectOutputPathSystemPrompt(systemPrompt, outputPath, agentConfig);
|
|
1248
|
+
const outputMode = params.outputMode ?? agentConfig.outputMode ?? "inline";
|
|
697
1249
|
const validationError = validateFileOnlyOutputMode(outputMode, outputPath, `Async single run (${agent})`);
|
|
698
1250
|
if (validationError)
|
|
699
1251
|
return formatAsyncStartError("single", validationError);
|
|
700
|
-
const taskWithOutputInstruction = injectSingleOutputInstruction(task, outputPath);
|
|
701
|
-
const
|
|
702
|
-
const
|
|
703
|
-
const
|
|
1252
|
+
const taskWithOutputInstruction = injectSingleOutputInstruction(task, outputPath, agentConfig);
|
|
1253
|
+
const reads = params.reads !== undefined ? params.reads : agentConfig.defaultReads ?? false;
|
|
1254
|
+
const readPaths = Array.isArray(reads) ? resolveExistingReadPaths(reads, readExistenceCwd) : [];
|
|
1255
|
+
const readsInstruction = readPaths.length > 0 ? `[Read from: ${readPaths.join(", ")}]
|
|
1256
|
+
|
|
1257
|
+
` : "";
|
|
1258
|
+
const taskText = readsInstruction + taskWithOutputInstruction;
|
|
1259
|
+
const modelScopes = resolveModelScopesForAgent(ctx.modelScope, agentConfig.name, ctx.currentModel);
|
|
1260
|
+
const primaryModel = externalRunner ? undefined : params.modelOverrideFromParent ? params.modelOverride : resolveSubagentModelOverride(params.modelOverride ?? agentConfig.model, ctx.currentModel, availableModels, ctx.currentModelProvider, { scope: modelScopes });
|
|
1261
|
+
const effectiveThinking = externalRunner ? undefined : params.thinkingOverride ?? agentConfig.thinking;
|
|
1262
|
+
const model = externalRunner ? undefined : applyThinkingSuffix(primaryModel, effectiveThinking, params.thinkingOverride !== undefined);
|
|
1263
|
+
const contextLimit = model ? findModelInfo(model, availableModels, agentConfig.modelProvider ?? ctx.currentModelProvider)?.contextWindow : undefined;
|
|
1264
|
+
const thinkingCeiling = externalRunner ? undefined : intersectThinkingCeilings(params.thinkingCeiling, agentConfig.maxThinking, decodeThinkingCeiling(process.env[SUBAGENT_THINKING_CEILING_ENV]));
|
|
1265
|
+
if (!externalRunner) {
|
|
1266
|
+
try {
|
|
1267
|
+
assertThinkingWithinCeiling({ model, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: agentConfig.name, runId: id });
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
704
1272
|
const toolBudgetInput = params.toolBudget ?? agentConfig.toolBudget ?? params.configToolBudget;
|
|
705
1273
|
const resolvedToolBudget = validateToolBudgetConfig(toolBudgetInput, params.toolBudget ? "toolBudget" : agentConfig.toolBudget ? "agent.toolBudget" : "config.toolBudget");
|
|
706
1274
|
if (resolvedToolBudget.error)
|
|
707
1275
|
return formatAsyncStartError("single", resolvedToolBudget.error);
|
|
708
|
-
const deadlineAt = params.timeoutMs !== undefined ? Date.now() + params.timeoutMs : undefined;
|
|
709
|
-
const
|
|
1276
|
+
const deadlineAt = params.absoluteDeadlineAt ?? (params.timeoutMs !== undefined ? Date.now() + params.timeoutMs : undefined);
|
|
1277
|
+
const timeoutMs = params.absoluteDeadlineAt !== undefined && deadlineAt !== undefined ? deadlineAt - Date.now() : params.timeoutMs;
|
|
1278
|
+
if (timeoutMs !== undefined && timeoutMs <= 0)
|
|
1279
|
+
return formatAsyncStartError("single", "The source run's absolute deadline expired before recovery could launch.");
|
|
1280
|
+
const resolvedToolTimeout = resolveToolTimeoutMs({
|
|
1281
|
+
callValue: params.toolTimeoutMs,
|
|
1282
|
+
agentValue: agentConfig.defaultToolTimeoutMs,
|
|
1283
|
+
configValue: params.configToolTimeoutMs,
|
|
1284
|
+
envValue: params.toolTimeoutMsEnv ?? toolTimeoutFromEnv()
|
|
1285
|
+
});
|
|
1286
|
+
if (resolvedToolTimeout.error)
|
|
1287
|
+
return formatAsyncStartError("single", resolvedToolTimeout.error);
|
|
1288
|
+
const toolTimeoutMs = resolvedToolTimeout.toolTimeoutMs;
|
|
1289
|
+
const initialUsageBudget = usageBudgetState(params.usageBudget, undefined);
|
|
1290
|
+
const resolvedSessionDir = params.sessionDir ?? (sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined);
|
|
1291
|
+
const structuredOutput = params.structuredOutputSchema ? createStructuredOutputRuntime(params.structuredOutputSchema, path.join(asyncDir, "structured-output"), { captureAcceptanceReport: params.acceptance !== false }) : undefined;
|
|
1292
|
+
const modelCandidates = externalRunner ? [] : buildModelCandidates(primaryModel, agentConfig.fallbackModels, availableModels, agentConfig.modelProvider ?? ctx.currentModelProvider, {
|
|
1293
|
+
scope: modelScopes,
|
|
1294
|
+
primaryModelFromParent: params.modelOverrideFromParent
|
|
1295
|
+
}).flatMap((candidate) => {
|
|
1296
|
+
const resolved = applyThinkingSuffix(candidate, effectiveThinking, params.thinkingOverride !== undefined);
|
|
1297
|
+
return resolved ? [resolved] : [];
|
|
1298
|
+
});
|
|
1299
|
+
if (!externalRunner) {
|
|
1300
|
+
try {
|
|
1301
|
+
for (const candidate of modelCandidates)
|
|
1302
|
+
assertThinkingWithinCeiling({ model: candidate, configThinking: effectiveThinking, ceiling: thinkingCeiling, agent: agentConfig.name, runId: id });
|
|
1303
|
+
} catch (error) {
|
|
1304
|
+
return formatAsyncStartError("single", error instanceof Error ? error.message : String(error));
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
const toolPlan = resolvePiLaunchToolPlan({
|
|
1308
|
+
tools: agentConfig.tools,
|
|
1309
|
+
allowNestedSubagents: agentConfig.allowNestedSubagents,
|
|
1310
|
+
extensions: agentConfig.extensions,
|
|
1311
|
+
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
1312
|
+
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
1313
|
+
cwd: runnerCwd,
|
|
1314
|
+
requireReadTool: Boolean(resolvedSkills.length),
|
|
1315
|
+
structuredOutput: Boolean(params.structuredOutputSchema),
|
|
1316
|
+
fast: params.fast ?? agentConfig.fast,
|
|
1317
|
+
model,
|
|
1318
|
+
modelCandidates,
|
|
1319
|
+
capabilityCeiling,
|
|
1320
|
+
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
1321
|
+
agentName: agentConfig.name,
|
|
1322
|
+
permissionRules: resolvePermissionRules(ctx.permissions, agentConfig.permissions),
|
|
1323
|
+
runtimeSnapshotHost: ctx.dm
|
|
1324
|
+
});
|
|
1325
|
+
const launchResolvedExtensions = externalRunner ? undefined : projectLaunchResolvedChildExtensions(toolPlan);
|
|
1326
|
+
if (!externalRunner) {
|
|
1327
|
+
const contractTools = toolPlan.explicitToolAllowlist ? toolPlan.effectiveToolAllowlist : undefined;
|
|
1328
|
+
const contractError = validateImplementationToolContract({
|
|
1329
|
+
agent: agentConfig.name,
|
|
1330
|
+
task: taskText,
|
|
1331
|
+
tools: contractTools,
|
|
1332
|
+
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
1333
|
+
configuredExtensions: toolPlan.configuredExtensions,
|
|
1334
|
+
requestedTools: toolPlan.requestedBuiltinTools,
|
|
1335
|
+
acceptanceRole: agentConfig.acceptanceRole,
|
|
1336
|
+
completionGuard: agentConfig.completionGuard
|
|
1337
|
+
});
|
|
1338
|
+
if (contractError)
|
|
1339
|
+
return formatAsyncStartError("single", contractError);
|
|
1340
|
+
}
|
|
1341
|
+
const launchContractDigest = launchBindingDigest({
|
|
1342
|
+
definitionDigest: agentDefinitionDigest(agentConfig),
|
|
1343
|
+
task,
|
|
1344
|
+
...model ? { model } : {},
|
|
1345
|
+
modelCandidates,
|
|
1346
|
+
...(params.fast ?? agentConfig.fast) !== undefined ? { fast: params.fast ?? agentConfig.fast } : {},
|
|
1347
|
+
...resolveEffectiveThinking(model, effectiveThinking) ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {},
|
|
1348
|
+
...thinkingCeiling ? { thinkingCeiling } : {},
|
|
1349
|
+
systemPrompt,
|
|
1350
|
+
systemPromptMode: agentConfig.systemPromptMode,
|
|
1351
|
+
inheritProjectContext: agentConfig.inheritProjectContext,
|
|
1352
|
+
inheritGlobalContext: agentConfig.inheritGlobalContext,
|
|
1353
|
+
inheritSkills: agentConfig.inheritSkills,
|
|
1354
|
+
skills: resolvedSkills.map((skill) => skill.name),
|
|
1355
|
+
tools: toolPlan.effectiveToolAllowlist,
|
|
1356
|
+
extensions: toolPlan.extensionArgs,
|
|
1357
|
+
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
1358
|
+
...outputPath ? { outputPath } : {},
|
|
1359
|
+
outputMode,
|
|
1360
|
+
...params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {},
|
|
1361
|
+
...extensionBindings ? { extensionBindings } : {}
|
|
1362
|
+
});
|
|
1363
|
+
const resolvedAcceptance = resolveEffectiveAcceptance({
|
|
1364
|
+
explicit: params.acceptance,
|
|
1365
|
+
agentName: agent,
|
|
1366
|
+
acceptanceRole: agentConfig.acceptanceRole,
|
|
1367
|
+
task,
|
|
1368
|
+
mode: "single",
|
|
1369
|
+
async: true,
|
|
1370
|
+
agentContract: params.agentContract
|
|
1371
|
+
});
|
|
1372
|
+
const recoveryAgentConfig = params.recoveryAgentConfig ?? agentConfig;
|
|
1373
|
+
const recoveryDescriptor = {
|
|
1374
|
+
version: 1,
|
|
1375
|
+
...lane ? { lane } : {},
|
|
1376
|
+
launchContractDigest,
|
|
1377
|
+
...extensionBindings ? { extensionBindings } : {},
|
|
1378
|
+
runFanoutBudget,
|
|
1379
|
+
sourceRunId: id,
|
|
1380
|
+
...params.agentContract ? { agentContract: params.agentContract } : {},
|
|
1381
|
+
agent,
|
|
1382
|
+
launchResolvedExtensions,
|
|
1383
|
+
...sessionFile ? { sessionFile } : {},
|
|
1384
|
+
cwd: runnerCwd,
|
|
1385
|
+
...model ? { model } : {},
|
|
1386
|
+
...params.fast ?? recoveryAgentConfig.fast ? { fast: params.fast ?? recoveryAgentConfig.fast } : {},
|
|
1387
|
+
...recoveryAgentConfig.modelProvider ? { modelProvider: recoveryAgentConfig.modelProvider } : {},
|
|
1388
|
+
...params.modelOverrideFromParent ? { modelOverrideFromParent: true } : {},
|
|
1389
|
+
...recoveryAgentConfig.fallbackModels ? { fallbackModels: [...recoveryAgentConfig.fallbackModels] } : {},
|
|
1390
|
+
...effectiveThinking ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {},
|
|
1391
|
+
...thinkingCeiling ? { thinkingCeiling } : {},
|
|
1392
|
+
...recoveryAgentConfig.tools ? { tools: [...recoveryAgentConfig.tools] } : {},
|
|
1393
|
+
...recoveryAgentConfig.allowNestedSubagents !== undefined ? { allowNestedSubagents: recoveryAgentConfig.allowNestedSubagents } : {},
|
|
1394
|
+
...recoveryAgentConfig.extensions ? { extensions: [...recoveryAgentConfig.extensions] } : {},
|
|
1395
|
+
...recoveryAgentConfig.subagentOnlyExtensions ? { subagentOnlyExtensions: [...recoveryAgentConfig.subagentOnlyExtensions] } : {},
|
|
1396
|
+
...recoveryAgentConfig.mcpDirectTools ? { mcpDirectTools: [...recoveryAgentConfig.mcpDirectTools] } : {},
|
|
1397
|
+
...recoveryAgentConfig.mutationTools ? { mutationTools: [...recoveryAgentConfig.mutationTools] } : {},
|
|
1398
|
+
...recoveryAgentConfig.systemPrompt ? { systemPrompt: recoveryAgentConfig.systemPrompt } : {},
|
|
1399
|
+
systemPromptMode: recoveryAgentConfig.systemPromptMode,
|
|
1400
|
+
inheritProjectContext: recoveryAgentConfig.inheritProjectContext,
|
|
1401
|
+
inheritGlobalContext: recoveryAgentConfig.inheritGlobalContext,
|
|
1402
|
+
inheritSkills: recoveryAgentConfig.inheritSkills,
|
|
1403
|
+
...resolvedSkills.length ? { skills: resolvedSkills.map((skill) => skill.name) } : {},
|
|
1404
|
+
...recoveryAgentConfig.skillPath ? { skillPath: [...recoveryAgentConfig.skillPath] } : {},
|
|
1405
|
+
...recoveryAgentConfig.filePath ? { agentFilePath: recoveryAgentConfig.filePath } : {},
|
|
1406
|
+
...recoveryAgentConfig.completionGuard !== undefined ? { completionGuard: recoveryAgentConfig.completionGuard } : {},
|
|
1407
|
+
...recoveryAgentConfig.memory ? { memory: { ...recoveryAgentConfig.memory } } : {},
|
|
1408
|
+
...outputPath ? { outputPath } : {},
|
|
1409
|
+
outputMode,
|
|
1410
|
+
...params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {},
|
|
1411
|
+
...params.acceptance !== undefined ? { acceptance: params.acceptance } : {},
|
|
1412
|
+
...controlConfig ? { controlConfig } : {},
|
|
1413
|
+
...params.context ? { context: params.context } : {},
|
|
1414
|
+
...params.intercomBridge !== undefined ? { intercomBridge: params.intercomBridge } : {},
|
|
1415
|
+
...deadlineAt !== undefined ? { absoluteDeadlineAt: deadlineAt } : {},
|
|
1416
|
+
...resolvedToolBudget.budget ? { initialToolBudget: resolvedToolBudget.budget } : {},
|
|
1417
|
+
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, recoveryAgentConfig.maxSubagentDepth),
|
|
1418
|
+
...maxOutput ? { maxOutput } : {},
|
|
1419
|
+
share: shareEnabled,
|
|
1420
|
+
...resolvedSessionDir ? { sessionDir: resolvedSessionDir } : {},
|
|
1421
|
+
...artifactsDir ? { artifactsDir } : {},
|
|
1422
|
+
artifactConfig,
|
|
1423
|
+
...capabilityCeiling ? { capabilityCeiling } : {}
|
|
1424
|
+
};
|
|
1425
|
+
if (!externalRunner) {
|
|
1426
|
+
try {
|
|
1427
|
+
writePrivateAtomicJson(path.join(asyncDir, "recovery-descriptor.json"), recoveryDescriptor);
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
return formatAsyncStartError("single", `Failed to persist async recovery descriptor for '${id}': ${error instanceof Error ? error.message : String(error)}`);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
710
1432
|
let spawnResult = {};
|
|
1433
|
+
const initialStatusAt = Date.now();
|
|
1434
|
+
const initialCompletionOwnerId = ctx.completionOwnerId ?? currentCompletionOwnerId();
|
|
711
1435
|
try {
|
|
712
1436
|
spawnResult = spawnRunner({
|
|
713
1437
|
id,
|
|
714
1438
|
steps: [
|
|
715
1439
|
{
|
|
716
1440
|
parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
|
|
1441
|
+
permissionRules,
|
|
1442
|
+
...capabilityCeiling ? { capabilityCeiling } : {},
|
|
717
1443
|
agent,
|
|
718
|
-
task:
|
|
1444
|
+
task: taskText,
|
|
1445
|
+
...agentConfig.runner ? { runner: agentConfig.runner } : {},
|
|
1446
|
+
...params.externalJobFollowUp ? { externalJobFollowUp: params.externalJobFollowUp } : {},
|
|
1447
|
+
...params.context ? { context: params.context } : {},
|
|
719
1448
|
cwd: runnerCwd,
|
|
1449
|
+
requestedCwd: params.requestedCwd ?? runnerCwd,
|
|
720
1450
|
model,
|
|
1451
|
+
...contextLimit !== undefined ? { contextLimit } : {},
|
|
1452
|
+
...params.fast ?? agentConfig.fast ? { fast: params.fast ?? agentConfig.fast } : {},
|
|
721
1453
|
thinking: resolveEffectiveThinking(model, effectiveThinking),
|
|
722
|
-
|
|
1454
|
+
...thinkingCeiling ? { thinkingCeiling } : {},
|
|
1455
|
+
modelCandidates,
|
|
1456
|
+
...params.modelOverrideFromParent ? { skipPrimaryModelVerification: true } : {},
|
|
1457
|
+
...availableModels && availableModels.length > 0 ? { modelVerificationRegistry: availableModels } : {},
|
|
723
1458
|
tools: agentConfig.tools,
|
|
1459
|
+
allowNestedSubagents: agentConfig.allowNestedSubagents,
|
|
724
1460
|
extensions: agentConfig.extensions,
|
|
725
1461
|
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
726
1462
|
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
1463
|
+
...toolPlan.mcpConfig ? { mcpConfig: toolPlan.mcpConfig } : {},
|
|
1464
|
+
...toolPlan.runtimeServerNames ? { runtimeServerNames: toolPlan.runtimeServerNames } : {},
|
|
1465
|
+
mutationTools: agentConfig.mutationTools,
|
|
727
1466
|
completionGuard: agentConfig.completionGuard,
|
|
728
1467
|
systemPrompt,
|
|
729
1468
|
systemPromptMode: agentConfig.systemPromptMode,
|
|
730
1469
|
inheritProjectContext: agentConfig.inheritProjectContext,
|
|
1470
|
+
inheritGlobalContext: agentConfig.inheritGlobalContext,
|
|
731
1471
|
inheritSkills: agentConfig.inheritSkills,
|
|
732
1472
|
skills: resolvedSkills.map((r) => r.name),
|
|
733
1473
|
outputPath,
|
|
1474
|
+
...params.outputClaimPath ? { outputClaimPath: params.outputClaimPath } : {},
|
|
734
1475
|
outputMode,
|
|
735
|
-
sessionFile,
|
|
1476
|
+
...!externalRunner && sessionFile ? { sessionFile } : {},
|
|
736
1477
|
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
}
|
|
744
|
-
|
|
1478
|
+
waitToolEnabled: params.waitToolEnabled,
|
|
1479
|
+
waitToolDefaultTimeoutMs: params.waitToolDefaultTimeoutMs,
|
|
1480
|
+
...params.agentContract ? { agentContract: params.agentContract } : {},
|
|
1481
|
+
definitionDigest: agentDefinitionDigest(agentConfig),
|
|
1482
|
+
launchBindingTask: task,
|
|
1483
|
+
launchContractDigest,
|
|
1484
|
+
...extensionBindings ? { extensionBindings } : {},
|
|
1485
|
+
launchResolvedExtensions,
|
|
1486
|
+
effectiveAcceptance: resolvedAcceptance,
|
|
1487
|
+
...structuredOutput ? { structuredOutput } : {},
|
|
1488
|
+
...params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {},
|
|
1489
|
+
...resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {},
|
|
1490
|
+
...params.worktree === true ? { worktree: true } : {},
|
|
1491
|
+
...lane ? { lane } : {}
|
|
745
1492
|
}
|
|
746
1493
|
],
|
|
747
|
-
resultPath: inheritedNestedRoute ? nestedResultsPath(inheritedNestedRoute.rootRunId, id) :
|
|
1494
|
+
resultPath: params.parentWorkflowRunId !== undefined && (params.revivalLease !== undefined || params.workflowAwaitAsync === true) ? workflowAwaitedAsyncResultPath(asyncDir) : inheritedNestedRoute ? nestedResultsPath(inheritedNestedRoute.rootRunId, id) : resultFilePath(DIRS.results, id),
|
|
748
1495
|
cwd: runnerCwd,
|
|
749
1496
|
placeholder: "{previous}",
|
|
750
1497
|
maxOutput,
|
|
751
1498
|
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
752
1499
|
artifactConfig,
|
|
753
1500
|
share: shareEnabled,
|
|
754
|
-
sessionDir:
|
|
1501
|
+
sessionDir: resolvedSessionDir,
|
|
755
1502
|
asyncDir,
|
|
756
1503
|
sessionId: ctx.currentSessionId,
|
|
1504
|
+
completionOwnerId: ctx.completionOwnerId ?? currentCompletionOwnerId(),
|
|
1505
|
+
...capabilityCeiling ? { capabilityCeiling } : {},
|
|
757
1506
|
piPackageRoot,
|
|
758
1507
|
piArgv1: process.argv[1],
|
|
759
1508
|
worktreeSetupHook,
|
|
760
1509
|
worktreeSetupHookTimeoutMs,
|
|
761
1510
|
worktreeBaseDir,
|
|
762
1511
|
controlConfig,
|
|
763
|
-
timeoutMs
|
|
1512
|
+
timeoutMs,
|
|
764
1513
|
deadlineAt,
|
|
765
|
-
|
|
1514
|
+
toolTimeoutMs,
|
|
766
1515
|
toolBudget: params.toolBudget,
|
|
1516
|
+
usageBudget: params.usageBudget,
|
|
767
1517
|
controlIntercomTarget,
|
|
768
1518
|
childIntercomTargets: childIntercomTarget ? [childIntercomTarget(agent, 0)] : undefined,
|
|
769
1519
|
resultMode: "single",
|
|
1520
|
+
launchContractDigest,
|
|
1521
|
+
launchResolvedExtensions,
|
|
1522
|
+
runFanoutBudget,
|
|
1523
|
+
...params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {},
|
|
1524
|
+
...params.workflowKey ? { workflowKey: params.workflowKey } : {},
|
|
1525
|
+
...lane ? { lane } : {},
|
|
1526
|
+
...params.revivalLease ? { revivalLease: params.revivalLease } : {},
|
|
770
1527
|
nestedRoute: nestedRoute ?? inheritedNestedRoute,
|
|
771
1528
|
nestedSelf: inheritedNestedRoute && nestedAddress ? {
|
|
772
1529
|
parentRunId: nestedAddress.parentRunId,
|
|
@@ -774,14 +1531,37 @@ ${memoryInjection}` : memoryInjection;
|
|
|
774
1531
|
depth: nestedAddress.depth,
|
|
775
1532
|
path: nestedAddress.path
|
|
776
1533
|
} : undefined
|
|
777
|
-
}, id, runnerCwd
|
|
1534
|
+
}, id, runnerCwd, {
|
|
1535
|
+
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
1536
|
+
runId: id,
|
|
1537
|
+
...ctx.currentSessionId ? { sessionId: ctx.currentSessionId } : {},
|
|
1538
|
+
...initialCompletionOwnerId ? { completionOwnerId: initialCompletionOwnerId } : {},
|
|
1539
|
+
mode: "single",
|
|
1540
|
+
state: "running",
|
|
1541
|
+
startedAt: initialStatusAt,
|
|
1542
|
+
lastUpdate: initialStatusAt,
|
|
1543
|
+
currentStep: 0,
|
|
1544
|
+
chainStepCount: 1,
|
|
1545
|
+
...lane ? { lane } : {},
|
|
1546
|
+
steps: [{ agent, status: "pending", ...lane ? { lane } : {}, ...model ? { model } : {}, ...contextLimit !== undefined ? { contextLimit } : {} }]
|
|
1547
|
+
}, path.join(asyncDir, "status.json"), (proof) => emitProcessTerminalEvent(ctx, proof), params.requestedCwd ?? runnerCwd);
|
|
778
1548
|
} catch (error) {
|
|
1549
|
+
params.activeAsyncCapacity?.rollback();
|
|
779
1550
|
const message = error instanceof Error ? error.message : String(error);
|
|
780
1551
|
return formatAsyncStartError("single", `Failed to start async run '${id}': ${message}`);
|
|
781
1552
|
}
|
|
782
1553
|
if (spawnResult.error) {
|
|
1554
|
+
if (!spawnResult.pid || !spawnResult.runnerProcessInstanceId || spawnResult.startupDidNotProceed && spawnResult.terminationObserved)
|
|
1555
|
+
params.activeAsyncCapacity?.rollback();
|
|
1556
|
+
else
|
|
1557
|
+
params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
783
1558
|
return formatAsyncStartError("single", `Failed to start async run '${id}': ${spawnResult.error}`);
|
|
784
1559
|
}
|
|
1560
|
+
if (!spawnResult.pid || !spawnResult.runnerProcessInstanceId) {
|
|
1561
|
+
params.activeAsyncCapacity?.rollback();
|
|
1562
|
+
return formatAsyncStartError("single", `Failed to start async run '${id}': runner identity unavailable`);
|
|
1563
|
+
}
|
|
1564
|
+
params.activeAsyncCapacity?.markStarted(spawnResult.runnerProcessInstanceId);
|
|
785
1565
|
if (spawnResult.pid) {
|
|
786
1566
|
if (inheritedNestedRoute && nestedAddress) {
|
|
787
1567
|
const now = Date.now();
|
|
@@ -808,33 +1588,41 @@ ${memoryInjection}` : memoryInjection;
|
|
|
808
1588
|
agent,
|
|
809
1589
|
agents: [agent],
|
|
810
1590
|
chainStepCount: 1,
|
|
811
|
-
...
|
|
812
|
-
...initialTurnBudget ? { turnBudget: initialTurnBudget } : {},
|
|
1591
|
+
...timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {},
|
|
813
1592
|
startedAt: now,
|
|
814
|
-
lastUpdate: now
|
|
1593
|
+
lastUpdate: now,
|
|
1594
|
+
...capabilityCeiling ? { capabilityCeiling } : {}
|
|
815
1595
|
}
|
|
816
1596
|
});
|
|
817
1597
|
} catch (error) {
|
|
818
1598
|
console.error("Failed to emit nested async start event:", error);
|
|
819
1599
|
}
|
|
820
1600
|
}
|
|
821
|
-
ctx.
|
|
1601
|
+
ctx.dm.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
|
|
822
1602
|
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
823
1603
|
id,
|
|
824
1604
|
pid: spawnResult.pid,
|
|
825
1605
|
sessionId: ctx.currentSessionId,
|
|
1606
|
+
completionOwnerId: ctx.completionOwnerId ?? currentCompletionOwnerId(),
|
|
826
1607
|
mode: "single",
|
|
827
1608
|
agent,
|
|
828
|
-
task: task?.
|
|
1609
|
+
task: task?.trim() ? PROMPT_REDACTED : undefined,
|
|
1610
|
+
goal: (params.goal ?? task).trim() ? PROMPT_REDACTED : undefined,
|
|
829
1611
|
cwd: runnerCwd,
|
|
830
1612
|
asyncDir,
|
|
831
|
-
...
|
|
832
|
-
|
|
1613
|
+
...sessionRoot ? { sessionRoot } : {},
|
|
1614
|
+
launchContractDigest,
|
|
1615
|
+
launchResolvedExtensions,
|
|
1616
|
+
...params.parentWorkflowRunId ? { parentWorkflowRunId: params.parentWorkflowRunId } : {},
|
|
1617
|
+
...params.workflowKey ? { workflowKey: params.workflowKey } : {},
|
|
1618
|
+
...timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {},
|
|
1619
|
+
...initialUsageBudget ? { usageBudget: initialUsageBudget } : {},
|
|
1620
|
+
...capabilityCeiling ? { capabilityCeiling } : {},
|
|
833
1621
|
nestedRoute
|
|
834
1622
|
});
|
|
835
1623
|
}
|
|
836
1624
|
return {
|
|
837
|
-
content: [{ type: "text", text: formatAsyncStartedMessage(`Async: ${agent} [${id}]
|
|
838
|
-
details: { mode: "single", runId: id, results: [], asyncId: id, asyncDir, ...params.timeoutMs !== undefined ? { timeoutMs
|
|
1625
|
+
content: [{ type: "text", text: formatAsyncStartedMessage(`Async: ${agent} [${id}]`, ctx.interactive === true) }],
|
|
1626
|
+
details: { mode: "single", runId: id, results: [], asyncId: id, asyncDir, launchContractDigest, launchResolvedExtensions, ...capabilityCeiling ? { capabilityCeiling } : {}, ...params.context ? { context: params.context } : {}, ...timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}, ...params.toolBudget ? { toolBudget: resolvedToolBudget.budget ?? params.toolBudget } : {}, ...initialUsageBudget ? { usageBudget: initialUsageBudget } : {} }
|
|
839
1627
|
};
|
|
840
1628
|
}
|