@selesai/code 0.8.5 → 0.8.7
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 +28 -0
- package/dist/core/agent-session.js +13 -1
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/provider-composer.js +17 -4
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.js +3 -0
- package/dist/core/system-prompt.js +2 -8
- package/dist/core/system-prompt.test.js +6 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.js +1 -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/defaults/models.json +5 -0
- package/dist/defaults/settings.json +1 -0
- package/dist/extensions/agent-browser.test.ts +178 -2
- package/dist/extensions/agent-browser.ts +2 -0
- package/dist/extensions/copy-turn.test.ts +229 -0
- package/dist/extensions/copy-turn.ts +11 -0
- package/dist/extensions/grep-app/index.test.ts +356 -1
- package/dist/extensions/grep-app/index.ts +6 -1
- package/dist/extensions/handoff-new.test.ts +351 -161
- package/dist/extensions/handoff-new.ts +3 -0
- package/dist/extensions/inline-skills.test.ts +93 -0
- package/dist/extensions/inline-skills.ts +3 -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/builder.md +5 -2
- package/dist/extensions/pi-subagents/agents/commentator.md +1 -1
- 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 -11
- 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 +4 -4
- 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 +16 -15
- 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 +59 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +146 -23
- 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 +17 -6
- 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 +11 -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/notify.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +224 -42
- 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 +35 -26
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +108 -9
- 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/background/wait-subscriptions.ts +2 -1
- 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/foreground-history.ts +7 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +368 -50
- 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/session-lineage.ts +71 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +66 -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 +129 -17
- 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/src/workflows/workflow-auto-relaunch.ts +28 -0
- 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 +369 -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/handoff-adoption.test.ts +103 -0
- 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 +91 -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/session-lineage.test.ts +73 -0
- 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-auto-relaunch.test.ts +45 -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/ponytail/index.js +11 -0
- package/dist/extensions/ponytail/ponytail-config.cjs +2 -0
- package/dist/extensions/ponytail/ponytail-instructions.cjs +6 -0
- package/dist/extensions/ponytail/test/extension.test.js +274 -140
- package/dist/extensions/ponytail/test/helpers.test.js +280 -92
- package/dist/extensions/question/index.ts +33 -0
- package/dist/extensions/question/question-list.ts +28 -0
- package/dist/extensions/question/row-layout.ts +3 -0
- package/dist/extensions/question/tests/batch.test.ts +103 -65
- 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 +75 -35
- package/dist/extensions/question/tests/question-list.test.ts +640 -198
- package/dist/extensions/question/tests/row-layout.test.ts +193 -114
- package/dist/extensions/question/tests/schemas.test.ts +42 -19
- package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
- package/dist/extensions/question/tests/shortcuts.test.ts +106 -84
- package/dist/extensions/question/tests/wizard.test.ts +771 -50
- 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/rtk.test.ts +180 -1
- package/dist/extensions/tokenin-onboarding.ts +3 -0
- package/dist/extensions/undo.test.ts +720 -0
- package/dist/extensions/undo.ts +6 -0
- package/dist/extensions/web-agent-onboarding.test.ts +415 -0
- package/dist/extensions/workflow/extension.ts +3 -3
- package/dist/extensions/workflow/modes.ts +41 -19
- 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 +16 -15
- 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/docs/plans/workflow-autoloop-reference.md +1 -2
- package/docs/plans/workflow-handoff-carryover.md +108 -0
- package/docs/settings.md +6 -0
- package/package.json +4 -1
|
@@ -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,13 +109,14 @@ 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";
|
|
115
116
|
import { handleHerdrInspectorAction, HERDR_INSPECTOR_ACTIONS } from "../../inspectors/herdr/actions.ts";
|
|
116
117
|
import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.ts";
|
|
117
118
|
import { previewSimpleWorkflowRun, runWorkflowScript, WorkflowScriptError, type WorkflowScriptChildResult } from "../../workflows/scripted-workflow.ts";
|
|
119
|
+
import { resolveAutoRelaunchDecision, resolveMaxWorkflowAutoRelaunches } from "../../workflows/workflow-auto-relaunch.ts";
|
|
118
120
|
import { renderWorkflowPrompt } from "../../shared/prompt-resources.ts";
|
|
119
121
|
import { resolveWorkflowChatProgress, type WorkflowChatProgressProjection } from "../../workflows/chat-progress.ts";
|
|
120
122
|
import {
|
|
@@ -139,6 +141,7 @@ import {
|
|
|
139
141
|
type Details,
|
|
140
142
|
type ExtensionConfig,
|
|
141
143
|
type ForegroundRunControl,
|
|
144
|
+
type IntercomBridgeConfig,
|
|
142
145
|
type IntercomEventBus,
|
|
143
146
|
type JsonSchemaObject,
|
|
144
147
|
type MaxOutputConfig,
|
|
@@ -300,10 +303,14 @@ export interface SubagentParamsLike {
|
|
|
300
303
|
concurrency?: number;
|
|
301
304
|
worktree?: boolean;
|
|
302
305
|
context?: "fresh" | "fork";
|
|
306
|
+
/** Per-run intercom bridge config. It replaces the global config for this launch only. */
|
|
307
|
+
intercomBridge?: IntercomBridgeConfig;
|
|
303
308
|
async?: boolean;
|
|
304
309
|
foregroundOnly?: boolean;
|
|
305
310
|
timeoutMs?: number;
|
|
306
311
|
maxRuntimeMs?: number;
|
|
312
|
+
/** Optional hard per-tool-call timeout (ms). Known-fast tools also have a default. */
|
|
313
|
+
toolTimeoutMs?: number;
|
|
307
314
|
turnBudget?: TurnBudgetConfig;
|
|
308
315
|
/** Internal-only strict turn-boundary enforcement for versioned foreground delegation. */
|
|
309
316
|
enforceHardTurnLimit?: boolean;
|
|
@@ -387,6 +394,8 @@ interface ExecutionContextData {
|
|
|
387
394
|
signal: AbortSignal;
|
|
388
395
|
onUpdate?: (r: AgentToolResult<Details>) => void;
|
|
389
396
|
agents: AgentConfig[];
|
|
397
|
+
/** Discovered agent definitions before per-run bridge injection. */
|
|
398
|
+
recoveryAgents: AgentConfig[];
|
|
390
399
|
runId: string;
|
|
391
400
|
shareEnabled: boolean;
|
|
392
401
|
sessionRoot: string;
|
|
@@ -404,6 +413,8 @@ interface ExecutionContextData {
|
|
|
404
413
|
nestedRoute?: NestedRouteInfo;
|
|
405
414
|
timeoutMs?: number;
|
|
406
415
|
deadlineAt?: number;
|
|
416
|
+
/** Raw global config.toolTimeoutMs, for per-step resolution in async runners. */
|
|
417
|
+
configToolTimeoutMs?: number;
|
|
407
418
|
turnBudget?: ResolvedTurnBudget;
|
|
408
419
|
toolBudget?: ResolvedToolBudget;
|
|
409
420
|
usageBudget?: UsageBudgetConfig;
|
|
@@ -781,7 +792,8 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
|
|
|
781
792
|
function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState): { runId: string; mode: SubagentRunMode; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
|
|
782
793
|
const requested = (params.id ?? params.runId)?.trim();
|
|
783
794
|
if (!requested || !state.foregroundRuns?.size || !state.currentSessionId) return undefined;
|
|
784
|
-
const
|
|
795
|
+
const acceptedSessions = new Set(state.sessionLineage?.length ? state.sessionLineage : [state.currentSessionId]);
|
|
796
|
+
const sessionRuns = [...state.foregroundRuns.values()].filter((run) => run.sessionId !== undefined && acceptedSessions.has(run.sessionId));
|
|
785
797
|
const direct = sessionRuns.find((run) => run.runId === requested);
|
|
786
798
|
const matches = direct ? [direct] : sessionRuns.filter((run) => run.runId.startsWith(requested));
|
|
787
799
|
if (matches.length === 0) return undefined;
|
|
@@ -1511,17 +1523,18 @@ async function resumeAsyncRun(input: {
|
|
|
1511
1523
|
const discoveredAgents = discovered.agents;
|
|
1512
1524
|
const modelScope = discovered.modelScope;
|
|
1513
1525
|
const sessionName = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
|
|
1526
|
+
const recoveryDescriptor = "recoveryDescriptor" in target ? target.recoveryDescriptor : undefined;
|
|
1514
1527
|
const intercomBridge = resolveIntercomBridge({
|
|
1515
1528
|
config: input.deps.config.intercomBridge,
|
|
1529
|
+
override: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
|
|
1516
1530
|
context: input.params.context,
|
|
1517
1531
|
orchestratorTarget: sessionName,
|
|
1518
1532
|
});
|
|
1519
1533
|
const agents = intercomBridge.active
|
|
1520
1534
|
? discoveredAgents.map((agent) => applyIntercomBridgeToAgent(agent, intercomBridge))
|
|
1521
1535
|
: discoveredAgents;
|
|
1522
|
-
const
|
|
1523
|
-
const
|
|
1524
|
-
const agentConfig: AgentConfig | undefined = discoveredAgentConfig ?? (recoveryDescriptor ? {
|
|
1536
|
+
const discoveredAgentConfig = discoveredAgents.find((agent) => agent.name === target.agent);
|
|
1537
|
+
const baseAgentConfig: AgentConfig | undefined = discoveredAgentConfig ?? (recoveryDescriptor ? {
|
|
1525
1538
|
name: recoveryDescriptor.agent,
|
|
1526
1539
|
description: "Persisted async recovery contract",
|
|
1527
1540
|
systemPrompt: "",
|
|
@@ -1531,7 +1544,7 @@ async function resumeAsyncRun(input: {
|
|
|
1531
1544
|
source: "project",
|
|
1532
1545
|
filePath: recoveryDescriptor.agentFilePath ?? path.join(getProjectSubagentsDir(recoveryDescriptor.cwd), "recovery-agent"),
|
|
1533
1546
|
} : undefined);
|
|
1534
|
-
if (!
|
|
1547
|
+
if (!baseAgentConfig) {
|
|
1535
1548
|
return {
|
|
1536
1549
|
content: [{ type: "text", text: `Unknown agent for resume: ${target.agent}` }],
|
|
1537
1550
|
isError: true,
|
|
@@ -1672,7 +1685,8 @@ async function resumeAsyncRun(input: {
|
|
|
1672
1685
|
if (error instanceof ActiveAsyncCapacityError) return { content: [{ type: "text", text: error.message }], isError: true, details: { mode: "single", results: [], activeAsyncCapacity: error.snapshot } };
|
|
1673
1686
|
return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "single", results: [] } };
|
|
1674
1687
|
}
|
|
1675
|
-
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(
|
|
1688
|
+
const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(baseAgentConfig, recoveryDescriptor) : baseAgentConfig;
|
|
1689
|
+
const agentConfig = intercomBridge.active ? applyIntercomBridgeToAgent(recoveryAgentConfig, intercomBridge) : recoveryAgentConfig;
|
|
1676
1690
|
const artifactConfig: ArtifactConfig = recoveryDescriptor?.artifactConfig ?? omitUndefinedProperties({ ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false, dir: input.deps.config.artifactDir ?? DEFAULT_ARTIFACT_CONFIG.dir });
|
|
1677
1691
|
const artifactsDir = recoveryDescriptor?.artifactsDir ?? getArtifactsDir(parentSessionFile, effectiveCwd, artifactConfig.dir);
|
|
1678
1692
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
@@ -1682,7 +1696,8 @@ async function resumeAsyncRun(input: {
|
|
|
1682
1696
|
agent: target.agent,
|
|
1683
1697
|
task: buildRevivedAsyncTask(target as Parameters<typeof buildRevivedAsyncTask>[0], effectiveFollowUp),
|
|
1684
1698
|
goal: effectiveFollowUp,
|
|
1685
|
-
agentConfig
|
|
1699
|
+
agentConfig,
|
|
1700
|
+
recoveryAgentConfig,
|
|
1686
1701
|
ctx: compactOptional<Parameters<typeof executeAsyncSingle>[1]["ctx"]>({
|
|
1687
1702
|
pi: input.deps.pi,
|
|
1688
1703
|
cwd: input.requestCwd,
|
|
@@ -1717,6 +1732,7 @@ async function resumeAsyncRun(input: {
|
|
|
1717
1732
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
1718
1733
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1719
1734
|
controlConfig: recoveryDescriptor?.controlConfig ?? resolveControlConfig(input.deps.config.control, input.params.control),
|
|
1735
|
+
intercomBridge: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
|
|
1720
1736
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
1721
1737
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
1722
1738
|
availableModels,
|
|
@@ -1731,7 +1747,7 @@ async function resumeAsyncRun(input: {
|
|
|
1731
1747
|
...(input.params.turnBudget !== undefined ? { turnBudget: input.params.turnBudget } : {}),
|
|
1732
1748
|
...(input.params.toolBudget !== undefined ? { toolBudget: input.params.toolBudget } : {}),
|
|
1733
1749
|
capabilityCeiling: intersectSubagentCapabilityCeilings("capabilityCeiling" in target ? target.capabilityCeiling : undefined, recoveryDescriptor?.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
|
|
1734
|
-
runFanoutBudget: recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
1750
|
+
runFanoutBudget: input.params.runFanoutBudget ?? recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
|
|
1735
1751
|
parentWorkflowRunId: input.params.workflowParentRunId,
|
|
1736
1752
|
workflowKey: input.params.workflowKey,
|
|
1737
1753
|
activeAsyncCapacity,
|
|
@@ -2497,16 +2513,19 @@ function resolveStaticLaunchSummary(input: {
|
|
|
2497
2513
|
thinkingOverrideForTask: ForkThinkingOverrideForTask;
|
|
2498
2514
|
}): StaticLaunchSummary {
|
|
2499
2515
|
const agentConfig = input.agents.find((agent) => agent.name === input.agent);
|
|
2500
|
-
const
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
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);
|
|
2510
2529
|
return {
|
|
2511
2530
|
agent: input.agent,
|
|
2512
2531
|
...(model ? { model } : {}),
|
|
@@ -2789,6 +2808,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2789
2808
|
toolBudget: data.toolBudget,
|
|
2790
2809
|
usageBudget: data.usageBudget,
|
|
2791
2810
|
configToolBudget: data.configToolBudget,
|
|
2811
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
2812
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2792
2813
|
capabilityCeiling: data.capabilityCeiling,
|
|
2793
2814
|
runFanoutBudget: data.runFanoutBudget,
|
|
2794
2815
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -2836,6 +2857,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2836
2857
|
toolBudget: data.toolBudget,
|
|
2837
2858
|
usageBudget: data.usageBudget,
|
|
2838
2859
|
configToolBudget: data.configToolBudget,
|
|
2860
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
2861
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2839
2862
|
capabilityCeiling: data.capabilityCeiling,
|
|
2840
2863
|
runFanoutBudget: data.runFanoutBudget,
|
|
2841
2864
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -2862,14 +2885,15 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2862
2885
|
const externalRunnerWithoutExplicitModel = a.runner?.type === "external-cli"
|
|
2863
2886
|
&& params.model === undefined
|
|
2864
2887
|
&& (a.model === undefined || (a.modelSource?.type === "subagents.defaultModel" && a.model === a.modelSource.model));
|
|
2865
|
-
const modelOverride =
|
|
2866
|
-
? undefined
|
|
2888
|
+
const modelOverride = a.runner?.type === "external-cli"
|
|
2889
|
+
? params.model ?? (externalRunnerWithoutExplicitModel ? undefined : a.model)
|
|
2867
2890
|
: resolveEffectiveSubagentModel(params.model as string | undefined, a.model, parentModel, availableModels, currentProvider, data.modelScope === undefined ? {} : { scope: data.modelScope });
|
|
2868
2891
|
return executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
2869
2892
|
agent: params.agent!,
|
|
2870
2893
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
2871
2894
|
goal: params.task ?? "",
|
|
2872
2895
|
agentConfig: a,
|
|
2896
|
+
recoveryAgentConfig: data.recoveryAgents.find((agent) => agent.name === params.agent),
|
|
2873
2897
|
ctx: asyncCtx,
|
|
2874
2898
|
availableModels,
|
|
2875
2899
|
cwd: effectiveCwd,
|
|
@@ -2894,6 +2918,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2894
2918
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
2895
2919
|
worktreeBaseDir: deps.config.worktreeBaseDir,
|
|
2896
2920
|
controlConfig,
|
|
2921
|
+
intercomBridge: params.intercomBridge,
|
|
2897
2922
|
controlIntercomTarget,
|
|
2898
2923
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(agent, index) : undefined,
|
|
2899
2924
|
nestedRoute,
|
|
@@ -2905,6 +2930,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
2905
2930
|
toolBudget: data.toolBudget,
|
|
2906
2931
|
usageBudget: data.usageBudget,
|
|
2907
2932
|
configToolBudget: data.configToolBudget,
|
|
2933
|
+
toolTimeoutMs: data.params?.toolTimeoutMs,
|
|
2934
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2908
2935
|
capabilityCeiling: data.capabilityCeiling,
|
|
2909
2936
|
runFanoutBudget: data.runFanoutBudget,
|
|
2910
2937
|
parentWorkflowRunId: params.workflowParentRunId,
|
|
@@ -2994,6 +3021,8 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
2994
3021
|
toolBudget: data.toolBudget,
|
|
2995
3022
|
usageBudget: data.usageBudget,
|
|
2996
3023
|
configToolBudget: data.configToolBudget,
|
|
3024
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
3025
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
2997
3026
|
permissions: deps.config.permissions,
|
|
2998
3027
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
2999
3028
|
capabilityCeiling: data.capabilityCeiling,
|
|
@@ -3061,6 +3090,8 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3061
3090
|
toolBudget: data.toolBudget,
|
|
3062
3091
|
usageBudget: data.usageBudget,
|
|
3063
3092
|
configToolBudget: data.configToolBudget,
|
|
3093
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
3094
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
3064
3095
|
capabilityCeiling: data.capabilityCeiling,
|
|
3065
3096
|
runFanoutBudget: data.runFanoutBudget,
|
|
3066
3097
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
@@ -3148,6 +3179,10 @@ interface ForegroundParallelRunInput {
|
|
|
3148
3179
|
worktreeSetup?: WorktreeSetup;
|
|
3149
3180
|
timeoutMs?: number;
|
|
3150
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;
|
|
3151
3186
|
turnBudget?: ResolvedTurnBudget;
|
|
3152
3187
|
usageBudget?: UsageBudgetConfig;
|
|
3153
3188
|
toolBudgets: (ResolvedToolBudget | undefined)[];
|
|
@@ -3239,10 +3274,128 @@ function buildParallelWorktreeTaskCwdError(
|
|
|
3239
3274
|
return formatWorktreeTaskCwdConflict(conflict, sharedCwd);
|
|
3240
3275
|
}
|
|
3241
3276
|
|
|
3242
|
-
function
|
|
3277
|
+
function resolveConfiguredSingleRunOutputBaseDir(deps: ExecutorDeps): string | undefined {
|
|
3243
3278
|
return deps.config.singleRunOutputBaseDir
|
|
3244
3279
|
? path.resolve(deps.expandTilde(deps.config.singleRunOutputBaseDir))
|
|
3245
|
-
:
|
|
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);
|
|
3246
3399
|
}
|
|
3247
3400
|
|
|
3248
3401
|
function buildChainWorktreeTaskCwdError(chain: ChainStep[], sharedCwd: string): string | undefined {
|
|
@@ -3406,6 +3559,8 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
3406
3559
|
share: input.shareEnabled || undefined,
|
|
3407
3560
|
maxOutput: input.maxOutput,
|
|
3408
3561
|
timeoutMs: input.timeoutMs,
|
|
3562
|
+
toolTimeoutMs: input.toolTimeoutMs,
|
|
3563
|
+
configToolTimeoutMs: input.configToolTimeoutMs,
|
|
3409
3564
|
turnBudget: input.turnBudget,
|
|
3410
3565
|
...(model ? { model } : {}),
|
|
3411
3566
|
...(effectiveSkills !== undefined ? { skill: effectiveSkills } : {}),
|
|
@@ -3485,6 +3640,8 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
3485
3640
|
acceptanceContext: { mode: "parallel" },
|
|
3486
3641
|
onEffectivePrompt: input.foregroundControl ? (prompt) => updateLiveEffectivePrompt(input.foregroundControl!, index, prompt) : undefined,
|
|
3487
3642
|
timeoutMs: input.timeoutMs,
|
|
3643
|
+
toolTimeoutMs: input.toolTimeoutMs,
|
|
3644
|
+
configToolTimeoutMs: input.configToolTimeoutMs,
|
|
3488
3645
|
deadlineAt: input.deadlineAt,
|
|
3489
3646
|
turnBudget: input.turnBudget,
|
|
3490
3647
|
toolBudget: input.toolBudgets[index],
|
|
@@ -3612,7 +3769,9 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3612
3769
|
...(task.model !== undefined ? { model: task.model } : {}),
|
|
3613
3770
|
}));
|
|
3614
3771
|
const modelOverrides: (string | undefined)[] = tasks.map((_, i) =>
|
|
3615
|
-
|
|
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 }),
|
|
3616
3775
|
);
|
|
3617
3776
|
|
|
3618
3777
|
if (params.clarify === true && ctx.hasUI) {
|
|
@@ -3647,7 +3806,9 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3647
3806
|
for (let i = 0; i < result.behaviorOverrides.length; i++) {
|
|
3648
3807
|
const override = result.behaviorOverrides[i];
|
|
3649
3808
|
if (override?.model !== undefined) {
|
|
3650
|
-
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 });
|
|
3651
3812
|
behaviorOverrides[i]!.model = override.model;
|
|
3652
3813
|
}
|
|
3653
3814
|
if (override?.output !== undefined) behaviorOverrides[i]!.output = override.output;
|
|
@@ -3734,6 +3895,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3734
3895
|
usageBudget: data.usageBudget,
|
|
3735
3896
|
toolBudget: data.toolBudget,
|
|
3736
3897
|
configToolBudget: data.configToolBudget,
|
|
3898
|
+
callToolTimeoutMs: data.params?.toolTimeoutMs,
|
|
3899
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
3737
3900
|
globalConcurrencyLimit: deps.config.globalConcurrencyLimit,
|
|
3738
3901
|
runFanoutBudget: data.runFanoutBudget,
|
|
3739
3902
|
}));
|
|
@@ -3854,6 +4017,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
3854
4017
|
worktreeSetup,
|
|
3855
4018
|
timeoutMs: data.timeoutMs,
|
|
3856
4019
|
deadlineAt,
|
|
4020
|
+
toolTimeoutMs: data.params?.toolTimeoutMs,
|
|
4021
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
3857
4022
|
turnBudget: data.turnBudget,
|
|
3858
4023
|
usageBudget: data.usageBudget,
|
|
3859
4024
|
toolBudgets,
|
|
@@ -4073,6 +4238,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4073
4238
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(task) : task,
|
|
4074
4239
|
goal: task,
|
|
4075
4240
|
agentConfig,
|
|
4241
|
+
recoveryAgentConfig: data.recoveryAgents.find((agent) => agent.name === params.agent),
|
|
4076
4242
|
ctx: asyncCtx,
|
|
4077
4243
|
availableModels,
|
|
4078
4244
|
cwd: effectiveCwd,
|
|
@@ -4097,6 +4263,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4097
4263
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
4098
4264
|
worktreeBaseDir: deps.config.worktreeBaseDir,
|
|
4099
4265
|
controlConfig,
|
|
4266
|
+
intercomBridge: params.intercomBridge,
|
|
4100
4267
|
controlIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
|
|
4101
4268
|
childIntercomTarget: data.intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(id, agent, index) : undefined,
|
|
4102
4269
|
nestedRoute: data.nestedRoute,
|
|
@@ -4246,6 +4413,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4246
4413
|
},
|
|
4247
4414
|
timeoutMs: data.timeoutMs,
|
|
4248
4415
|
deadlineAt,
|
|
4416
|
+
toolTimeoutMs: params.toolTimeoutMs,
|
|
4417
|
+
configToolTimeoutMs: data.configToolTimeoutMs,
|
|
4249
4418
|
turnBudget: data.turnBudget,
|
|
4250
4419
|
enforceHardTurnLimit: params.enforceHardTurnLimit,
|
|
4251
4420
|
toolBudget: effectiveToolBudget.toolBudget,
|
|
@@ -4324,8 +4493,15 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
4324
4493
|
}
|
|
4325
4494
|
|
|
4326
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}`;
|
|
4327
4503
|
return {
|
|
4328
|
-
content: [{ type: "text", text:
|
|
4504
|
+
content: [{ type: "text", text: message }],
|
|
4329
4505
|
details,
|
|
4330
4506
|
};
|
|
4331
4507
|
}
|
|
@@ -4369,17 +4545,28 @@ function duplicateSubagentCallResult(params: SubagentParamsLike): AgentToolResul
|
|
|
4369
4545
|
|
|
4370
4546
|
const workflowLaunchObservers = new WeakMap<object, (launch: { agent: string; sessionFile?: string; async: boolean; runId?: string }) => void>();
|
|
4371
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
|
+
|
|
4372
4554
|
function recordMissionWorkflowChild(
|
|
4373
4555
|
binding: MissionLaunchBinding | undefined,
|
|
4374
4556
|
workflowRunId: string,
|
|
4375
4557
|
key: string,
|
|
4376
4558
|
update: Omit<MissionWorkflowChildUpdate, "workflowRunId" | "key">,
|
|
4377
4559
|
): void {
|
|
4378
|
-
if (!binding) return;
|
|
4560
|
+
if (!binding || missionsMissingFromStore.has(binding.missionId)) return;
|
|
4379
4561
|
const { task: _task, ...durableUpdate } = update;
|
|
4380
4562
|
try {
|
|
4381
4563
|
updateMission(binding.location, binding.missionId, { upsertWorkflowChildren: [{ workflowRunId, key, ...durableUpdate }] });
|
|
4382
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
|
+
}
|
|
4383
4570
|
console.warn(`[pi-subagents] Failed to record mission workflow child '${key}': ${error instanceof Error ? error.message : String(error)}`);
|
|
4384
4571
|
}
|
|
4385
4572
|
}
|
|
@@ -4449,6 +4636,7 @@ function workflowChildResult(key: string, result: AgentToolResult<Details>): Wor
|
|
|
4449
4636
|
...(result.details.runId || result.details.asyncId ? { runId: result.details.runId ?? result.details.asyncId } : {}),
|
|
4450
4637
|
output,
|
|
4451
4638
|
...(!ok ? { error: receiptOutput || output || "Child run failed." } : {}),
|
|
4639
|
+
...(detached ? { detached: true } : {}),
|
|
4452
4640
|
...(structured.length === 1 ? { structuredOutput: structured[0] } : structured.length > 1 ? { structuredOutput: structured } : {}),
|
|
4453
4641
|
artifactPaths: [...artifactPaths],
|
|
4454
4642
|
results: result.details.results,
|
|
@@ -4469,16 +4657,19 @@ export function prepareWorkflowLaunchParams(
|
|
|
4469
4657
|
const timeoutMs = childParams.timeoutMs ?? childParams.maxRuntimeMs ?? workflowDefaults.timeoutMs ?? workflowDefaults.maxRuntimeMs;
|
|
4470
4658
|
const turnBudget = childParams.turnBudget ?? workflowDefaults.turnBudget;
|
|
4471
4659
|
const toolBudget = childParams.toolBudget ?? workflowDefaults.toolBudget;
|
|
4660
|
+
const intercomBridge = childParams.intercomBridge ?? workflowDefaults.intercomBridge;
|
|
4472
4661
|
return {
|
|
4473
4662
|
action: "resume",
|
|
4474
4663
|
id: childParams.resume.trim(),
|
|
4475
4664
|
message: typeof childParams.task === "string" ? childParams.task.trim() : "",
|
|
4476
4665
|
workflowParentRunId: parentWorkflowRunId,
|
|
4477
4666
|
workflowKey,
|
|
4667
|
+
...(options.runFanoutBudget ? { runFanoutBudget: { ...options.runFanoutBudget, parentPath: `${options.runFanoutBudget.parentPath ? `${options.runFanoutBudget.parentPath}/` : ""}workflow[${workflowKey}]` } } : {}),
|
|
4478
4668
|
...(options.missionDetached ? { mission: false } : {}),
|
|
4479
4669
|
...(timeoutMs !== undefined ? { timeoutMs: timeoutMs as number } : {}),
|
|
4480
4670
|
...(turnBudget !== undefined ? { turnBudget: turnBudget as TurnBudgetConfig } : {}),
|
|
4481
4671
|
...(toolBudget !== undefined ? { toolBudget: toolBudget as ToolBudgetConfig } : {}),
|
|
4672
|
+
...(intercomBridge !== undefined ? { intercomBridge: intercomBridge as IntercomBridgeConfig } : {}),
|
|
4482
4673
|
};
|
|
4483
4674
|
}
|
|
4484
4675
|
const launchParams = {
|
|
@@ -4665,6 +4856,17 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4665
4856
|
const workflowUsageBudget = validateUsageBudgetConfig(requestParams.usageBudget ?? deps.config.usageBudget, requestParams.usageBudget ? "usageBudget" : "config.usageBudget");
|
|
4666
4857
|
if (workflowUsageBudget.error) return buildRequestedModeError(requestParams, workflowUsageBudget.error);
|
|
4667
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
|
+
}
|
|
4668
4870
|
const workflowPrompts = { render: (ref: string, vars?: unknown) => renderWorkflowPrompt(ref, vars, workflowCwd) };
|
|
4669
4871
|
const chatProgressResult = resolveWorkflowChatProgress({ requested: requestParams.chatProgress, parentCwd, workflowCwd, background: requestParams.async !== false });
|
|
4670
4872
|
if (chatProgressResult.error) return { content: [{ type: "text", text: chatProgressResult.error }], isError: true, details: { mode: "workflow", results: [] } };
|
|
@@ -4743,7 +4945,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4743
4945
|
if (workflowRunId) {
|
|
4744
4946
|
const toolCallId = _id;
|
|
4745
4947
|
const asyncDir = path.join(DIRS.async, workflowRunId);
|
|
4746
|
-
const resultPath =
|
|
4948
|
+
const resultPath = resultFilePath(DIRS.results, workflowRunId);
|
|
4747
4949
|
const statusPath = path.join(asyncDir, "status.json");
|
|
4748
4950
|
const eventsPath = path.join(asyncDir, "events.jsonl");
|
|
4749
4951
|
const startedAt = Date.now();
|
|
@@ -4782,7 +4984,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4782
4984
|
status.lastUpdate = Date.now();
|
|
4783
4985
|
writeAtomicJson(statusPath, status);
|
|
4784
4986
|
if (indexedState !== status.state) {
|
|
4785
|
-
updateActiveRunIndex(asyncDir, status.state);
|
|
4987
|
+
updateActiveRunIndex(asyncDir, status.state, status.toolCallId);
|
|
4786
4988
|
indexedState = status.state;
|
|
4787
4989
|
}
|
|
4788
4990
|
const job = deps.state.asyncJobs.get(workflowRunId);
|
|
@@ -4807,6 +5009,17 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4807
5009
|
job.workflow = status.workflow;
|
|
4808
5010
|
}
|
|
4809
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
|
+
};
|
|
4810
5023
|
const projectWorkflowActivity = () => {
|
|
4811
5024
|
const steps = status.steps ?? [];
|
|
4812
5025
|
const runningSteps = steps.filter((step) => step.status === "running");
|
|
@@ -4828,7 +5041,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4828
5041
|
status.toolCount = toolCounts.length > 0 ? toolCounts.reduce((total, count) => total + count, 0) : undefined;
|
|
4829
5042
|
status.currentStep = runningSteps.length === 1 ? steps.indexOf(runningSteps[0]!) : undefined;
|
|
4830
5043
|
};
|
|
4831
|
-
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 };
|
|
4832
5045
|
deps.state.asyncJobs.set(workflowRunId, workflowJob);
|
|
4833
5046
|
deps.state.fleetJobs ??= new Map();
|
|
4834
5047
|
deps.state.fleetJobs.set(workflowRunId, workflowJob);
|
|
@@ -4838,6 +5051,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4838
5051
|
void Promise.resolve().then(async () => {
|
|
4839
5052
|
const workflowResults: SingleResult[] = [];
|
|
4840
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>();
|
|
4841
5058
|
const workflowSteps = new Map<string, NonNullable<AsyncStatus["steps"]>[number]>();
|
|
4842
5059
|
let projectedTraceLength = 0;
|
|
4843
5060
|
let projectedTraceTail: NonNullable<Details["workflow"]>["trace"][number] | undefined;
|
|
@@ -4857,12 +5074,24 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4857
5074
|
if (entry.operation !== "run") continue;
|
|
4858
5075
|
const existing = workflowSteps.get(entry.key);
|
|
4859
5076
|
if (entry.state === "reused" && existing) continue;
|
|
4860
|
-
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";
|
|
4861
5086
|
if (existing) {
|
|
4862
5087
|
existing.status = mapped;
|
|
4863
5088
|
if (entry.agent) existing.agent = entry.agent;
|
|
4864
5089
|
if (entry.runId) existing.runId = entry.runId;
|
|
4865
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;
|
|
4866
5095
|
if (entry.error === undefined) delete existing.error;
|
|
4867
5096
|
else existing.error = entry.error;
|
|
4868
5097
|
if (entry.durationMs === undefined) delete existing.durationMs;
|
|
@@ -4877,6 +5106,8 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4877
5106
|
startedAt: Date.now(),
|
|
4878
5107
|
...(entry.runId ? { runId: entry.runId } : {}),
|
|
4879
5108
|
...(entry.state === "failed" && !entry.runId ? { async: false } : {}),
|
|
5109
|
+
...(entry.state === "detached" ? { activityState: "needs_attention" as const } : {}),
|
|
5110
|
+
...(entry.state === "stopped" ? { stopped: true } : {}),
|
|
4880
5111
|
};
|
|
4881
5112
|
status.steps?.push(step);
|
|
4882
5113
|
workflowSteps.set(entry.key, step);
|
|
@@ -4889,15 +5120,27 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4889
5120
|
appendWorkflowEvent({ type: "subagent.workflow.trace", trace });
|
|
4890
5121
|
};
|
|
4891
5122
|
try {
|
|
4892
|
-
const
|
|
4893
|
-
|
|
5123
|
+
const autoRelaunchCap = resolveMaxWorkflowAutoRelaunches(deps.config.maxWorkflowAutoRelaunches);
|
|
5124
|
+
let relaunched = 0;
|
|
5125
|
+
let capReached = false;
|
|
5126
|
+
let workflow: Awaited<ReturnType<typeof runWorkflowScript>> | undefined;
|
|
5127
|
+
while (true) {
|
|
5128
|
+
if (relaunched > 0) {
|
|
5129
|
+
workflowFanoutBudget = createRunFanoutBudget(`${workflowRunId}#${relaunched + 1}`, workflowFanoutBudget.limit);
|
|
5130
|
+
status = { ...status, workflow: { trace: [], emits: [], console: [] } };
|
|
5131
|
+
}
|
|
5132
|
+
workflow = await runWorkflowScript({
|
|
5133
|
+
script: workflowScript,
|
|
4894
5134
|
timeoutMs: timeout,
|
|
4895
5135
|
signal: controller.signal,
|
|
4896
5136
|
prompts: workflowPrompts,
|
|
4897
5137
|
...(workflowState ? { state: workflowState } : {}),
|
|
4898
5138
|
onTrace: updateTrace,
|
|
4899
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);
|
|
4900
5142
|
status.runFanoutBudget = claimRunFanoutBatch(workflowFanoutBudget, calls.map(({ key }) => `workflow[${key}]`));
|
|
5143
|
+
if (outputClaims.claims) applyWorkflowChildOutputClaims(claimedOutputPaths, outputClaims.claims);
|
|
4901
5144
|
persist();
|
|
4902
5145
|
},
|
|
4903
5146
|
onEmit: (emits) => {
|
|
@@ -4921,7 +5164,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4921
5164
|
});
|
|
4922
5165
|
const result = await runMissionWorkflowChild(missionBinding, workflowRunId, key, childPhase, () => {
|
|
4923
5166
|
const childRequest = bindMissionWorkflowChildAsyncLaunch(
|
|
4924
|
-
{ ...
|
|
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 },
|
|
4925
5168
|
missionBinding,
|
|
4926
5169
|
deps.asyncByDefault,
|
|
4927
5170
|
);
|
|
@@ -4939,7 +5182,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4939
5182
|
return execute(randomUUID(), childRequest, workflowSignal, (update) => {
|
|
4940
5183
|
const progress = update.details.progress?.[0];
|
|
4941
5184
|
const step = status.steps?.find((candidate) => candidate.workflowKey === key);
|
|
4942
|
-
if (!progress || !step) return;
|
|
5185
|
+
if (!progress || !step || step.stopped) return;
|
|
4943
5186
|
step.status = progress.status === "completed" ? "completed" : progress.status === "failed" ? "failed" : "running";
|
|
4944
5187
|
step.activityState = progress.activityState;
|
|
4945
5188
|
step.lastActivityAt = progress.lastActivityAt;
|
|
@@ -4988,21 +5231,57 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
4988
5231
|
},
|
|
4989
5232
|
status: async (keyOrRunId, workflowSignal) => workflowChildResult(keyOrRunId, await execute(randomUUID(), { action: "status", id: keyOrRunId }, workflowSignal, undefined, ctx, preserveActiveSession)),
|
|
4990
5233
|
});
|
|
5234
|
+
const decision = resolveAutoRelaunchDecision(workflow?.value, relaunched, autoRelaunchCap);
|
|
5235
|
+
if (!decision.relaunch) {
|
|
5236
|
+
capReached = decision.capped;
|
|
5237
|
+
break;
|
|
5238
|
+
}
|
|
5239
|
+
relaunched += 1;
|
|
5240
|
+
status = { ...status, workflowRelaunchCount: relaunched };
|
|
5241
|
+
persist();
|
|
5242
|
+
appendWorkflowEvent({ type: "subagent.workflow.relaunched", relaunched });
|
|
5243
|
+
}
|
|
5244
|
+
if (!workflow) throw new Error("Workflow script produced no result.");
|
|
4991
5245
|
const returnPreview = formatWorkflowValue(workflow.value).slice(0, 1_000);
|
|
4992
5246
|
const emitPreview = workflow.emits.length > 0 ? ` Emitted: ${workflow.emits.map(formatWorkflowValue).join(", ").slice(0, 1_000)}` : "";
|
|
4993
|
-
const
|
|
5247
|
+
const relaunchNote = relaunched > 0 ? `Auto-relaunched ${relaunched} time(s) with a fresh fan-out budget. ` : "";
|
|
5248
|
+
const summary = `${relaunchNote}Workflow completed with ${workflow.children.length} child run(s). Return: ${returnPreview}${emitPreview} Trace: ${workflow.trace.length} event(s).`;
|
|
4994
5249
|
const workflowUsage = sumResultsUsage(workflowResults);
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
5250
|
+
if (capReached) {
|
|
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;
|
|
5256
|
+
persist();
|
|
5257
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: "failed", error: status.error });
|
|
5258
|
+
} else {
|
|
5259
|
+
const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, summary);
|
|
5260
|
+
const resultSummary = appendWorkflowOutputWarning(summary, outputWarning);
|
|
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) };
|
|
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;
|
|
5263
|
+
persist();
|
|
5264
|
+
appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}) });
|
|
5265
|
+
}
|
|
4999
5266
|
} catch (error) {
|
|
5000
5267
|
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
5001
5268
|
const stopped = controller.signal.aborted;
|
|
5002
|
-
|
|
5003
|
-
|
|
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;
|
|
5004
5283
|
persist();
|
|
5005
|
-
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 } : {}) });
|
|
5006
5285
|
} finally {
|
|
5007
5286
|
deps.state.workflowControllers?.delete(workflowRunId);
|
|
5008
5287
|
deps.state.activeAsyncCapacity = workflowCapacity?.reconcile(new Set(deps.state.workflowControllers?.keys() ?? []))
|
|
@@ -5015,6 +5294,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5015
5294
|
}, workflowFanoutBudget));
|
|
5016
5295
|
}
|
|
5017
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>();
|
|
5018
5301
|
const workflowResults: SingleResult[] = [];
|
|
5019
5302
|
let liveWorkflow: NonNullable<Details["workflow"]> = { trace: [], emits: [], console: [] };
|
|
5020
5303
|
const sendWorkflowProgress = () => {
|
|
@@ -5033,7 +5316,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5033
5316
|
sendWorkflowProgress();
|
|
5034
5317
|
},
|
|
5035
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);
|
|
5036
5321
|
claimRunFanoutBatch(workflowFanoutBudget, calls.map(({ key }) => `workflow[${key}]`));
|
|
5322
|
+
if (outputClaims.claims) applyWorkflowChildOutputClaims(claimedOutputPaths, outputClaims.claims);
|
|
5037
5323
|
},
|
|
5038
5324
|
onEmit: (emits) => {
|
|
5039
5325
|
liveWorkflow = { ...liveWorkflow, emits };
|
|
@@ -5054,7 +5340,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5054
5340
|
});
|
|
5055
5341
|
const result = await runMissionWorkflowChild(missionBinding, _id, key, childPhase, () => {
|
|
5056
5342
|
const childRequest = bindMissionWorkflowChildAsyncLaunch(
|
|
5057
|
-
{ ...
|
|
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 },
|
|
5058
5344
|
missionBinding,
|
|
5059
5345
|
deps.asyncByDefault,
|
|
5060
5346
|
);
|
|
@@ -5095,8 +5381,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5095
5381
|
if (workflow.emits.length > 0) sections.push(`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5096
5382
|
if (workflow.console.length > 0) sections.push(`Console:\n${workflow.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5097
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);
|
|
5098
5387
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5099
|
-
content: [{ type: "text", text:
|
|
5388
|
+
content: [{ type: "text", text: displayText }],
|
|
5100
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 }),
|
|
5101
5390
|
}, workflowFanoutBudget));
|
|
5102
5391
|
} catch (error) {
|
|
@@ -5107,8 +5396,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5107
5396
|
if (partial.emits.length > 0) sections.push(`Emitted:\n${partial.emits.map(formatWorkflowValue).join("\n")}`);
|
|
5108
5397
|
if (partial.console.length > 0) sections.push(`Console:\n${partial.console.map((entry) => `[${entry.level}] ${entry.text}`).join("\n")}`);
|
|
5109
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);
|
|
5110
5402
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5111
|
-
content: [{ type: "text", text:
|
|
5403
|
+
content: [{ type: "text", text: displayText }],
|
|
5112
5404
|
isError: true,
|
|
5113
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 }),
|
|
5114
5406
|
}, workflowFanoutBudget));
|
|
@@ -5326,7 +5618,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5326
5618
|
}
|
|
5327
5619
|
if (action === "children.list") {
|
|
5328
5620
|
deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
5329
|
-
const children = listRetainedChildren(DIRS.async, deps.state.currentSessionId);
|
|
5621
|
+
const children = listRetainedChildren(DIRS.async, deps.state.sessionLineage?.length ? deps.state.sessionLineage : [deps.state.currentSessionId]);
|
|
5330
5622
|
return {
|
|
5331
5623
|
content: [{ type: "text", text: formatRetainedChildren(children) }],
|
|
5332
5624
|
details: { mode: "management", results: [] },
|
|
@@ -5372,11 +5664,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5372
5664
|
details: { mode: "management", results: [], spawnBudget, activeAsyncCapacity },
|
|
5373
5665
|
};
|
|
5374
5666
|
}
|
|
5375
|
-
if (action === "status") {
|
|
5667
|
+
if (action === "status" || action === "debug.run") {
|
|
5376
5668
|
if (!preserveActiveSession) deps.state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
5377
5669
|
const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
|
|
5378
5670
|
const hasDirectoryTarget = Boolean(paramsWithResolvedCwd.dir);
|
|
5379
|
-
const targetLabel = formatStatusTargetLabel(paramsWithResolvedCwd, targetRunId);
|
|
5671
|
+
const targetLabel = action === "debug.run" ? "Debug run" : formatStatusTargetLabel(paramsWithResolvedCwd, targetRunId);
|
|
5380
5672
|
const withBudget = (result: AgentToolResult<Details>) => {
|
|
5381
5673
|
const budgeted = withSpawnBudgetStatus(result, deps.state, deps.config, deps.state.currentSessionId);
|
|
5382
5674
|
return {
|
|
@@ -5388,6 +5680,15 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5388
5680
|
};
|
|
5389
5681
|
const nestedScope = nestedResolutionScopeForExecutor(deps);
|
|
5390
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
|
+
}
|
|
5391
5692
|
if (paramsWithResolvedCwd.view === "fleet") {
|
|
5392
5693
|
return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots })));
|
|
5393
5694
|
}
|
|
@@ -5777,6 +6078,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5777
6078
|
const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
|
|
5778
6079
|
const intercomBridge = resolveIntercomBridge({
|
|
5779
6080
|
config: deps.config.intercomBridge,
|
|
6081
|
+
override: effectiveParams.intercomBridge,
|
|
5780
6082
|
context: effectiveParams.context ?? (contextPolicy.usesFork ? "fork" : undefined),
|
|
5781
6083
|
orchestratorTarget: sessionName,
|
|
5782
6084
|
});
|
|
@@ -5825,6 +6127,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5825
6127
|
const parentModel = requestParentModel;
|
|
5826
6128
|
prepareForkThinking = (agentName, index, modelOverride) => {
|
|
5827
6129
|
const agentConfig = agents.find((agent) => agent.name === agentName);
|
|
6130
|
+
if (agentConfig?.runner?.type === "external-cli") {
|
|
6131
|
+
forkThinkingRequirements.set(index, true);
|
|
6132
|
+
return;
|
|
6133
|
+
}
|
|
5828
6134
|
const primaryModel = resolveEffectiveSubagentModel(
|
|
5829
6135
|
modelOverride,
|
|
5830
6136
|
agentConfig?.model,
|
|
@@ -6039,6 +6345,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6039
6345
|
signal,
|
|
6040
6346
|
onUpdate: onUpdateWithContext,
|
|
6041
6347
|
agents,
|
|
6348
|
+
recoveryAgents: discoveredAgents,
|
|
6042
6349
|
runId,
|
|
6043
6350
|
shareEnabled,
|
|
6044
6351
|
sessionRoot,
|
|
@@ -6060,6 +6367,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6060
6367
|
usageBudget: usageBudget.budget,
|
|
6061
6368
|
allowZeroToolBudget,
|
|
6062
6369
|
configToolBudget: configToolBudget.toolBudget,
|
|
6370
|
+
configToolTimeoutMs: deps.config.toolTimeoutMs,
|
|
6063
6371
|
contextPolicy,
|
|
6064
6372
|
modelScope,
|
|
6065
6373
|
parentModel: requestParentModel,
|
|
@@ -6229,7 +6537,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6229
6537
|
};
|
|
6230
6538
|
|
|
6231
6539
|
let nestedForegroundStarted = false;
|
|
6540
|
+
let asyncLaunchFailed = false;
|
|
6232
6541
|
try {
|
|
6542
|
+
if (effectiveAsync) {
|
|
6543
|
+
deps.state.liveAsyncSessionRoots ??= new Map();
|
|
6544
|
+
deps.state.liveAsyncSessionRoots.set(asyncRunId, sessionRoot);
|
|
6545
|
+
}
|
|
6233
6546
|
if (workflowLaunchObserver) {
|
|
6234
6547
|
const singleTask = hasTasks && effectiveParams.tasks?.length === 1 ? effectiveParams.tasks[0] : undefined;
|
|
6235
6548
|
const launch = hasSingle
|
|
@@ -6243,7 +6556,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6243
6556
|
}
|
|
6244
6557
|
}
|
|
6245
6558
|
const asyncResult = runAsyncPath(execData, deps);
|
|
6246
|
-
if (asyncResult)
|
|
6559
|
+
if (asyncResult) {
|
|
6560
|
+
asyncLaunchFailed = asyncResult.isError === true;
|
|
6561
|
+
return attachMission(withRunFanoutBudget(withResolvedContext(withForkThinkingNotes(asyncResult, forkThinkingDowngrades), contextPolicy.contextSummary), runFanoutBudget));
|
|
6562
|
+
}
|
|
6247
6563
|
if (foregroundControl) {
|
|
6248
6564
|
writeNestedForegroundEvent("subagent.nested.started");
|
|
6249
6565
|
nestedForegroundStarted = true;
|
|
@@ -6265,10 +6581,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6265
6581
|
return attachMission(withRunFanoutBudget(withResolvedContext(withForkThinkingNotes(result, forkThinkingDowngrades), contextPolicy.contextSummary), runFanoutBudget, { annotateContent: runFanoutAnnotateContent }));
|
|
6266
6582
|
}
|
|
6267
6583
|
} catch (error) {
|
|
6584
|
+
asyncLaunchFailed = effectiveAsync;
|
|
6268
6585
|
const errorResult = withForkThinkingNotes(toExecutionErrorResult(effectiveParams, error, contextPolicy.contextSummary), forkThinkingDowngrades);
|
|
6269
6586
|
if (nestedForegroundStarted) writeNestedForegroundEvent("subagent.nested.completed", errorResult);
|
|
6270
6587
|
return attachMission(errorResult);
|
|
6271
6588
|
} finally {
|
|
6589
|
+
if (effectiveAsync && (asyncLaunchFailed || (activeAsyncCapacity && !activeAsyncCapacity.owner.runnerStartedAt))) deps.state.liveAsyncSessionRoots?.delete(asyncRunId);
|
|
6272
6590
|
if (activeAsyncCapacity && !activeAsyncCapacity.owner.runnerStartedAt) activeAsyncCapacity.rollback();
|
|
6273
6591
|
if (foregroundControl) {
|
|
6274
6592
|
settleForegroundSchedulingOwner(foregroundControl);
|