@selesai/code 0.8.6 → 0.8.8
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/CHANGELOG.md +31 -1
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.js +11 -0
- package/dist/cli/args.test.d.ts +1 -0
- package/dist/cli/args.test.js +24 -0
- package/dist/core/agent-session.d.ts +4 -1
- package/dist/core/agent-session.js +18 -7
- package/dist/core/experimental.d.ts +4 -0
- package/dist/core/experimental.js +4 -0
- package/dist/core/extensions/types.d.ts +6 -0
- package/dist/core/keybindings.d.ts +24 -0
- package/dist/core/model-config.d.ts +5 -0
- package/dist/core/model-config.js +1 -0
- package/dist/core/project-trust.js +2 -2
- package/dist/core/provider-composer.js +17 -4
- package/dist/core/sdk.d.ts +5 -3
- package/dist/core/sdk.js +2 -1
- package/dist/core/session-manager.js +2 -2
- package/dist/core/settings-manager.d.ts +8 -0
- package/dist/core/settings-manager.js +15 -0
- package/dist/core/system-prompt.js +3 -9
- package/dist/core/system-prompt.test.js +6 -0
- package/dist/core/tools/bash.js +2 -0
- package/dist/core/tools/edit.js +2 -0
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/read.js +2 -0
- package/dist/core/tools/schema-prune.d.ts +16 -0
- package/dist/core/tools/schema-prune.js +39 -0
- package/dist/core/tools/schema-prune.test.d.ts +1 -0
- package/dist/core/tools/schema-prune.test.js +111 -0
- package/dist/core/tools/write.js +2 -0
- package/dist/defaults/settings.json +1 -0
- package/dist/extensions/model-prompt-injector/config.json +10 -0
- package/dist/extensions/model-prompt-injector/index.test.ts +112 -0
- package/dist/extensions/model-prompt-injector/index.ts +151 -0
- package/dist/extensions/package.json +1 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +158 -90
- package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +172 -0
- package/dist/extensions/pi-subagents/agents/oracle.md +7 -5
- package/dist/extensions/pi-subagents/agents/reviewer.md +2 -2
- package/dist/extensions/pi-subagents/agents/scout.md +1 -1
- package/dist/extensions/pi-subagents/agents/worker.md +1 -1
- package/dist/extensions/pi-subagents/docs/configuration.md +78 -19
- package/dist/extensions/pi-subagents/docs/extension-api.md +36 -0
- package/dist/extensions/pi-subagents/docs/missions.md +5 -3
- package/dist/extensions/pi-subagents/docs/models.md +1 -1
- package/dist/extensions/pi-subagents/docs/observability.md +42 -2
- package/dist/extensions/pi-subagents/docs/tool-reference.md +20 -3
- package/dist/extensions/pi-subagents/docs/workflows.md +5 -5
- package/dist/extensions/pi-subagents/install.mjs +2 -2
- package/dist/extensions/pi-subagents/package-lock.json +1470 -1472
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +15 -14
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +37 -12
- package/dist/extensions/pi-subagents/src/api/external-runs.ts +174 -84
- package/dist/extensions/pi-subagents/src/api/preflight.ts +13 -7
- package/dist/extensions/pi-subagents/src/extension/config.ts +53 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +67 -13
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +34 -6
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +5 -1
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -30
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +10 -9
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +13 -8
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +16 -3
- package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -6
- package/dist/extensions/pi-subagents/src/inspectors/herdr/shell-command.ts +16 -0
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +5 -4
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +19 -42
- package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +3 -1
- package/dist/extensions/pi-subagents/src/missions/store.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +82 -25
- package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +71 -1
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +73 -43
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +5 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +277 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +11 -1
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +21 -6
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +187 -41
- package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +27 -7
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +76 -19
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +30 -24
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +101 -4
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +54 -28
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +27 -13
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +298 -33
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +219 -15
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +333 -45
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +107 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +39 -23
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +16 -2
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +66 -62
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +376 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +15 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +12 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +95 -0
- package/dist/extensions/pi-subagents/src/shared/agent-stream-options.ts +5 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +0 -4
- package/dist/extensions/pi-subagents/src/shared/display-text.ts +50 -0
- package/dist/extensions/pi-subagents/src/shared/node-executable.ts +21 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +50 -4
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +34 -25
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +4 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +160 -45
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +1 -48
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +128 -16
- package/dist/extensions/pi-subagents/src/tui/render.ts +122 -44
- package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +2 -1
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -3
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +10 -2
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +272 -76
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +2 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +68 -9
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +27 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +49 -0
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +26 -1
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +395 -98
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +111 -78
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +12 -0
- package/dist/extensions/pi-subagents/test/support/node-command.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +61 -0
- package/dist/extensions/pi-subagents/test/unit/agent-stream-options.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +162 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +209 -10
- package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +135 -42
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +252 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +192 -6
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +59 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +69 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +23 -4
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +56 -1
- package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +67 -3
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +25 -2
- package/dist/extensions/pi-subagents/test/unit/node-executable.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +348 -0
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +5 -2
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +6 -1
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +92 -0
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +127 -17
- package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +247 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +107 -2
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +5 -8
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +456 -4
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +16 -7
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +79 -15
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +12 -12
- package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +109 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +42 -2
- package/dist/extensions/question/index.ts +21 -6
- package/dist/extensions/question/question-list.ts +7 -1
- package/dist/extensions/question/row-layout.ts +3 -0
- package/dist/extensions/question/tests/exp.test.ts +70 -0
- package/dist/extensions/question/tests/exp2.test.ts +59 -0
- package/dist/extensions/question/tests/exp3.test.ts +47 -0
- package/dist/extensions/question/tests/helpers.test.ts +7 -0
- package/dist/extensions/question/tests/question-list.test.ts +140 -0
- package/dist/extensions/question/tests/row-layout.test.ts +13 -0
- package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
- package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
- package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
- package/dist/extensions/tokenin-onboarding.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/main.js +4 -0
- package/dist/modes/interactive/components/model-selector.js +2 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/tool-execution.js +10 -1
- package/dist/modes/interactive/interactive-mode.d.ts +8 -2
- package/dist/modes/interactive/interactive-mode.js +81 -25
- package/dist/modes/interactive/model-catalog-refresh.d.ts +6 -0
- package/dist/modes/interactive/model-catalog-refresh.js +33 -0
- package/dist/modes/interactive/theme/dark.json +2 -0
- package/dist/modes/interactive/theme/light.json +2 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
- package/dist/modes/interactive/theme/theme-controller.js +25 -11
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive/theme/theme.d.ts +5 -3
- package/dist/modes/interactive/theme/theme.js +12 -2
- package/dist/skills/pi-subagents/SKILL.md +1 -1
- package/dist/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/skills/pi-subagents/references/execution-controls.md +15 -14
- package/dist/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/dist/utils/abort.d.ts +4 -0
- package/dist/utils/abort.js +47 -0
- package/dist/utils/tools-manager.d.ts +5 -1
- package/dist/utils/tools-manager.js +12 -21
- package/docs/settings.md +6 -0
- package/package.json +6 -6
|
@@ -101,6 +101,7 @@ import { stopAsyncRun } from "./async-stop-action.ts";
|
|
|
101
101
|
import { dismissRecoveredWorkflow } from "./async-dismiss-action.ts";
|
|
102
102
|
import { reconcileAsyncRun } from "../background/stale-run-reconciler.ts";
|
|
103
103
|
import { resolveAsyncRootResultPath, waitForImportedAsyncRoot } from "../background/chain-root-attachment.ts";
|
|
104
|
+
import { resultFilePath, writeAsyncResultFile } from "../background/result-files.ts";
|
|
104
105
|
import { attachRootChildrenToSteps, createNestedRoute, findNestedControlResult, resolveInheritedNestedRouteFromEnv, resolveNestedAsyncDir, resolveNestedParentAddressFromEnv, snapshotNestedEventFiles, updateForegroundNestedProjection, writeNestedControlRequest, writeNestedEvent, type NestedRunResolutionScope } from "../shared/nested-events.ts";
|
|
105
106
|
import { resolveSubagentRunId, type ResolvedSubagentRunId } from "../background/run-id-resolver.ts";
|
|
106
107
|
import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
|
|
@@ -108,7 +109,7 @@ import { inspectSubagentStatus } from "../background/run-status.ts";
|
|
|
108
109
|
import { applyForceTopLevelAsyncOverride } from "../background/top-level-async.ts";
|
|
109
110
|
import { handleMissionAction, MISSION_ACTIONS } from "../../missions/actions.ts";
|
|
110
111
|
import { attachMissionToLaunchResult, prepareMissionLaunch, writeMissionAsyncBinding, type MissionLaunchBinding } from "../../missions/lifecycle.ts";
|
|
111
|
-
import { updateMission } from "../../missions/store.ts";
|
|
112
|
+
import { MissionNotFoundError, updateMission } from "../../missions/store.ts";
|
|
112
113
|
import type { MissionWorkflowChildUpdate } from "../../missions/types.ts";
|
|
113
114
|
import { createMissionWorkflowState } from "../../missions/workflow-state.ts";
|
|
114
115
|
import { resolveAuthorityDecision } from "../../policy/authority.ts";
|
|
@@ -140,6 +141,7 @@ import {
|
|
|
140
141
|
type Details,
|
|
141
142
|
type ExtensionConfig,
|
|
142
143
|
type ForegroundRunControl,
|
|
144
|
+
type IntercomBridgeConfig,
|
|
143
145
|
type IntercomEventBus,
|
|
144
146
|
type JsonSchemaObject,
|
|
145
147
|
type MaxOutputConfig,
|
|
@@ -301,10 +303,14 @@ export interface SubagentParamsLike {
|
|
|
301
303
|
concurrency?: number;
|
|
302
304
|
worktree?: boolean;
|
|
303
305
|
context?: "fresh" | "fork";
|
|
306
|
+
/** Per-run intercom bridge config. It replaces the global config for this launch only. */
|
|
307
|
+
intercomBridge?: IntercomBridgeConfig;
|
|
304
308
|
async?: boolean;
|
|
305
309
|
foregroundOnly?: boolean;
|
|
306
310
|
timeoutMs?: number;
|
|
307
311
|
maxRuntimeMs?: number;
|
|
312
|
+
/** Optional hard per-tool-call timeout (ms). Known-fast tools also have a default. */
|
|
313
|
+
toolTimeoutMs?: number;
|
|
308
314
|
turnBudget?: TurnBudgetConfig;
|
|
309
315
|
/** Internal-only strict turn-boundary enforcement for versioned foreground delegation. */
|
|
310
316
|
enforceHardTurnLimit?: boolean;
|
|
@@ -388,6 +394,8 @@ interface ExecutionContextData {
|
|
|
388
394
|
signal: AbortSignal;
|
|
389
395
|
onUpdate?: (r: AgentToolResult<Details>) => void;
|
|
390
396
|
agents: AgentConfig[];
|
|
397
|
+
/** Discovered agent definitions before per-run bridge injection. */
|
|
398
|
+
recoveryAgents: AgentConfig[];
|
|
391
399
|
runId: string;
|
|
392
400
|
shareEnabled: boolean;
|
|
393
401
|
sessionRoot: string;
|
|
@@ -405,6 +413,8 @@ interface ExecutionContextData {
|
|
|
405
413
|
nestedRoute?: NestedRouteInfo;
|
|
406
414
|
timeoutMs?: number;
|
|
407
415
|
deadlineAt?: number;
|
|
416
|
+
/** Raw global config.toolTimeoutMs, for per-step resolution in async runners. */
|
|
417
|
+
configToolTimeoutMs?: number;
|
|
408
418
|
turnBudget?: ResolvedTurnBudget;
|
|
409
419
|
toolBudget?: ResolvedToolBudget;
|
|
410
420
|
usageBudget?: UsageBudgetConfig;
|
|
@@ -1513,17 +1523,18 @@ async function resumeAsyncRun(input: {
|
|
|
1513
1523
|
const discoveredAgents = discovered.agents;
|
|
1514
1524
|
const modelScope = discovered.modelScope;
|
|
1515
1525
|
const sessionName = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
|
|
1526
|
+
const recoveryDescriptor = "recoveryDescriptor" in target ? target.recoveryDescriptor : undefined;
|
|
1516
1527
|
const intercomBridge = resolveIntercomBridge({
|
|
1517
1528
|
config: input.deps.config.intercomBridge,
|
|
1529
|
+
override: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
|
|
1518
1530
|
context: input.params.context,
|
|
1519
1531
|
orchestratorTarget: sessionName,
|
|
1520
1532
|
});
|
|
1521
1533
|
const agents = intercomBridge.active
|
|
1522
1534
|
? discoveredAgents.map((agent) => applyIntercomBridgeToAgent(agent, intercomBridge))
|
|
1523
1535
|
: discoveredAgents;
|
|
1524
|
-
const
|
|
1525
|
-
const
|
|
1526
|
-
const agentConfig: AgentConfig | undefined = discoveredAgentConfig ?? (recoveryDescriptor ? {
|
|
1536
|
+
const discoveredAgentConfig = discoveredAgents.find((agent) => agent.name === target.agent);
|
|
1537
|
+
const baseAgentConfig: AgentConfig | undefined = discoveredAgentConfig ?? (recoveryDescriptor ? {
|
|
1527
1538
|
name: recoveryDescriptor.agent,
|
|
1528
1539
|
description: "Persisted async recovery contract",
|
|
1529
1540
|
systemPrompt: "",
|
|
@@ -1533,7 +1544,7 @@ async function resumeAsyncRun(input: {
|
|
|
1533
1544
|
source: "project",
|
|
1534
1545
|
filePath: recoveryDescriptor.agentFilePath ?? path.join(getProjectSubagentsDir(recoveryDescriptor.cwd), "recovery-agent"),
|
|
1535
1546
|
} : undefined);
|
|
1536
|
-
if (!
|
|
1547
|
+
if (!baseAgentConfig) {
|
|
1537
1548
|
return {
|
|
1538
1549
|
content: [{ type: "text", text: `Unknown agent for resume: ${target.agent}` }],
|
|
1539
1550
|
isError: true,
|
|
@@ -1674,7 +1685,8 @@ async function resumeAsyncRun(input: {
|
|
|
1674
1685
|
if (error instanceof ActiveAsyncCapacityError) return { content: [{ type: "text", text: error.message }], isError: true, details: { mode: "single", results: [], activeAsyncCapacity: error.snapshot } };
|
|
1675
1686
|
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "single", results: [] } };
|
|
1676
1687
|
}
|
|
1677
|
-
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(
|
|
1688
|
+
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(baseAgentConfig, recoveryDescriptor) : baseAgentConfig;
|
|
1689
|
+
const agentConfig = intercomBridge.active ? applyIntercomBridgeToAgent(recoveryAgentConfig, intercomBridge) : recoveryAgentConfig;
|
|
1678
1690
|
const artifactConfig: ArtifactConfig = recoveryDescriptor?.artifactConfig ?? omitUndefinedProperties({ ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false, dir: input.deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir });
|
|
1679
1691
|
const artifactsDir = recoveryDescriptor?.artifactsDir ?? getArtifactsDir(parentSessionFile, effectiveCwd, artifactConfig.dir);
|
|
1680
1692
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
@@ -1684,7 +1696,8 @@ async function resumeAsyncRun(input: {
|
|
|
1684
1696
|
agent: target.agent,
|
|
1685
1697
|
task: buildRevivedAsyncTask(target as Parameters<typeof buildRevivedAsyncTask>[0], effectiveFollowUp),
|
|
1686
1698
|
goal: effectiveFollowUp,
|
|
1687
|
-
agentConfig
|
|
1699
|
+
agentConfig,
|
|
1700
|
+
recoveryAgentConfig,
|
|
1688
1701
|
ctx: compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
1689
1702
|
pi: input.deps.pi,
|
|
1690
1703
|
cwd: input.requestCwd,
|
|
@@ -1719,6 +1732,7 @@ async function resumeAsyncRun(input: {
|
|
|
1719
1732
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
1720
1733
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1721
1734
|
controlConfig: recoveryDescriptor?.controlConfig ?? resolveControlConfig(input.deps.config.control, input.params.control),
|
|
1735
|
+
intercomBridge: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
|
|
1722
1736
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
1723
1737
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
1724
1738
|
availableModels,
|
|
@@ -1733,7 +1747,7 @@ async function resumeAsyncRun(input: {
|
|
|
1733
1747
|
...(input.params.turnBudget !== undefined ? { turnBudget: input.params.turnBudget } : {}),
|
|
1734
1748
|
...(input.params.toolBudget !== undefined ? { toolBudget: input.params.toolBudget } : {}),
|
|
1735
1749
|
capabilityCeiling: intersectSubagentCapabilityCeilings("capabilityCeiling" in target ? target.capabilityCeiling : undefined, recoveryDescriptor?.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
|
|
1736
|
-
runFanoutBudget: recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
1750
|
+
runFanoutBudget: input.params.runFanoutBudget ?? recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
1737
1751
|
parentWorkflowRunId: input.params.workflowParentRunId,
|
|
1738
1752
|
workflowKey: input.params.workflowKey,
|
|
1739
1753
|
activeAsyncCapacity,
|
|
@@ -2499,16 +2513,19 @@ function resolveStaticLaunchSummary(input: {
|
|
|
2499
2513
|
thinkingOverrideForTask: ForkThinkingOverrideForTask;
|
|
2500
2514
|
}): StaticLaunchSummary {
|
|
2501
2515
|
const agentConfig = input.agents.find((agent) => agent.name === input.agent);
|
|
2502
|
-
const
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2516
|
+
const externalRunner = agentConfig?.runner?.type === "external-cli";
|
|
2517
|
+
const model = externalRunner
|
|
2518
|
+
? undefined
|
|
2519
|
+
: resolveEffectiveSubagentModel(
|
|
2520
|
+
input.explicitModel,
|
|
2521
|
+
agentConfig?.model,
|
|
2522
|
+
input.parentModel,
|
|
2523
|
+
input.availableModels,
|
|
2524
|
+
input.currentProvider,
|
|
2525
|
+
input.modelScope === undefined ? {} : { scope: input.modelScope },
|
|
2526
|
+
);
|
|
2527
|
+
const thinkingOverride = externalRunner ? undefined : input.thinkingOverrideForTask(input.agent, input.index, model);
|
|
2528
|
+
const thinking = externalRunner ? undefined : resolveEffectiveThinking(model, thinkingOverride ?? agentConfig?.thinking);
|
|
2512
2529
|
return {
|
|
2513
2530
|
agent: input.agent,
|
|
2514
2531
|
...(model ? { model } : {}),
|
|
@@ -2791,6 +2808,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2791
2808
|
toolBudget: data.toolBudget,
|
|
2792
2809
|
usageBudget: data.usageBudget,
|
|
2793
2810
|
configToolBudget: data.configToolBudget,
|
|
2811
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
2812
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2794
2813
|
capabilityCeiling: data.capabilityCeiling,
|
|
2795
2814
|
runFanoutBudget: data.runFanoutBudget,
|
|
2796
2815
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -2838,6 +2857,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2838
2857
|
toolBudget: data.toolBudget,
|
|
2839
2858
|
usageBudget: data.usageBudget,
|
|
2840
2859
|
configToolBudget: data.configToolBudget,
|
|
2860
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
2861
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2841
2862
|
capabilityCeiling: data.capabilityCeiling,
|
|
2842
2863
|
runFanoutBudget: data.runFanoutBudget,
|
|
2843
2864
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -2864,14 +2885,15 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2864
2885
|
const externalRunnerWithoutExplicitModel = a.runner?.type === "external-cli"
|
|
2865
2886
|
&& params.model === undefined
|
|
2866
2887
|
&& (a.model === undefined || (a.modelSource?.type === "subagents.defaultModel" && a.model === a.modelSource.model));
|
|
2867
|
-
const modelOverride =
|
|
2868
|
-
? undefined
|
|
2888
|
+
const modelOverride = a.runner?.type === "external-cli"
|
|
2889
|
+
? params.model ?? (externalRunnerWithoutExplicitModel ? undefined : a.model)
|
|
2869
2890
|
: resolveEffectiveSubagentModel(params.model as string | undefined, a.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope });
|
|
2870
2891
|
return executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
2871
2892
|
agent: params.agent!,
|
|
2872
2893
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
2873
2894
|
goal: params.task ?? "",
|
|
2874
2895
|
agentConfig: a,
|
|
2896
|
+
recoveryAgentConfig: data.recoveryAgents.find((agent) => agent.name === params.agent),
|
|
2875
2897
|
ctx: asyncCtx,
|
|
2876
2898
|
availableModels,
|
|
2877
2899
|
cwd: effectiveCwd,
|
|
@@ -2896,6 +2918,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2896
2918
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
2897
2919
|
worktreeBaseDir: deps.config.worktreeBaseDir,
|
|
2898
2920
|
controlConfig,
|
|
2921
|
+
intercomBridge: params.intercomBridge,
|
|
2899
2922
|
controlIntercomTarget,
|
|
2900
2923
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(agent, index) : undefined,
|
|
2901
2924
|
nestedRoute,
|
|
@@ -2907,6 +2930,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2907
2930
|
toolBudget: data.toolBudget,
|
|
2908
2931
|
usageBudget: data.usageBudget,
|
|
2909
2932
|
configToolBudget: data.configToolBudget,
|
|
2933
|
+
toolTimeoutMs: data.params?.toolTimeoutMs,
|
|
2934
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2910
2935
|
capabilityCeiling: data.capabilityCeiling,
|
|
2911
2936
|
runFanoutBudget: data.runFanoutBudget,
|
|
2912
2937
|
parentWorkflowRunId: params.workflowParentRunId,
|
|
@@ -2996,6 +3021,8 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2996
3021
|
toolBudget: data.toolBudget,
|
|
2997
3022
|
usageBudget: data.usageBudget,
|
|
2998
3023
|
configToolBudget: data.configToolBudget,
|
|
3024
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
3025
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2999
3026
|
permissions: deps.config.permissions,
|
|
3000
3027
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
3001
3028
|
capabilityCeiling: data.capabilityCeiling,
|
|
@@ -3063,6 +3090,8 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3063
3090
|
toolBudget: data.toolBudget,
|
|
3064
3091
|
usageBudget: data.usageBudget,
|
|
3065
3092
|
configToolBudget: data.configToolBudget,
|
|
3093
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
3094
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
3066
3095
|
capabilityCeiling: data.capabilityCeiling,
|
|
3067
3096
|
runFanoutBudget: data.runFanoutBudget,
|
|
3068
3097
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -3150,6 +3179,10 @@ interface ForegroundParallelRunInput {
|
|
|
3150
3179
|
worktreeSetup?: WorktreeSetup;
|
|
3151
3180
|
timeoutMs?: number;
|
|
3152
3181
|
deadlineAt?: number;
|
|
3182
|
+
/** Per-call per-tool timeout, resolved separately for each task's agent. */
|
|
3183
|
+
toolTimeoutMs?: number;
|
|
3184
|
+
/** Raw global config.toolTimeoutMs, used by each task's resolver. */
|
|
3185
|
+
configToolTimeoutMs?: number;
|
|
3153
3186
|
turnBudget?: ResolvedTurnBudget;
|
|
3154
3187
|
usageBudget?: UsageBudgetConfig;
|
|
3155
3188
|
toolBudgets: (ResolvedToolBudget | undefined)[];
|
|
@@ -3241,10 +3274,128 @@ function buildParallelWorktreeTaskCwdError(
|
|
|
3241
3274
|
return formatWorktreeTaskCwdConflict(conflict, sharedCwd);
|
|
3242
3275
|
}
|
|
3243
3276
|
|
|
3244
|
-
function
|
|
3277
|
+
function resolveConfiguredSingleRunOutputBaseDir(deps: ExecutorDeps): string | undefined {
|
|
3245
3278
|
return deps.config.singleRunOutputBaseDir
|
|
3246
3279
|
? path.resolve(deps.expandTilde(deps.config.singleRunOutputBaseDir))
|
|
3247
|
-
:
|
|
3280
|
+
: undefined;
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
function resolveSingleRunOutputBaseDir(deps: ExecutorDeps, artifactsDir: string, runId: string): string {
|
|
3284
|
+
return resolveConfiguredSingleRunOutputBaseDir(deps) ?? path.join(artifactsDir, "outputs", runId);
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
function resolveWorkflowAggregateOutputPath(
|
|
3288
|
+
output: string | boolean | undefined,
|
|
3289
|
+
ctxCwd: string,
|
|
3290
|
+
workflowCwd: string,
|
|
3291
|
+
outputBaseDir: string,
|
|
3292
|
+
configuredOutputBaseDir: string | undefined,
|
|
3293
|
+
): string | undefined {
|
|
3294
|
+
if (typeof output === "string" && output && !path.isAbsolute(output) && !configuredOutputBaseDir) return path.resolve(workflowCwd, output);
|
|
3295
|
+
return resolveSingleOutputPath(output, ctxCwd, workflowCwd, outputBaseDir);
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
function workflowChildDefaultOutput(aggregateOutputPath: string | undefined, artifactsDir: string, workflowRunId: string, workflowKey: string): string {
|
|
3299
|
+
if (aggregateOutputPath) {
|
|
3300
|
+
const parsed = path.parse(aggregateOutputPath);
|
|
3301
|
+
return path.join(parsed.dir, `${parsed.name}.${workflowKey}${parsed.ext || ".md"}`);
|
|
3302
|
+
}
|
|
3303
|
+
return path.join(artifactsDir, "outputs", workflowRunId, `${workflowKey}.md`);
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
function writeWorkflowAggregateOutput(outputPath: string | undefined, text: string): string | undefined {
|
|
3307
|
+
if (!outputPath) return undefined;
|
|
3308
|
+
try {
|
|
3309
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
3310
|
+
fs.writeFileSync(outputPath, text, "utf-8");
|
|
3311
|
+
return undefined;
|
|
3312
|
+
} catch (error) {
|
|
3313
|
+
return `Output file error: ${outputPath}\n${error instanceof Error ? error.message : String(error)}`;
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
|
|
3317
|
+
function appendWorkflowOutputWarning(text: string, warning: string | undefined): string {
|
|
3318
|
+
return warning ? `${text}\n\n${warning}` : text;
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
function resolveWorkflowChildOutputPath(input: {
|
|
3322
|
+
ctxCwd: string;
|
|
3323
|
+
workflowCwd: string;
|
|
3324
|
+
artifactsDir: string;
|
|
3325
|
+
workflowRunId: string;
|
|
3326
|
+
aggregateOutputPath?: string;
|
|
3327
|
+
configuredOutputBaseDir?: string;
|
|
3328
|
+
discoverAgents: (cwd: string, scope: AgentScope) => { agents: AgentConfig[] };
|
|
3329
|
+
workflowAgentScope?: unknown;
|
|
3330
|
+
key: string;
|
|
3331
|
+
params: Record<string, unknown>;
|
|
3332
|
+
}): string | undefined {
|
|
3333
|
+
const rawOutput = input.params.output;
|
|
3334
|
+
const hasExplicitOutput = typeof rawOutput === "string" || typeof rawOutput === "boolean";
|
|
3335
|
+
const childCwd = typeof input.params.cwd === "string" ? resolveChildCwd(input.workflowCwd, input.params.cwd) : input.workflowCwd;
|
|
3336
|
+
const agentScope = resolveExecutionAgentScope(input.params.agentScope ?? input.workflowAgentScope);
|
|
3337
|
+
const agents = input.discoverAgents(childCwd, agentScope).agents;
|
|
3338
|
+
const agent = typeof input.params.agent === "string" ? resolveAgentName(input.params.agent, agents).agent : undefined;
|
|
3339
|
+
const agentOutput = typeof agent?.output === "string" ? agent.output : undefined;
|
|
3340
|
+
const output = rawOutput === true || rawOutput === "true"
|
|
3341
|
+
? agentOutput
|
|
3342
|
+
: hasExplicitOutput
|
|
3343
|
+
? rawOutput
|
|
3344
|
+
: workflowChildDefaultOutput(input.aggregateOutputPath, input.artifactsDir, input.workflowRunId, input.key);
|
|
3345
|
+
return resolveSingleOutputPath(output, input.ctxCwd, childCwd, input.configuredOutputBaseDir);
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
function workflowChildOutputClaims(input: {
|
|
3349
|
+
ctxCwd: string;
|
|
3350
|
+
workflowCwd: string;
|
|
3351
|
+
artifactsDir: string;
|
|
3352
|
+
workflowRunId: string;
|
|
3353
|
+
aggregateOutputPath?: string;
|
|
3354
|
+
configuredOutputBaseDir?: string;
|
|
3355
|
+
discoverAgents: (cwd: string, scope: AgentScope) => { agents: AgentConfig[] };
|
|
3356
|
+
workflowAgentScope?: unknown;
|
|
3357
|
+
claimedOutputPaths: Map<string, string>;
|
|
3358
|
+
entries: Array<{ key: string; params: Record<string, unknown> }>;
|
|
3359
|
+
}): { error?: string; claims?: Map<string, string> } {
|
|
3360
|
+
const claims = new Map(input.claimedOutputPaths);
|
|
3361
|
+
for (const { key, params } of input.entries) {
|
|
3362
|
+
const resolved = resolveWorkflowChildOutputPath({ ...input, key, params });
|
|
3363
|
+
if (!resolved) continue;
|
|
3364
|
+
if (input.aggregateOutputPath && resolved === input.aggregateOutputPath) return { error: `Workflow child '${key}' output resolves to the workflow aggregate output path: ${resolved}. Use a distinct child output path.` };
|
|
3365
|
+
const previous = claims.get(resolved);
|
|
3366
|
+
if (previous) return { error: `Workflow children '${previous}' and '${key}' resolve output to the same path: ${resolved}. Use distinct child output paths.` };
|
|
3367
|
+
claims.set(resolved, key);
|
|
3368
|
+
}
|
|
3369
|
+
return { claims };
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
function applyWorkflowChildOutputClaims(target: Map<string, string>, claims: Map<string, string>): void {
|
|
3373
|
+
target.clear();
|
|
3374
|
+
for (const [resolved, key] of claims) target.set(resolved, key);
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3377
|
+
function prepareWorkflowChildLaunchParams(input: {
|
|
3378
|
+
workflowDefaults: SubagentParamsLike;
|
|
3379
|
+
childParams: Record<string, unknown>;
|
|
3380
|
+
parentWorkflowRunId: string;
|
|
3381
|
+
workflowKey: string;
|
|
3382
|
+
ctxCwd: string;
|
|
3383
|
+
workflowCwd: string;
|
|
3384
|
+
artifactsDir: string;
|
|
3385
|
+
aggregateOutputPath?: string;
|
|
3386
|
+
configuredOutputBaseDir?: string;
|
|
3387
|
+
discoverAgents: (cwd: string, scope: AgentScope) => { agents: AgentConfig[] };
|
|
3388
|
+
workflowAgentScope?: unknown;
|
|
3389
|
+
options?: { missionDetached?: boolean; suppressRoutineResultIntercom?: boolean; runFanoutBudget?: RunFanoutBudgetDescriptor };
|
|
3390
|
+
}): SubagentParamsLike {
|
|
3391
|
+
let childParams = input.childParams;
|
|
3392
|
+
if (input.childParams.output === undefined && input.childParams.resume === undefined) {
|
|
3393
|
+
childParams = { ...input.childParams, output: workflowChildDefaultOutput(input.aggregateOutputPath, input.artifactsDir, input.parentWorkflowRunId, input.workflowKey) };
|
|
3394
|
+
} else if (input.childParams.resume === undefined) {
|
|
3395
|
+
const resolvedOutput = resolveWorkflowChildOutputPath({ ctxCwd: input.ctxCwd, workflowCwd: input.workflowCwd, artifactsDir: input.artifactsDir, workflowRunId: input.parentWorkflowRunId, aggregateOutputPath: input.aggregateOutputPath, configuredOutputBaseDir: input.configuredOutputBaseDir, discoverAgents: input.discoverAgents, workflowAgentScope: input.workflowAgentScope, key: input.workflowKey, params: input.childParams });
|
|
3396
|
+
if (resolvedOutput) childParams = { ...input.childParams, output: resolvedOutput };
|
|
3397
|
+
}
|
|
3398
|
+
return prepareWorkflowLaunchParams(input.workflowDefaults, childParams, input.parentWorkflowRunId, input.workflowKey, input.options);
|
|
3248
3399
|
}
|
|
3249
3400
|
|
|
3250
3401
|
function buildChainWorktreeTaskCwdError(chain: ChainStep[], sharedCwd: string): string | undefined {
|
|
@@ -3408,6 +3559,8 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
3408
3559
|
share: input.shareEnabled || undefined,
|
|
3409
3560
|
maxOutput: input.maxOutput,
|
|
3410
3561
|
timeoutMs: input.timeoutMs,
|
|
3562
|
+
toolTimeoutMs: input.toolTimeoutMs,
|
|
3563
|
+
configToolTimeoutMs: input.configToolTimeoutMs,
|
|
3411
3564
|
turnBudget: input.turnBudget,
|
|
3412
3565
|
...(model ? { model } : {}),
|
|
3413
3566
|
...(effectiveSkills !== undefined ? { skill: effectiveSkills } : {}),
|
|
@@ -3487,6 +3640,8 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
3487
3640
|
acceptanceContext: { mode: "parallel" },
|
|
3488
3641
|
onEffectivePrompt: input.foregroundControl ? (prompt) => updateLiveEffectivePrompt(input.foregroundControl!, index, prompt) : undefined,
|
|
3489
3642
|
timeoutMs: input.timeoutMs,
|
|
3643
|
+
toolTimeoutMs: input.toolTimeoutMs,
|
|
3644
|
+
configToolTimeoutMs: input.configToolTimeoutMs,
|
|
3490
3645
|
deadlineAt: input.deadlineAt,
|
|
3491
3646
|
turnBudget: input.turnBudget,
|
|
3492
3647
|
toolBudget: input.toolBudgets[index],
|
|
@@ -3614,7 +3769,9 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3614
3769
|
...(task.model !== undefined ? { model: task.model } : {}),
|
|
3615
3770
|
}));
|
|
3616
3771
|
const modelOverrides: (string | undefined)[] = tasks.map((_, i) =>
|
|
3617
|
-
|
|
3772
|
+
agentConfigs[i]?.runner?.type === "external-cli"
|
|
3773
|
+
? undefined
|
|
3774
|
+
: resolveEffectiveSubagentModel(behaviorOverrides[i]?.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope }),
|
|
3618
3775
|
);
|
|
3619
3776
|
|
|
3620
3777
|
if (params.clarify === true && ctx.hasUI) {
|
|
@@ -3649,7 +3806,9 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3649
3806
|
for (let i = 0; i < result.behaviorOverrides.length; i++) {
|
|
3650
3807
|
const override = result.behaviorOverrides[i];
|
|
3651
3808
|
if (override?.model !== undefined) {
|
|
3652
|
-
modelOverrides[i] =
|
|
3809
|
+
modelOverrides[i] = agentConfigs[i]?.runner?.type === "external-cli"
|
|
3810
|
+
? undefined
|
|
3811
|
+
: resolveEffectiveSubagentModel(override.model, agentConfigs[i]?.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope });
|
|
3653
3812
|
behaviorOverrides[i]!.model = override.model;
|
|
3654
3813
|
}
|
|
3655
3814
|
if (override?.output !== undefined) behaviorOverrides[i]!.output = override.output;
|
|
@@ -3736,6 +3895,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3736
3895
|
usageBudget: data.usageBudget,
|
|
3737
3896
|
toolBudget: data.toolBudget,
|
|
3738
3897
|
configToolBudget: data.configToolBudget,
|
|
3898
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
3899
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
3739
3900
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
3740
3901
|
runFanoutBudget: data.runFanoutBudget,
|
|
3741
3902
|
}));
|
|
@@ -3856,6 +4017,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3856
4017
|
worktreeSetup,
|
|
3857
4018
|
timeoutMs: data.timeoutMs,
|
|
3858
4019
|
deadlineAt,
|
|
4020
|
+
toolTimeoutMs: data.params?.toolTimeoutMs,
|
|
4021
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
3859
4022
|
turnBudget: data.turnBudget,
|
|
3860
4023
|
usageBudget: data.usageBudget,
|
|
3861
4024
|
toolBudgets,
|
|
@@ -4075,6 +4238,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4075
4238
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(task) : task,
|
|
4076
4239
|
goal: task,
|
|
4077
4240
|
agentConfig,
|
|
4241
|
+
recoveryAgentConfig: data.recoveryAgents.find((agent) => agent.name === params.agent),
|
|
4078
4242
|
ctx: asyncCtx,
|
|
4079
4243
|
availableModels,
|
|
4080
4244
|
cwd: effectiveCwd,
|
|
@@ -4099,6 +4263,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4099
4263
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
4100
4264
|
worktreeBaseDir: deps.config.worktreeBaseDir,
|
|
4101
4265
|
controlConfig,
|
|
4266
|
+
intercomBridge: params.intercomBridge,
|
|
4102
4267
|
controlIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
4103
4268
|
childIntercomTarget: data.intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(id, agent, index) : undefined,
|
|
4104
4269
|
nestedRoute: data.nestedRoute,
|
|
@@ -4248,6 +4413,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4248
4413
|
},
|
|
4249
4414
|
timeoutMs: data.timeoutMs,
|
|
4250
4415
|
deadlineAt,
|
|
4416
|
+
toolTimeoutMs: params.toolTimeoutMs,
|
|
4417
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
4251
4418
|
turnBudget: data.turnBudget,
|
|
4252
4419
|
enforceHardTurnLimit: params.enforceHardTurnLimit,
|
|
4253
4420
|
toolBudget: effectiveToolBudget.toolBudget,
|
|
@@ -4326,8 +4493,15 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4326
4493
|
}
|
|
4327
4494
|
|
|
4328
4495
|
if (r.detached) {
|
|
4496
|
+
const statusRecovery = `subagent({ action: "status", id: "${runId}" }) to recover the result; do not resume or launch a replacement while it remains detached.`;
|
|
4497
|
+
const blockingRecovery = `subagent_wait({ id: "${runId}" }). Use ${statusRecovery}`;
|
|
4498
|
+
const message = r.detachedReason === "intercom coordination"
|
|
4499
|
+
? `Detached for intercom coordination: ${params.agent}. Reply to the supervisor request first, then wait with ${blockingRecovery}`
|
|
4500
|
+
: r.detachedReason === "user request"
|
|
4501
|
+
? `Detached at user request: ${params.agent}. The child continues independently. Register a completion wake-up with subagent_wait({ id: "${runId}", nonBlocking: true }), or use ${statusRecovery}`
|
|
4502
|
+
: `Detached before task completion: ${params.agent}. Wait with ${blockingRecovery}`;
|
|
4329
4503
|
return {
|
|
4330
|
-
content: [{ type: "text", text:
|
|
4504
|
+
content: [{ type: "text", text: message }],
|
|
4331
4505
|
details,
|
|
4332
4506
|
};
|
|
4333
4507
|
}
|
|
@@ -4371,17 +4545,28 @@ function duplicateSubagentCallResult(params: SubagentParamsLike): AgentToolResul
|
|
|
4371
4545
|
|
|
4372
4546
|
const workflowLaunchObservers = new WeakMap<object, (launch: { agent: string; sessionFile?: string; async: boolean; runId?: string }) => void>();
|
|
4373
4547
|
|
|
4548
|
+
/**
|
|
4549
|
+
* Terminal-mission retention can remove a mission while its children still
|
|
4550
|
+
* report. Remember it to prevent later heartbeats from warning repeatedly.
|
|
4551
|
+
*/
|
|
4552
|
+
const missionsMissingFromStore = new Set<string>();
|
|
4553
|
+
|
|
4374
4554
|
function recordMissionWorkflowChild(
|
|
4375
4555
|
binding: MissionLaunchBinding | undefined,
|
|
4376
4556
|
workflowRunId: string,
|
|
4377
4557
|
key: string,
|
|
4378
4558
|
update: Omit<MissionWorkflowChildUpdate, "workflowRunId" | "key">,
|
|
4379
4559
|
): void {
|
|
4380
|
-
if (!binding) return;
|
|
4560
|
+
if (!binding || missionsMissingFromStore.has(binding.missionId)) return;
|
|
4381
4561
|
const { task: _task, ...durableUpdate } = update;
|
|
4382
4562
|
try {
|
|
4383
4563
|
updateMission(binding.location, binding.missionId, { upsertWorkflowChildren: [{ workflowRunId, key, ...durableUpdate }] });
|
|
4384
4564
|
} catch (error) {
|
|
4565
|
+
if (error instanceof MissionNotFoundError) {
|
|
4566
|
+
missionsMissingFromStore.add(binding.missionId);
|
|
4567
|
+
console.warn(`[pi-subagents] Mission '${binding.missionId}' is no longer in the mission store; stopped recording its workflow children. Terminal-mission retention can prune a mission while its run is still active.`);
|
|
4568
|
+
return;
|
|
4569
|
+
}
|
|
4385
4570
|
console.warn(`[pi-subagents] Failed to record mission workflow child '${key}': ${error instanceof Error ? error.message : String(error)}`);
|
|
4386
4571
|
}
|
|
4387
4572
|
}
|
|
@@ -4451,6 +4636,7 @@ function workflowChildResult(key: string, result: AgentToolResult<Details>): Wor
|
|
|
4451
4636
|
...(result.details.runId || result.details.asyncId ? { runId: result.details.runId ?? result.details.asyncId } : {}),
|
|
4452
4637
|
output,
|
|
4453
4638
|
...(!ok ? { error: receiptOutput || output || "Child run failed." } : {}),
|
|
4639
|
+
...(detached ? { detached: true } : {}),
|
|
4454
4640
|
...(structured.length === 1 ? { structuredOutput: structured[0] } : structured.length > 1 ? { structuredOutput: structured } : {}),
|
|
4455
4641
|
artifactPaths: [...artifactPaths],
|
|
4456
4642
|
results: result.details.results,
|
|
@@ -4471,16 +4657,19 @@ export function prepareWorkflowLaunchParams(
|
|
|
4471
4657
|
const timeoutMs = childParams.timeoutMs ?? childParams.maxRuntimeMs ?? workflowDefaults.timeoutMs ?? workflowDefaults.maxRuntimeMs;
|
|
4472
4658
|
const turnBudget = childParams.turnBudget ?? workflowDefaults.turnBudget;
|
|
4473
4659
|
const toolBudget = childParams.toolBudget ?? workflowDefaults.toolBudget;
|
|
4660
|
+
const intercomBridge = childParams.intercomBridge ?? workflowDefaults.intercomBridge;
|
|
4474
4661
|
return {
|
|
4475
4662
|
action: "resume",
|
|
4476
4663
|
id: childParams.resume.trim(),
|
|
4477
4664
|
message: typeof childParams.task === "string" ? childParams.task.trim() : "",
|
|
4478
4665
|
workflowParentRunId: parentWorkflowRunId,
|
|
4479
4666
|
workflowKey,
|
|
4667
|
+
...(options.runFanoutBudget ? { runFanoutBudget: { ...options.runFanoutBudget, parentPath: `${options.runFanoutBudget.parentPath ? `${options.runFanoutBudget.parentPath}/` : ""}workflow[${workflowKey}]` } } : {}),
|
|
4480
4668
|
...(options.missionDetached ? { mission: false } : {}),
|
|
4481
4669
|
...(timeoutMs !== undefined ? { timeoutMs: timeoutMs as number } : {}),
|
|
4482
4670
|
...(turnBudget !== undefined ? { turnBudget: turnBudget as TurnBudgetConfig } : {}),
|
|
4483
4671
|
...(toolBudget !== undefined ? { toolBudget: toolBudget as ToolBudgetConfig } : {}),
|
|
4672
|
+
...(intercomBridge !== undefined ? { intercomBridge: intercomBridge as IntercomBridgeConfig } : {}),
|
|
4484
4673
|
};
|
|
4485
4674
|
}
|
|
4486
4675
|
const launchParams = {
|
|
@@ -4667,6 +4856,17 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4667
4856
|
const workflowUsageBudget = validateUsageBudgetConfig(requestParams.usageBudget ?? deps.config.usageBudget, requestParams.usageBudget ? "usageBudget" : "config.usageBudget");
|
|
4668
4857
|
if (workflowUsageBudget.error) return buildRequestedModeError(requestParams, workflowUsageBudget.error);
|
|
4669
4858
|
const workflowCwd = resolveRequestedCwd(parentCwd, requestParams.cwd);
|
|
4859
|
+
const workflowArtifactConfig: ArtifactConfig = omitUndefinedProperties({
|
|
4860
|
+
...DEFAULT_ARTIFACT_CONFIG,
|
|
4861
|
+
enabled: requestParams.artifacts !== false,
|
|
4862
|
+
dir: deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir,
|
|
4863
|
+
});
|
|
4864
|
+
const workflowArtifactsDir = getArtifactsDir(ctx.sessionManager.getSessionFile() ?? null, workflowCwd, workflowArtifactConfig.dir);
|
|
4865
|
+
if (workflowArtifactConfig.dir === "project" && !warnedArtifactPackageDirs.has(workflowCwd)) {
|
|
4866
|
+
warnedArtifactPackageDirs.add(workflowCwd);
|
|
4867
|
+
const warning = getProjectArtifactPackagingWarning(workflowCwd);
|
|
4868
|
+
if (warning) console.warn(`[pi-subagents] ${warning}`);
|
|
4869
|
+
}
|
|
4670
4870
|
const workflowPrompts = { render: (ref: string, vars?: unknown) => renderWorkflowPrompt(ref, vars, workflowCwd) };
|
|
4671
4871
|
const chatProgressResult = resolveWorkflowChatProgress({ requested: requestParams.chatProgress, parentCwd, workflowCwd, background: requestParams.async !== false });
|
|
4672
4872
|
if (chatProgressResult.error) return { content: [{ type: "text", text: chatProgressResult.error }], isError: true, details: { mode: "workflow", results: [] } };
|
|
@@ -4745,7 +4945,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4745
4945
|
if (workflowRunId) {
|
|
4746
4946
|
const toolCallId = _id;
|
|
4747
4947
|
const asyncDir = path.join(DIRS.async, workflowRunId);
|
|
4748
|
-
const resultPath =
|
|
4948
|
+
const resultPath = resultFilePath(DIRS.results, workflowRunId);
|
|
4749
4949
|
const statusPath = path.join(asyncDir, "status.json");
|
|
4750
4950
|
const eventsPath = path.join(asyncDir, "events.jsonl");
|
|
4751
4951
|
const startedAt = Date.now();
|
|
@@ -4784,7 +4984,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4784
4984
|
status.lastUpdate = Date.now();
|
|
4785
4985
|
writeAtomicJson(statusPath, status);
|
|
4786
4986
|
if (indexedState !== status.state) {
|
|
4787
|
-
updateActiveRunIndex(asyncDir, status.state);
|
|
4987
|
+
updateActiveRunIndex(asyncDir, status.state, status.toolCallId);
|
|
4788
4988
|
indexedState = status.state;
|
|
4789
4989
|
}
|
|
4790
4990
|
const job = deps.state.asyncJobs.get(workflowRunId);
|
|
@@ -4809,6 +5009,17 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4809
5009
|
job.workflow = status.workflow;
|
|
4810
5010
|
}
|
|
4811
5011
|
};
|
|
5012
|
+
const writeWorkflowResult = (payload: Record<string, unknown>): boolean => {
|
|
5013
|
+
try {
|
|
5014
|
+
writeAsyncResultFile(resultPath, payload);
|
|
5015
|
+
return true;
|
|
5016
|
+
} catch (error) {
|
|
5017
|
+
const message = `Failed to write async workflow result ${resultPath}: ${error instanceof Error ? error.message : String(error)}`;
|
|
5018
|
+
console.error(message, error);
|
|
5019
|
+
appendWorkflowEvent({ type: "subagent.workflow.result_write_failed", error: message });
|
|
5020
|
+
return false;
|
|
5021
|
+
}
|
|
5022
|
+
};
|
|
4812
5023
|
const projectWorkflowActivity = () => {
|
|
4813
5024
|
const steps = status.steps ?? [];
|
|
4814
5025
|
const runningSteps = steps.filter((step) => step.status === "running");
|
|
@@ -4830,7 +5041,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4830
5041
|
status.toolCount = toolCounts.length > 0 ? toolCounts.reduce((total, count) => total + count, 0) : undefined;
|
|
4831
5042
|
status.currentStep = runningSteps.length === 1 ? steps.indexOf(runningSteps[0]!) : undefined;
|
|
4832
5043
|
};
|
|
4833
|
-
const workflowJob: AsyncJobState = { asyncId: workflowRunId, asyncDir, cwd: workflowCwd, status: "running", sessionId: currentSessionId ?? undefined, mode: "workflow", agents: [], steps: [], startedAt, updatedAt: startedAt, ...(timeout !== undefined ? { timeoutMs: timeout, deadlineAt: startedAt + timeout } : {}), workflow: status.workflow };
|
|
5044
|
+
const workflowJob: AsyncJobState = { asyncId: workflowRunId, asyncDir, toolCallId, cwd: workflowCwd, status: "running", sessionId: currentSessionId ?? undefined, mode: "workflow", agents: [], steps: [], startedAt, updatedAt: startedAt, ...(timeout !== undefined ? { timeoutMs: timeout, deadlineAt: startedAt + timeout } : {}), workflow: status.workflow };
|
|
4834
5045
|
deps.state.asyncJobs.set(workflowRunId, workflowJob);
|
|
4835
5046
|
deps.state.fleetJobs ??= new Map();
|
|
4836
5047
|
deps.state.fleetJobs.set(workflowRunId, workflowJob);
|
|
@@ -4840,6 +5051,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4840
5051
|
void Promise.resolve().then(async () => {
|
|
4841
5052
|
const workflowResults: SingleResult[] = [];
|
|
4842
5053
|
const { action: _action, agent: _agent, task: _task, resume: _resume, tasks: _tasks, chain: _chain, concurrency: _concurrency, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, missionId: _missionId, mission: _mission, ...workflowChildDefaults } = workflowRequest;
|
|
5054
|
+
const workflowOutput = typeof workflowChildDefaults.output === "string" || typeof workflowChildDefaults.output === "boolean" ? workflowChildDefaults.output : undefined;
|
|
5055
|
+
const configuredOutputBaseDir = resolveConfiguredSingleRunOutputBaseDir(deps);
|
|
5056
|
+
const workflowAggregateOutputPath = resolveWorkflowAggregateOutputPath(workflowOutput, ctx.cwd, workflowCwd, resolveSingleRunOutputBaseDir(deps, workflowArtifactsDir, workflowRunId), configuredOutputBaseDir);
|
|
5057
|
+
const claimedOutputPaths = new Map<string, string>();
|
|
4843
5058
|
const workflowSteps = new Map<string, NonNullable<AsyncStatus["steps"]>[number]>();
|
|
4844
5059
|
let projectedTraceLength = 0;
|
|
4845
5060
|
let projectedTraceTail: NonNullable<Details["workflow"]>["trace"][number] | undefined;
|
|
@@ -4859,12 +5074,24 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4859
5074
|
if (entry.operation !== "run") continue;
|
|
4860
5075
|
const existing = workflowSteps.get(entry.key);
|
|
4861
5076
|
if (entry.state === "reused" && existing) continue;
|
|
4862
|
-
const mapped = entry.state === "started" || entry.state === "reused"
|
|
5077
|
+
const mapped = entry.state === "started" || entry.state === "reused"
|
|
5078
|
+
? "running"
|
|
5079
|
+
: entry.state === "completed"
|
|
5080
|
+
? "completed"
|
|
5081
|
+
: entry.state === "stopped"
|
|
5082
|
+
? "stopped"
|
|
5083
|
+
: entry.state === "detached"
|
|
5084
|
+
? "paused"
|
|
5085
|
+
: "failed";
|
|
4863
5086
|
if (existing) {
|
|
4864
5087
|
existing.status = mapped;
|
|
4865
5088
|
if (entry.agent) existing.agent = entry.agent;
|
|
4866
5089
|
if (entry.runId) existing.runId = entry.runId;
|
|
4867
5090
|
if (entry.state === "failed" && !entry.runId && existing.async === undefined) existing.async = false;
|
|
5091
|
+
if (entry.state === "detached") existing.activityState = "needs_attention";
|
|
5092
|
+
else if (existing.status !== "running") delete existing.activityState;
|
|
5093
|
+
if (entry.state === "stopped") existing.stopped = true;
|
|
5094
|
+
else delete existing.stopped;
|
|
4868
5095
|
if (entry.error === undefined) delete existing.error;
|
|
4869
5096
|
else existing.error = entry.error;
|
|
4870
5097
|
if (entry.durationMs === undefined) delete existing.durationMs;
|
|
@@ -4879,6 +5106,8 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4879
5106
|
startedAt: Date.now(),
|
|
4880
5107
|
...(entry.runId ? { runId: entry.runId } : {}),
|
|
4881
5108
|
...(entry.state === "failed" && !entry.runId ? { async: false } : {}),
|
|
5109
|
+
...(entry.state === "detached" ? { activityState: "needs_attention" as const } : {}),
|
|
5110
|
+
...(entry.state === "stopped" ? { stopped: true } : {}),
|
|
4882
5111
|
};
|
|
4883
5112
|
status.steps?.push(step);
|
|
4884
5113
|
workflowSteps.set(entry.key, step);
|
|
@@ -4908,7 +5137,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4908
5137
|
...(workflowState ? { state: workflowState } : {}),
|
|
4909
5138
|
onTrace: updateTrace,
|
|
4910
5139
|
admit: (calls) => {
|
|
5140
|
+
const outputClaims = workflowChildOutputClaims({ ctxCwd: ctx.cwd, workflowCwd, artifactsDir: workflowArtifactsDir, workflowRunId, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: deps.discoverAgents, workflowAgentScope: workflowChildDefaults.agentScope, claimedOutputPaths, entries: calls });
|
|
5141
|
+
if (outputClaims.error) throw new Error(outputClaims.error);
|
|
4911
5142
|
status.runFanoutBudget = claimRunFanoutBatch(workflowFanoutBudget, calls.map(({ key }) => `workflow[${key}]`));
|
|
5143
|
+
if (outputClaims.claims) applyWorkflowChildOutputClaims(claimedOutputPaths, outputClaims.claims);
|
|
4912
5144
|
persist();
|
|
4913
5145
|
},
|
|
4914
5146
|
onEmit: (emits) => {
|
|
@@ -4932,7 +5164,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4932
5164
|
});
|
|
4933
5165
|
const result = await runMissionWorkflowChild(missionBinding, workflowRunId, key, childPhase, () => {
|
|
4934
5166
|
const childRequest = bindMissionWorkflowChildAsyncLaunch(
|
|
4935
|
-
{ ...
|
|
5167
|
+
{ ...prepareWorkflowChildLaunchParams({ workflowDefaults: workflowChildDefaults, childParams, parentWorkflowRunId: workflowRunId, workflowKey: key, ctxCwd: ctx.cwd, workflowCwd, artifactsDir: workflowArtifactsDir, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: deps.discoverAgents, workflowAgentScope: workflowChildDefaults.agentScope, options: { missionDetached: detachWorkflowChildMissions, runFanoutBudget: workflowFanoutBudget } }), runFanoutAdmitted: admission.admitted },
|
|
4936
5168
|
missionBinding,
|
|
4937
5169
|
deps.asyncByDefault,
|
|
4938
5170
|
);
|
|
@@ -4950,7 +5182,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4950
5182
|
return execute(randomUUID(), childRequest, workflowSignal, (update) => {
|
|
4951
5183
|
const progress = update.details.progress?.[0];
|
|
4952
5184
|
const step = status.steps?.find((candidate) => candidate.workflowKey === key);
|
|
4953
|
-
if (!progress || !step) return;
|
|
5185
|
+
if (!progress || !step || step.stopped) return;
|
|
4954
5186
|
step.status = progress.status === "completed" ? "completed" : progress.status === "failed" ? "failed" : "running";
|
|
4955
5187
|
step.activityState = progress.activityState;
|
|
4956
5188
|
step.lastActivityAt = progress.lastActivityAt;
|
|
@@ -5016,23 +5248,40 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5016
5248
|
const summary = `${relaunchNote}Workflow completed with ${workflow.children.length} child run(s). Return: ${returnPreview}${emitPreview} Trace: ${workflow.trace.length} event(s).`;
|
|
5017
5249
|
const workflowUsage = sumResultsUsage(workflowResults);
|
|
5018
5250
|
if (capReached) {
|
|
5019
|
-
|
|
5020
|
-
|
|
5251
|
+
const relaunchCapError = `Workflow auto-relaunch cap reached after ${relaunched} relaunch(es); the goal is not clean yet. The progress file is current; raise config.maxWorkflowAutoRelaunches or relaunch manually.`;
|
|
5252
|
+
status = compactOptional<AsyncStatus>({ ...status, state: "failed", error: relaunchCapError, endedAt: Date.now(), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console } });
|
|
5253
|
+
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, relaunchCapError);
|
|
5254
|
+
const resultSummary = appendWorkflowOutputWarning(relaunchCapError, outputWarning);
|
|
5255
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: false, state: "failed", summary: resultSummary, error: relaunchCapError, results: workflow.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, asyncDir, cwd: workflowCwd, sessionId: currentSessionId, timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
5021
5256
|
persist();
|
|
5022
5257
|
appendWorkflowEvent({ type: "subagent.workflow.completed", state: "failed", error: status.error });
|
|
5023
5258
|
} else {
|
|
5259
|
+
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, summary);
|
|
5260
|
+
const resultSummary = appendWorkflowOutputWarning(summary, outputWarning);
|
|
5024
5261
|
status = { ...status, state: "complete", endedAt: Date.now(), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, totalTokens: { input: workflowUsage.input, output: workflowUsage.output, total: workflowUsage.input + workflowUsage.output }, totalCost: sumResultsCost(workflowResults) };
|
|
5025
|
-
|
|
5262
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, results: workflow.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, asyncDir, cwd: workflowCwd, sessionId: currentSessionId, timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
5026
5263
|
persist();
|
|
5027
|
-
appendWorkflowEvent({ type: "subagent.workflow.completed", state:
|
|
5264
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}) });
|
|
5028
5265
|
}
|
|
5029
5266
|
} catch (error) {
|
|
5030
5267
|
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
5031
5268
|
const stopped = controller.signal.aborted;
|
|
5032
|
-
|
|
5033
|
-
|
|
5269
|
+
const detachedChildKeys = new Set(partial.children.filter((child) => child.detached).map((child) => child.key));
|
|
5270
|
+
const hasRealFailedChild = partial.children.some((child) => !child.ok && !child.detached);
|
|
5271
|
+
const pauseForDetached = !stopped && error instanceof WorkflowScriptError && error.errorKind === "detached-child" && detachedChildKeys.size > 0 && !hasRealFailedChild;
|
|
5272
|
+
const state = stopped ? "stopped" : pauseForDetached ? "paused" : "failed";
|
|
5273
|
+
for (const step of status.steps ?? []) {
|
|
5274
|
+
if (step.workflowKey && detachedChildKeys.has(step.workflowKey)) {
|
|
5275
|
+
step.status = "paused";
|
|
5276
|
+
step.activityState = "needs_attention";
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
status = compactOptional<AsyncStatus>({ ...status, state, stopped: stopped || undefined, activityState: pauseForDetached ? "needs_attention" : undefined, error: error instanceof Error ? error.message : String(error), endedAt: Date.now(), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console } });
|
|
5280
|
+
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, status.error ?? (pauseForDetached ? "Workflow paused." : "Workflow failed."));
|
|
5281
|
+
const resultSummary = appendWorkflowOutputWarning(status.error ?? (pauseForDetached ? "Workflow paused." : "Workflow failed."), outputWarning);
|
|
5282
|
+
if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: false, state: status.state, summary: resultSummary, error: status.error, stopped: status.stopped, activityState: status.activityState, results: partial.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.detached ? { detached: true } : {}), ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, asyncDir, cwd: workflowCwd, sessionId: currentSessionId, timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
|
|
5034
5283
|
persist();
|
|
5035
|
-
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, error: status.error });
|
|
5284
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, error: status.error, ...(status.activityState ? { activityState: status.activityState } : {}) });
|
|
5036
5285
|
} finally {
|
|
5037
5286
|
deps.state.workflowControllers?.delete(workflowRunId);
|
|
5038
5287
|
deps.state.activeAsyncCapacity = workflowCapacity?.reconcile(new Set(deps.state.workflowControllers?.keys() ?? []))
|
|
@@ -5045,6 +5294,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5045
5294
|
}, workflowFanoutBudget));
|
|
5046
5295
|
}
|
|
5047
5296
|
const { workflowScript: _workflowScript, action: _action, agent: _agent, task: _task, resume: _resume, tasks: _tasks, chain: _chain, concurrency: _concurrency, async: _async, foregroundOnly: _foregroundOnly, clarify: _clarify, timeoutMs: _timeoutMs, maxRuntimeMs: _maxRuntimeMs, usageBudget: _usageBudget, chatProgress: _chatProgress, missionId: _missionId, mission: _mission, ...workflowChildDefaults } = requestParams;
|
|
5297
|
+
const workflowOutput = typeof workflowChildDefaults.output === "string" || typeof workflowChildDefaults.output === "boolean" ? workflowChildDefaults.output : undefined;
|
|
5298
|
+
const configuredOutputBaseDir = resolveConfiguredSingleRunOutputBaseDir(deps);
|
|
5299
|
+
const workflowAggregateOutputPath = resolveWorkflowAggregateOutputPath(workflowOutput, ctx.cwd, workflowCwd, resolveSingleRunOutputBaseDir(deps, workflowArtifactsDir, _id), configuredOutputBaseDir);
|
|
5300
|
+
const claimedOutputPaths = new Map<string, string>();
|
|
5048
5301
|
const workflowResults: SingleResult[] = [];
|
|
5049
5302
|
let liveWorkflow: NonNullable<Details["workflow"]> = { trace: [], emits: [], console: [] };
|
|
5050
5303
|
const sendWorkflowProgress = () => {
|
|
@@ -5063,7 +5316,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5063
5316
|
sendWorkflowProgress();
|
|
5064
5317
|
},
|
|
5065
5318
|
admit: (calls) => {
|
|
5319
|
+
const outputClaims = workflowChildOutputClaims({ ctxCwd: ctx.cwd, workflowCwd, artifactsDir: workflowArtifactsDir, workflowRunId: _id, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: deps.discoverAgents, workflowAgentScope: workflowChildDefaults.agentScope, claimedOutputPaths, entries: calls });
|
|
5320
|
+
if (outputClaims.error) throw new Error(outputClaims.error);
|
|
5066
5321
|
claimRunFanoutBatch(workflowFanoutBudget, calls.map(({ key }) => `workflow[${key}]`));
|
|
5322
|
+
if (outputClaims.claims) applyWorkflowChildOutputClaims(claimedOutputPaths, outputClaims.claims);
|
|
5067
5323
|
},
|
|
5068
5324
|
onEmit: (emits) => {
|
|
5069
5325
|
liveWorkflow = { ...liveWorkflow, emits };
|
|
@@ -5084,7 +5340,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5084
5340
|
});
|
|
5085
5341
|
const result = await runMissionWorkflowChild(missionBinding, _id, key, childPhase, () => {
|
|
5086
5342
|
const childRequest = bindMissionWorkflowChildAsyncLaunch(
|
|
5087
|
-
{ ...
|
|
5343
|
+
{ ...prepareWorkflowChildLaunchParams({ workflowDefaults: workflowChildDefaults, childParams, parentWorkflowRunId: _id, workflowKey: key, ctxCwd: ctx.cwd, workflowCwd, artifactsDir: workflowArtifactsDir, aggregateOutputPath: workflowAggregateOutputPath, configuredOutputBaseDir, discoverAgents: deps.discoverAgents, workflowAgentScope: workflowChildDefaults.agentScope, options: { missionDetached: detachWorkflowChildMissions, suppressRoutineResultIntercom: chatProgress.mode === "live-card", runFanoutBudget: workflowFanoutBudget } }), runFanoutAdmitted: admission.admitted },
|
|
5088
5344
|
missionBinding,
|
|
5089
5345
|
deps.asyncByDefault,
|
|
5090
5346
|
);
|
|
@@ -5125,8 +5381,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5125
5381
|
if (workflow.emits.length > 0) sections.push(`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5126
5382
|
if (workflow.console.length > 0) sections.push(`Console:\n${workflow.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5127
5383
|
if (traceLines.length > 0) sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
5384
|
+
const workflowText = sections.join("\n\n");
|
|
5385
|
+
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, workflowText);
|
|
5386
|
+
const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
|
|
5128
5387
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5129
|
-
content: [{ type: "text", text:
|
|
5388
|
+
content: [{ type: "text", text: displayText }],
|
|
5130
5389
|
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, chatProgress }),
|
|
5131
5390
|
}, workflowFanoutBudget));
|
|
5132
5391
|
} catch (error) {
|
|
@@ -5137,8 +5396,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5137
5396
|
if (partial.emits.length > 0) sections.push(`Emitted:\n${partial.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5138
5397
|
if (partial.console.length > 0) sections.push(`Console:\n${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5139
5398
|
if (traceLines.length > 0) sections.push(`Call trace:\n${traceLines.join("\n")}`);
|
|
5399
|
+
const workflowText = sections.join("\n\n");
|
|
5400
|
+
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, workflowText);
|
|
5401
|
+
const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
|
|
5140
5402
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5141
|
-
content: [{ type: "text", text:
|
|
5403
|
+
content: [{ type: "text", text: displayText }],
|
|
5142
5404
|
isError: true,
|
|
5143
5405
|
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console }, chatProgress }),
|
|
5144
5406
|
}, workflowFanoutBudget));
|
|
@@ -5402,11 +5664,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5402
5664
|
details: { mode: "management", results: [], spawnBudget, activeAsyncCapacity },
|
|
5403
5665
|
};
|
|
5404
5666
|
}
|
|
5405
|
-
if (action === "status") {
|
|
5667
|
+
if (action === "status" || action === "debug.run") {
|
|
5406
5668
|
if (!preserveActiveSession) deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
5407
5669
|
const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
|
|
5408
5670
|
const hasDirectoryTarget = Boolean(paramsWithResolvedCwd.dir);
|
|
5409
|
-
const targetLabel = formatStatusTargetLabel(paramsWithResolvedCwd, targetRunId);
|
|
5671
|
+
const targetLabel = action === "debug.run" ? "Debug run" : formatStatusTargetLabel(paramsWithResolvedCwd, targetRunId);
|
|
5410
5672
|
const withBudget = (result: AgentToolResult<Details>) => {
|
|
5411
5673
|
const budgeted = withSpawnBudgetStatus(result, deps.state, deps.config, deps.state.currentSessionId);
|
|
5412
5674
|
return {
|
|
@@ -5418,6 +5680,15 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5418
5680
|
};
|
|
5419
5681
|
const nestedScope = nestedResolutionScopeForExecutor(deps);
|
|
5420
5682
|
const sessionRoots = trustedSessionRootsForStatus(ctx, deps);
|
|
5683
|
+
if (action === "debug.run") {
|
|
5684
|
+
if (!targetRunId && !hasDirectoryTarget) {
|
|
5685
|
+
return withBudget({ content: [{ type: "text", text: "action='debug.run' requires id, runId, or dir." }], isError: true, details: { mode: "management", results: [] } });
|
|
5686
|
+
}
|
|
5687
|
+
if (paramsWithResolvedCwd.view) {
|
|
5688
|
+
return withBudget({ content: [{ type: "text", text: "action='debug.run' does not support status views." }], isError: true, details: { mode: "management", results: [] } });
|
|
5689
|
+
}
|
|
5690
|
+
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots })));
|
|
5691
|
+
}
|
|
5421
5692
|
if (paramsWithResolvedCwd.view === "fleet") {
|
|
5422
5693
|
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots })));
|
|
5423
5694
|
}
|
|
@@ -5807,6 +6078,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5807
6078
|
const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
5808
6079
|
const intercomBridge = resolveIntercomBridge({
|
|
5809
6080
|
config: deps.config.intercomBridge,
|
|
6081
|
+
override: effectiveParams.intercomBridge,
|
|
5810
6082
|
context: effectiveParams.context ?? (contextPolicy.usesFork ? "fork" : undefined),
|
|
5811
6083
|
orchestratorTarget: sessionName,
|
|
5812
6084
|
});
|
|
@@ -5855,6 +6127,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5855
6127
|
const parentModel = requestParentModel;
|
|
5856
6128
|
prepareForkThinking = (agentName, index, modelOverride) => {
|
|
5857
6129
|
const agentConfig = agents.find((agent) => agent.name === agentName);
|
|
6130
|
+
if (agentConfig?.runner?.type === "external-cli") {
|
|
6131
|
+
forkThinkingRequirements.set(index, true);
|
|
6132
|
+
return;
|
|
6133
|
+
}
|
|
5858
6134
|
const primaryModel = resolveEffectiveSubagentModel(
|
|
5859
6135
|
modelOverride,
|
|
5860
6136
|
agentConfig?.model,
|
|
@@ -6069,6 +6345,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6069
6345
|
signal,
|
|
6070
6346
|
onUpdate: onUpdateWithContext,
|
|
6071
6347
|
agents,
|
|
6348
|
+
recoveryAgents: discoveredAgents,
|
|
6072
6349
|
runId,
|
|
6073
6350
|
shareEnabled,
|
|
6074
6351
|
sessionRoot,
|
|
@@ -6090,6 +6367,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6090
6367
|
usageBudget: usageBudget.budget,
|
|
6091
6368
|
allowZeroToolBudget,
|
|
6092
6369
|
configToolBudget: configToolBudget.toolBudget,
|
|
6370
|
+
configToolTimeoutMs: deps.config.toolTimeoutMs,
|
|
6093
6371
|
contextPolicy,
|
|
6094
6372
|
modelScope,
|
|
6095
6373
|
parentModel: requestParentModel,
|
|
@@ -6259,7 +6537,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6259
6537
|
};
|
|
6260
6538
|
|
|
6261
6539
|
let nestedForegroundStarted = false;
|
|
6540
|
+
let asyncLaunchFailed = false;
|
|
6262
6541
|
try {
|
|
6542
|
+
if (effectiveAsync) {
|
|
6543
|
+
deps.state.liveAsyncSessionRoots ??= new Map();
|
|
6544
|
+
deps.state.liveAsyncSessionRoots.set(asyncRunId, sessionRoot);
|
|
6545
|
+
}
|
|
6263
6546
|
if (workflowLaunchObserver) {
|
|
6264
6547
|
const singleTask = hasTasks && effectiveParams.tasks?.length === 1 ? effectiveParams.tasks[0] : undefined;
|
|
6265
6548
|
const launch = hasSingle
|
|
@@ -6273,7 +6556,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6273
6556
|
}
|
|
6274
6557
|
}
|
|
6275
6558
|
const asyncResult = runAsyncPath(execData, deps);
|
|
6276
|
-
if (asyncResult)
|
|
6559
|
+
if (asyncResult) {
|
|
6560
|
+
asyncLaunchFailed = asyncResult.isError === true;
|
|
6561
|
+
return attachMission(withRunFanoutBudget(withResolvedContext(withForkThinkingNotes(asyncResult, forkThinkingDowngrades), contextPolicy.contextSummary), runFanoutBudget));
|
|
6562
|
+
}
|
|
6277
6563
|
if (foregroundControl) {
|
|
6278
6564
|
writeNestedForegroundEvent("subagent.nested.started");
|
|
6279
6565
|
nestedForegroundStarted = true;
|
|
@@ -6295,10 +6581,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6295
6581
|
return attachMission(withRunFanoutBudget(withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary), runFanoutBudget, { annotateContent: runFanoutAnnotateContent }));
|
|
6296
6582
|
}
|
|
6297
6583
|
} catch (error) {
|
|
6584
|
+
asyncLaunchFailed = effectiveAsync;
|
|
6298
6585
|
const errorResult = withForkThinkingNotes(toExecutionErrorResult(effectiveParams, error, contextPolicy.contextSummary), forkThinkingDowngrades);
|
|
6299
6586
|
if (nestedForegroundStarted) writeNestedForegroundEvent("subagent.nested.completed", errorResult);
|
|
6300
6587
|
return attachMission(errorResult);
|
|
6301
6588
|
} finally {
|
|
6589
|
+
if (effectiveAsync && (asyncLaunchFailed || (activeAsyncCapacity && !activeAsyncCapacity.owner.runnerStartedAt))) deps.state.liveAsyncSessionRoots?.delete(asyncRunId);
|
|
6302
6590
|
if (activeAsyncCapacity && !activeAsyncCapacity.owner.runnerStartedAt) activeAsyncCapacity.rollback();
|
|
6303
6591
|
if (foregroundControl) {
|
|
6304
6592
|
settleForegroundSchedulingOwner(foregroundControl);
|