@bastani/atomic 0.8.19-0 → 0.8.20-0
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 +19 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +5 -0
- package/dist/builtin/mcp/package.json +2 -2
- package/dist/builtin/subagents/CHANGELOG.md +12 -2
- package/dist/builtin/subagents/agents/code-simplifier.md +1 -1
- package/dist/builtin/subagents/agents/codebase-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +1 -1
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/debugger.md +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +12 -12
- package/dist/builtin/subagents/src/agents/agent-management.ts +16 -11
- package/dist/builtin/subagents/src/agents/skills.ts +13 -1
- package/dist/builtin/subagents/src/extension/index.ts +14 -3
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +8 -0
- package/dist/builtin/subagents/src/runs/background/run-status.ts +2 -3
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +11 -1
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +31 -23
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +13 -7
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +160 -93
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +1 -0
- package/dist/builtin/subagents/src/runs/shared/run-history.ts +1 -1
- package/dist/builtin/subagents/src/shared/settings.ts +1 -0
- package/dist/builtin/subagents/src/shared/types.ts +78 -4
- package/dist/builtin/subagents/src/tui/render.ts +203 -19
- package/dist/builtin/web-access/CHANGELOG.md +5 -0
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +19 -0
- package/dist/builtin/workflows/README.md +22 -3
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +1 -1
- package/dist/builtin/workflows/builtin/open-claude-design.ts +12 -4
- package/dist/builtin/workflows/builtin/ralph.ts +2 -2
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/config-loader.ts +68 -0
- package/dist/builtin/workflows/src/extension/index.ts +246 -55
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +372 -0
- package/dist/builtin/workflows/src/extension/render-call.ts +1 -1
- package/dist/builtin/workflows/src/extension/wiring.ts +32 -3
- package/dist/builtin/workflows/src/runs/background/status.ts +14 -74
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +5 -3
- package/dist/builtin/workflows/src/tui/chat-surface-message.ts +3 -13
- package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +2 -10
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +5 -5
- package/dist/builtin/workflows/src/tui/session-confirm.ts +6 -7
- package/dist/builtin/workflows/src/tui/session-picker.ts +18 -14
- package/dist/builtin/workflows/src/tui/status-list.ts +2 -2
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +125 -30
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +4 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +3 -2
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +13 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +63 -17
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js +29 -0
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +46 -13
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/pi-user-agent.d.ts.map +1 -1
- package/dist/utils/pi-user-agent.js +2 -1
- package/dist/utils/pi-user-agent.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +1 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +3 -5
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/models.md +52 -52
- package/docs/quickstart.md +2 -2
- package/docs/workflows.md +22 -5
- package/package.json +9 -9
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
5
4
|
import { APP_NAME, getEnvValue, type ExtensionAPI, type ExtensionContext } from "@bastani/atomic";
|
|
6
5
|
import { type AgentConfig, type AgentScope } from "../../agents/agents.ts";
|
|
7
6
|
import { getArtifactsDir } from "../../shared/artifacts.ts";
|
|
@@ -78,15 +77,19 @@ import {
|
|
|
78
77
|
type SingleResult,
|
|
79
78
|
type SubagentRunMode,
|
|
80
79
|
type SubagentState,
|
|
80
|
+
type SubagentToolResult,
|
|
81
81
|
DEFAULT_ARTIFACT_CONFIG,
|
|
82
82
|
SUBAGENT_ACTIONS,
|
|
83
83
|
SUBAGENT_CONTROL_EVENT,
|
|
84
84
|
SUBAGENT_CONTROL_INTERCOM_EVENT,
|
|
85
85
|
checkSubagentDepth,
|
|
86
|
+
isWorkflowStageOrchestrationContext,
|
|
86
87
|
resolveTopLevelParallelConcurrency,
|
|
87
88
|
resolveTopLevelParallelMaxTasks,
|
|
88
89
|
resolveChildMaxSubagentDepth,
|
|
89
|
-
|
|
90
|
+
resolveSubagentDepthPolicy,
|
|
91
|
+
resolveWorkflowStageMaxSubagentDepth,
|
|
92
|
+
subagentDepthBlockedMessage,
|
|
90
93
|
wrapForkTask,
|
|
91
94
|
} from "../../shared/types.ts";
|
|
92
95
|
|
|
@@ -107,7 +110,7 @@ interface TaskParam {
|
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
export interface SubagentParamsLike {
|
|
110
|
-
action?:
|
|
113
|
+
action?: (typeof SUBAGENT_ACTIONS)[number];
|
|
111
114
|
id?: string;
|
|
112
115
|
runId?: string;
|
|
113
116
|
dir?: string;
|
|
@@ -115,6 +118,8 @@ export interface SubagentParamsLike {
|
|
|
115
118
|
agent?: string;
|
|
116
119
|
task?: string;
|
|
117
120
|
message?: string;
|
|
121
|
+
chainName?: string;
|
|
122
|
+
config?: unknown;
|
|
118
123
|
chain?: ChainStep[];
|
|
119
124
|
tasks?: TaskParam[];
|
|
120
125
|
concurrency?: number;
|
|
@@ -133,10 +138,32 @@ export interface SubagentParamsLike {
|
|
|
133
138
|
skill?: string | string[] | boolean;
|
|
134
139
|
output?: string | boolean;
|
|
135
140
|
outputMode?: "inline" | "file-only";
|
|
136
|
-
agentScope?:
|
|
141
|
+
agentScope?: string;
|
|
137
142
|
chainDir?: string;
|
|
138
143
|
}
|
|
139
144
|
|
|
145
|
+
export interface SubagentExecutorRuntimeDeps {
|
|
146
|
+
runSync: typeof runSync;
|
|
147
|
+
executeAsyncChain: typeof executeAsyncChain;
|
|
148
|
+
executeAsyncSingle: typeof executeAsyncSingle;
|
|
149
|
+
isAsyncAvailable: typeof isAsyncAvailable;
|
|
150
|
+
formatAsyncStartedMessage: typeof formatAsyncStartedMessage;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const defaultSubagentExecutorRuntimeDeps: SubagentExecutorRuntimeDeps = {
|
|
154
|
+
runSync,
|
|
155
|
+
executeAsyncChain,
|
|
156
|
+
executeAsyncSingle,
|
|
157
|
+
isAsyncAvailable,
|
|
158
|
+
formatAsyncStartedMessage,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
function resolveSubagentExecutorRuntimeDeps(
|
|
162
|
+
overrides?: Partial<SubagentExecutorRuntimeDeps>,
|
|
163
|
+
): SubagentExecutorRuntimeDeps {
|
|
164
|
+
return { ...defaultSubagentExecutorRuntimeDeps, ...overrides };
|
|
165
|
+
}
|
|
166
|
+
|
|
140
167
|
interface ExecutorDeps {
|
|
141
168
|
pi: ExtensionAPI;
|
|
142
169
|
state: SubagentState;
|
|
@@ -147,6 +174,11 @@ interface ExecutorDeps {
|
|
|
147
174
|
expandTilde: (p: string) => string;
|
|
148
175
|
discoverAgents: (cwd: string, scope: AgentScope) => { agents: AgentConfig[] };
|
|
149
176
|
allowMutatingManagementActions?: boolean;
|
|
177
|
+
runtime?: Partial<SubagentExecutorRuntimeDeps>;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
interface ResolvedExecutorDeps extends Omit<ExecutorDeps, "runtime"> {
|
|
181
|
+
runtime: SubagentExecutorRuntimeDeps;
|
|
150
182
|
}
|
|
151
183
|
|
|
152
184
|
interface ExecutionContextData {
|
|
@@ -154,7 +186,7 @@ interface ExecutionContextData {
|
|
|
154
186
|
effectiveCwd: string;
|
|
155
187
|
ctx: ExtensionContext;
|
|
156
188
|
signal: AbortSignal;
|
|
157
|
-
onUpdate?: (r:
|
|
189
|
+
onUpdate?: (r: SubagentToolResult) => void;
|
|
158
190
|
agents: AgentConfig[];
|
|
159
191
|
runId: string;
|
|
160
192
|
shareEnabled: boolean;
|
|
@@ -206,7 +238,7 @@ function formatForegroundActivity(control: SubagentState["foregroundControls"] e
|
|
|
206
238
|
return [`active ${seconds}s ago`, ...facts].join(" | ");
|
|
207
239
|
}
|
|
208
240
|
|
|
209
|
-
function nestedResolutionScopeForExecutor(deps:
|
|
241
|
+
function nestedResolutionScopeForExecutor(deps: ResolvedExecutorDeps): NestedRunResolutionScope | undefined {
|
|
210
242
|
if (deps.allowMutatingManagementActions !== false) return undefined;
|
|
211
243
|
const route = resolveInheritedNestedRouteFromEnv();
|
|
212
244
|
const address = route ? resolveNestedParentAddressFromEnv() : undefined;
|
|
@@ -216,7 +248,7 @@ function nestedResolutionScopeForExecutor(deps: ExecutorDeps): NestedRunResoluti
|
|
|
216
248
|
};
|
|
217
249
|
}
|
|
218
250
|
|
|
219
|
-
function foregroundStatusResult(control: SubagentState["foregroundControls"] extends Map<string, infer T> ? T : never):
|
|
251
|
+
function foregroundStatusResult(control: SubagentState["foregroundControls"] extends Map<string, infer T> ? T : never): SubagentToolResult {
|
|
220
252
|
let nestedWarning: string | undefined;
|
|
221
253
|
try {
|
|
222
254
|
updateForegroundNestedProjection(control);
|
|
@@ -399,7 +431,7 @@ function emitControlNotification(input: {
|
|
|
399
431
|
}
|
|
400
432
|
}
|
|
401
433
|
|
|
402
|
-
function interruptAsyncRun(state: SubagentState, runId: string | undefined):
|
|
434
|
+
function interruptAsyncRun(state: SubagentState, runId: string | undefined): SubagentToolResult | null {
|
|
403
435
|
const target = getAsyncInterruptTarget(state, runId);
|
|
404
436
|
if (!target) return null;
|
|
405
437
|
const status = readStatus(target.asyncDir);
|
|
@@ -509,7 +541,7 @@ async function sendNestedControlRequest(target: ResolvedSubagentRunId & { kind:
|
|
|
509
541
|
return waitForNestedControlResult(target, requestId);
|
|
510
542
|
}
|
|
511
543
|
|
|
512
|
-
function directNestedAsyncInterrupt(target: ResolvedSubagentRunId & { kind: "nested" }):
|
|
544
|
+
function directNestedAsyncInterrupt(target: ResolvedSubagentRunId & { kind: "nested" }): SubagentToolResult | undefined {
|
|
513
545
|
const run = target.match.run;
|
|
514
546
|
const asyncDir = resolveNestedAsyncDir(target.match.rootRunId, run);
|
|
515
547
|
if (!asyncDir) return undefined;
|
|
@@ -525,7 +557,7 @@ function directNestedAsyncInterrupt(target: ResolvedSubagentRunId & { kind: "nes
|
|
|
525
557
|
}
|
|
526
558
|
}
|
|
527
559
|
|
|
528
|
-
async function interruptNestedRun(target: ResolvedSubagentRunId & { kind: "nested" }): Promise<
|
|
560
|
+
async function interruptNestedRun(target: ResolvedSubagentRunId & { kind: "nested" }): Promise<SubagentToolResult> {
|
|
529
561
|
const run = target.match.run;
|
|
530
562
|
if (run.state === "complete") return { content: [{ type: "text", text: `Nested run ${run.id} is already complete and cannot be interrupted.` }], isError: true, details: { mode: "management", results: [] } };
|
|
531
563
|
if (run.state === "failed") return { content: [{ type: "text", text: `Nested run ${run.id} has failed and cannot be interrupted.` }], isError: true, details: { mode: "management", results: [] } };
|
|
@@ -537,7 +569,7 @@ async function interruptNestedRun(target: ResolvedSubagentRunId & { kind: "neste
|
|
|
537
569
|
return { content: [{ type: "text", text: `Nested run ${run.id} owner is not reachable and no safe direct async interrupt fallback is available.` }], isError: true, details: { mode: "management", results: [] } };
|
|
538
570
|
}
|
|
539
571
|
|
|
540
|
-
async function resumeLiveNestedRun(input: { target: ResolvedSubagentRunId & { kind: "nested" }; message: string }): Promise<
|
|
572
|
+
async function resumeLiveNestedRun(input: { target: ResolvedSubagentRunId & { kind: "nested" }; message: string }): Promise<SubagentToolResult> {
|
|
541
573
|
const run = input.target.match.run;
|
|
542
574
|
const result = await sendNestedControlRequest(input.target, "resume", input.message);
|
|
543
575
|
if (result) return { content: [{ type: "text", text: result.message }], isError: result.ok ? undefined : true, details: { mode: "management", results: [] } };
|
|
@@ -548,8 +580,8 @@ async function resumeAsyncRun(input: {
|
|
|
548
580
|
params: SubagentParamsLike;
|
|
549
581
|
requestCwd: string;
|
|
550
582
|
ctx: ExtensionContext;
|
|
551
|
-
deps:
|
|
552
|
-
}): Promise<
|
|
583
|
+
deps: ResolvedExecutorDeps;
|
|
584
|
+
}): Promise<SubagentToolResult> {
|
|
553
585
|
const followUp = (input.params.message ?? input.params.task ?? "").trim();
|
|
554
586
|
if (!followUp) {
|
|
555
587
|
return {
|
|
@@ -602,10 +634,17 @@ async function resumeAsyncRun(input: {
|
|
|
602
634
|
};
|
|
603
635
|
}
|
|
604
636
|
|
|
605
|
-
const
|
|
637
|
+
const resumeDepthPolicy = resolveSubagentDepthPolicy(input.ctx, input.deps.config.maxSubagentDepth);
|
|
638
|
+
const { blocked, depth, maxDepth, workflowStageGuard } = checkSubagentDepth(resumeDepthPolicy.maxSubagentDepth);
|
|
606
639
|
if (blocked) {
|
|
607
640
|
return {
|
|
608
|
-
content: [{
|
|
641
|
+
content: [{
|
|
642
|
+
type: "text",
|
|
643
|
+
text: subagentDepthBlockedMessage(depth, maxDepth, {
|
|
644
|
+
action: "resume",
|
|
645
|
+
workflowStageGuard: workflowStageGuard || resumeDepthPolicy.workflowStageSubagentGuard,
|
|
646
|
+
}),
|
|
647
|
+
}],
|
|
609
648
|
isError: true,
|
|
610
649
|
details: { mode: "management", results: [] },
|
|
611
650
|
};
|
|
@@ -637,7 +676,7 @@ async function resumeAsyncRun(input: {
|
|
|
637
676
|
const runId = randomUUID().slice(0, 8);
|
|
638
677
|
const artifactConfig: ArtifactConfig = { ...DEFAULT_ARTIFACT_CONFIG, enabled: input.params.artifacts !== false };
|
|
639
678
|
const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
640
|
-
const result = executeAsyncSingle(runId, {
|
|
679
|
+
const result = input.deps.runtime.executeAsyncSingle(runId, {
|
|
641
680
|
agent: target.agent,
|
|
642
681
|
task: buildRevivedAsyncTask(target, followUp),
|
|
643
682
|
agentConfig,
|
|
@@ -655,7 +694,8 @@ async function resumeAsyncRun(input: {
|
|
|
655
694
|
shareEnabled: input.params.share === true,
|
|
656
695
|
sessionRoot: input.deps.getSubagentSessionRoot(parentSessionFile),
|
|
657
696
|
sessionFile: target.sessionFile,
|
|
658
|
-
maxSubagentDepth:
|
|
697
|
+
maxSubagentDepth: resolveWorkflowStageMaxSubagentDepth(input.ctx, input.deps.config.maxSubagentDepth),
|
|
698
|
+
workflowStageSubagentGuard: isWorkflowStageOrchestrationContext(input.ctx),
|
|
659
699
|
worktreeSetupHook: input.deps.config.worktreeSetupHook,
|
|
660
700
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
661
701
|
controlConfig: resolveControlConfig(input.deps.config.control, input.params.control),
|
|
@@ -677,7 +717,7 @@ async function resumeAsyncRun(input: {
|
|
|
677
717
|
revivedTarget ? `Intercom target: ${revivedTarget} (if registered)` : undefined,
|
|
678
718
|
`Status if needed: subagent({ action: "status", id: "${revivedId}" })`,
|
|
679
719
|
].filter((line): line is string => Boolean(line));
|
|
680
|
-
return { content: [{ type: "text", text: formatAsyncStartedMessage(lines.join("\n")) }], details: result.details };
|
|
720
|
+
return { content: [{ type: "text", text: input.deps.runtime.formatAsyncStartedMessage(lines.join("\n")) }], details: result.details };
|
|
681
721
|
}
|
|
682
722
|
|
|
683
723
|
function resultSummaryForIntercom(result: SingleResult): string {
|
|
@@ -765,7 +805,7 @@ function validateExecutionInput(
|
|
|
765
805
|
hasTasks: boolean,
|
|
766
806
|
hasSingle: boolean,
|
|
767
807
|
allowClarifyTaskPrompt: boolean,
|
|
768
|
-
):
|
|
808
|
+
): SubagentToolResult | null {
|
|
769
809
|
if (Number(hasChain) + Number(hasTasks) + Number(hasSingle) !== 1) {
|
|
770
810
|
return {
|
|
771
811
|
content: [
|
|
@@ -869,7 +909,7 @@ function applyAgentDefaultContext(params: SubagentParamsLike, agents: AgentConfi
|
|
|
869
909
|
: params;
|
|
870
910
|
}
|
|
871
911
|
|
|
872
|
-
function buildRequestedModeError(params: SubagentParamsLike, message: string):
|
|
912
|
+
function buildRequestedModeError(params: SubagentParamsLike, message: string): SubagentToolResult {
|
|
873
913
|
return withForkContext(
|
|
874
914
|
{
|
|
875
915
|
content: [{ type: "text", text: message }],
|
|
@@ -921,7 +961,7 @@ function expandChainParallelCounts(chain: ChainStep[]): { chain?: ChainStep[]; e
|
|
|
921
961
|
return { chain: expandedChain };
|
|
922
962
|
}
|
|
923
963
|
|
|
924
|
-
function normalizeRepeatedParallelCounts(params: SubagentParamsLike): { params?: SubagentParamsLike; error?:
|
|
964
|
+
function normalizeRepeatedParallelCounts(params: SubagentParamsLike): { params?: SubagentParamsLike; error?: SubagentToolResult } {
|
|
925
965
|
if (params.tasks) {
|
|
926
966
|
const expandedTasks = expandTopLevelTaskCounts(params.tasks);
|
|
927
967
|
if (expandedTasks.error) {
|
|
@@ -940,9 +980,9 @@ function normalizeRepeatedParallelCounts(params: SubagentParamsLike): { params?:
|
|
|
940
980
|
}
|
|
941
981
|
|
|
942
982
|
function withForkContext(
|
|
943
|
-
result:
|
|
983
|
+
result: SubagentToolResult,
|
|
944
984
|
context: SubagentParamsLike["context"],
|
|
945
|
-
):
|
|
985
|
+
): SubagentToolResult {
|
|
946
986
|
if (context !== "fork" || !result.details) return result;
|
|
947
987
|
return {
|
|
948
988
|
...result,
|
|
@@ -953,7 +993,7 @@ function withForkContext(
|
|
|
953
993
|
};
|
|
954
994
|
}
|
|
955
995
|
|
|
956
|
-
function toExecutionErrorResult(params: SubagentParamsLike, error: unknown):
|
|
996
|
+
function toExecutionErrorResult(params: SubagentParamsLike, error: unknown): SubagentToolResult {
|
|
957
997
|
const message = error instanceof Error ? error.message : String(error);
|
|
958
998
|
return withForkContext(
|
|
959
999
|
{
|
|
@@ -1005,7 +1045,7 @@ function wrapChainTasksForFork(chain: ChainStep[], context: SubagentParamsLike["
|
|
|
1005
1045
|
});
|
|
1006
1046
|
}
|
|
1007
1047
|
|
|
1008
|
-
function runAsyncPath(data: ExecutionContextData, deps:
|
|
1048
|
+
function runAsyncPath(data: ExecutionContextData, deps: ResolvedExecutorDeps): SubagentToolResult | null {
|
|
1009
1049
|
const {
|
|
1010
1050
|
params,
|
|
1011
1051
|
effectiveCwd,
|
|
@@ -1048,7 +1088,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1048
1088
|
}
|
|
1049
1089
|
}
|
|
1050
1090
|
|
|
1051
|
-
if (!isAsyncAvailable()) {
|
|
1091
|
+
if (!deps.runtime.isAsyncAvailable()) {
|
|
1052
1092
|
return {
|
|
1053
1093
|
content: [{ type: "text", text: `Async mode requires upstream jiti for TypeScript execution but it could not be found. Ensure the ${APP_NAME}-subagents package dependencies are installed.` }],
|
|
1054
1094
|
isError: true,
|
|
@@ -1064,7 +1104,9 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1064
1104
|
currentModel: currentModelFullId(ctx.model),
|
|
1065
1105
|
};
|
|
1066
1106
|
const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
1067
|
-
const
|
|
1107
|
+
const depthPolicy = resolveSubagentDepthPolicy(ctx, deps.config.maxSubagentDepth);
|
|
1108
|
+
const currentMaxSubagentDepth = depthPolicy.maxSubagentDepth;
|
|
1109
|
+
const workflowStageSubagentGuard = depthPolicy.workflowStageSubagentGuard;
|
|
1068
1110
|
const currentProvider = ctx.model?.provider;
|
|
1069
1111
|
const controlIntercomTarget = intercomBridge.active ? intercomBridge.orchestratorTarget : undefined;
|
|
1070
1112
|
const childIntercomTarget = intercomBridge.active ? (agent: string, index: number) => resolveSubagentIntercomTarget(id, agent, index) : undefined;
|
|
@@ -1086,7 +1128,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1086
1128
|
...(task.reads !== undefined && task.reads !== true ? { reads: task.reads } : {}),
|
|
1087
1129
|
...(task.progress !== undefined ? { progress: task.progress } : {}),
|
|
1088
1130
|
}));
|
|
1089
|
-
return executeAsyncChain(id, {
|
|
1131
|
+
return deps.runtime.executeAsyncChain(id, {
|
|
1090
1132
|
chain: [{
|
|
1091
1133
|
parallel: parallelTasks,
|
|
1092
1134
|
concurrency: resolveTopLevelParallelConcurrency(params.concurrency, deps.config.parallel?.concurrency),
|
|
@@ -1105,6 +1147,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1105
1147
|
chainSkills: [],
|
|
1106
1148
|
sessionFilesByFlatIndex: params.tasks.map((_, index) => sessionFileForIndex(index)),
|
|
1107
1149
|
maxSubagentDepth: currentMaxSubagentDepth,
|
|
1150
|
+
workflowStageSubagentGuard,
|
|
1108
1151
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
1109
1152
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
1110
1153
|
controlConfig,
|
|
@@ -1118,7 +1161,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1118
1161
|
const normalized = normalizeSkillInput(params.skill);
|
|
1119
1162
|
const chainSkills = normalized === false ? [] : (normalized ?? []);
|
|
1120
1163
|
const chain = wrapChainTasksForFork(params.chain as ChainStep[], params.context);
|
|
1121
|
-
return executeAsyncChain(id, {
|
|
1164
|
+
return deps.runtime.executeAsyncChain(id, {
|
|
1122
1165
|
chain,
|
|
1123
1166
|
task: params.task,
|
|
1124
1167
|
agents,
|
|
@@ -1133,6 +1176,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1133
1176
|
chainSkills,
|
|
1134
1177
|
sessionFilesByFlatIndex: collectChainSessionFiles(chain, sessionFileForIndex),
|
|
1135
1178
|
maxSubagentDepth: currentMaxSubagentDepth,
|
|
1179
|
+
workflowStageSubagentGuard,
|
|
1136
1180
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
1137
1181
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
1138
1182
|
controlConfig,
|
|
@@ -1158,7 +1202,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1158
1202
|
const skills = normalizedSkills === false ? [] : normalizedSkills;
|
|
1159
1203
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, a.maxSubagentDepth);
|
|
1160
1204
|
const modelOverride = resolveModelCandidate((params.model as string | undefined) ?? a.model, availableModels, currentProvider);
|
|
1161
|
-
return executeAsyncSingle(id, {
|
|
1205
|
+
return deps.runtime.executeAsyncSingle(id, {
|
|
1162
1206
|
agent: params.agent!,
|
|
1163
1207
|
task: params.context === "fork" ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
1164
1208
|
agentConfig: a,
|
|
@@ -1176,6 +1220,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1176
1220
|
outputMode: effectiveOutputMode,
|
|
1177
1221
|
modelOverride,
|
|
1178
1222
|
maxSubagentDepth,
|
|
1223
|
+
workflowStageSubagentGuard,
|
|
1179
1224
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
1180
1225
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
1181
1226
|
controlConfig,
|
|
@@ -1188,7 +1233,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
1188
1233
|
return null;
|
|
1189
1234
|
}
|
|
1190
1235
|
|
|
1191
|
-
async function runChainPath(data: ExecutionContextData, deps:
|
|
1236
|
+
async function runChainPath(data: ExecutionContextData, deps: ResolvedExecutorDeps): Promise<SubagentToolResult> {
|
|
1192
1237
|
const {
|
|
1193
1238
|
params,
|
|
1194
1239
|
effectiveCwd,
|
|
@@ -1211,7 +1256,9 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
1211
1256
|
const normalized = normalizeSkillInput(params.skill);
|
|
1212
1257
|
const chainSkills = normalized === false ? [] : (normalized ?? []);
|
|
1213
1258
|
const chain = wrapChainTasksForFork(params.chain as ChainStep[], params.context);
|
|
1214
|
-
const
|
|
1259
|
+
const depthPolicy = resolveSubagentDepthPolicy(ctx, deps.config.maxSubagentDepth);
|
|
1260
|
+
const currentMaxSubagentDepth = depthPolicy.maxSubagentDepth;
|
|
1261
|
+
const workflowStageSubagentGuard = depthPolicy.workflowStageSubagentGuard;
|
|
1215
1262
|
const chainResult = await executeChain({
|
|
1216
1263
|
chain,
|
|
1217
1264
|
task: params.task,
|
|
@@ -1238,12 +1285,14 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
1238
1285
|
chainSkills,
|
|
1239
1286
|
chainDir: params.chainDir,
|
|
1240
1287
|
maxSubagentDepth: currentMaxSubagentDepth,
|
|
1288
|
+
workflowStageSubagentGuard,
|
|
1241
1289
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
1242
1290
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
1291
|
+
runSync: deps.runtime.runSync,
|
|
1243
1292
|
});
|
|
1244
1293
|
|
|
1245
1294
|
if (chainResult.requestedAsync) {
|
|
1246
|
-
if (!isAsyncAvailable()) {
|
|
1295
|
+
if (!deps.runtime.isAsyncAvailable()) {
|
|
1247
1296
|
return {
|
|
1248
1297
|
content: [{ type: "text", text: `Background mode requires upstream jiti for TypeScript execution but it could not be found. Ensure the ${APP_NAME}-subagents package dependencies are installed.` }],
|
|
1249
1298
|
isError: true,
|
|
@@ -1259,7 +1308,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
1259
1308
|
currentModel: currentModelFullId(ctx.model),
|
|
1260
1309
|
};
|
|
1261
1310
|
const asyncChain = wrapChainTasksForFork(chainResult.requestedAsync.chain, params.context);
|
|
1262
|
-
return executeAsyncChain(id, {
|
|
1311
|
+
return deps.runtime.executeAsyncChain(id, {
|
|
1263
1312
|
chain: asyncChain,
|
|
1264
1313
|
task: params.task,
|
|
1265
1314
|
agents,
|
|
@@ -1274,6 +1323,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
1274
1323
|
chainSkills: chainResult.requestedAsync.chainSkills,
|
|
1275
1324
|
sessionFilesByFlatIndex: collectChainSessionFiles(asyncChain, sessionFileForIndex),
|
|
1276
1325
|
maxSubagentDepth: currentMaxSubagentDepth,
|
|
1326
|
+
workflowStageSubagentGuard,
|
|
1277
1327
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
1278
1328
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
1279
1329
|
controlConfig,
|
|
@@ -1323,6 +1373,7 @@ interface ForegroundParallelRunInput {
|
|
|
1323
1373
|
maxOutput?: MaxOutputConfig;
|
|
1324
1374
|
paramsCwd: string;
|
|
1325
1375
|
maxSubagentDepths: number[];
|
|
1376
|
+
workflowStageSubagentGuard?: boolean;
|
|
1326
1377
|
availableModels: ModelInfo[];
|
|
1327
1378
|
modelOverrides: (string | undefined)[];
|
|
1328
1379
|
behaviors: Array<ReturnType<typeof resolveStepBehavior>>;
|
|
@@ -1335,11 +1386,12 @@ interface ForegroundParallelRunInput {
|
|
|
1335
1386
|
concurrencyLimit: number;
|
|
1336
1387
|
liveResults: (SingleResult | undefined)[];
|
|
1337
1388
|
liveProgress: (AgentProgress | undefined)[];
|
|
1338
|
-
onUpdate?: (r:
|
|
1389
|
+
onUpdate?: (r: SubagentToolResult) => void;
|
|
1339
1390
|
worktreeSetup?: WorktreeSetup;
|
|
1391
|
+
runtime: Pick<SubagentExecutorRuntimeDeps, "runSync">;
|
|
1340
1392
|
}
|
|
1341
1393
|
|
|
1342
|
-
function buildParallelModeError(message: string):
|
|
1394
|
+
function buildParallelModeError(message: string): SubagentToolResult {
|
|
1343
1395
|
return {
|
|
1344
1396
|
content: [{ type: "text", text: message }],
|
|
1345
1397
|
isError: true,
|
|
@@ -1354,7 +1406,7 @@ function createParallelWorktreeSetup(
|
|
|
1354
1406
|
tasks: TaskParam[],
|
|
1355
1407
|
setupHook: ExtensionConfig["worktreeSetupHook"],
|
|
1356
1408
|
setupHookTimeoutMs: ExtensionConfig["worktreeSetupHookTimeoutMs"],
|
|
1357
|
-
): { setup?: WorktreeSetup; errorResult?:
|
|
1409
|
+
): { setup?: WorktreeSetup; errorResult?: SubagentToolResult } {
|
|
1358
1410
|
if (!enabled) return {};
|
|
1359
1411
|
try {
|
|
1360
1412
|
return {
|
|
@@ -1469,7 +1521,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1469
1521
|
};
|
|
1470
1522
|
}
|
|
1471
1523
|
const agentConfig = input.agents.find((agent) => agent.name === task.agent);
|
|
1472
|
-
return runSync(input.ctx.cwd, input.agents, task.agent, taskText, {
|
|
1524
|
+
return input.runtime.runSync(input.ctx.cwd, input.agents, task.agent, taskText, {
|
|
1473
1525
|
cwd: taskCwd,
|
|
1474
1526
|
signal: input.signal,
|
|
1475
1527
|
interruptSignal: interruptController.signal,
|
|
@@ -1486,6 +1538,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1486
1538
|
outputPath,
|
|
1487
1539
|
outputMode: behavior?.outputMode,
|
|
1488
1540
|
maxSubagentDepth: input.maxSubagentDepths[index],
|
|
1541
|
+
workflowStageSubagentGuard: input.workflowStageSubagentGuard,
|
|
1489
1542
|
controlConfig: input.controlConfig,
|
|
1490
1543
|
onControlEvent: input.onControlEvent,
|
|
1491
1544
|
intercomSessionName: input.childIntercomTarget?.(task.agent, index),
|
|
@@ -1496,39 +1549,39 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1496
1549
|
preferredModelProvider: input.ctx.model?.provider,
|
|
1497
1550
|
currentModel: currentModelFullId(input.ctx.model),
|
|
1498
1551
|
skills: effectiveSkills === false ? [] : effectiveSkills,
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
}
|
|
1517
|
-
if (stepResults.length > 0) input.liveResults[index] = stepResults[0];
|
|
1518
|
-
if (stepProgress.length > 0) input.liveProgress[index] = stepProgress[0];
|
|
1519
|
-
const mergedResults = input.liveResults.filter((result): result is SingleResult => result !== undefined);
|
|
1520
|
-
const mergedProgress = input.liveProgress.filter((progress): progress is AgentProgress => progress !== undefined);
|
|
1521
|
-
input.onUpdate?.({
|
|
1522
|
-
content: progressUpdate.content,
|
|
1523
|
-
details: {
|
|
1524
|
-
mode: "parallel",
|
|
1525
|
-
results: mergedResults,
|
|
1526
|
-
progress: mergedProgress,
|
|
1527
|
-
controlEvents: progressUpdate.details?.controlEvents,
|
|
1528
|
-
totalSteps: input.tasks.length,
|
|
1529
|
-
},
|
|
1530
|
-
});
|
|
1552
|
+
onUpdate: input.onUpdate
|
|
1553
|
+
? (progressUpdate) => {
|
|
1554
|
+
const stepResults = progressUpdate.details?.results || [];
|
|
1555
|
+
const stepProgress = progressUpdate.details?.progress || [];
|
|
1556
|
+
if (input.foregroundControl && stepProgress.length > 0) {
|
|
1557
|
+
const current = stepProgress[0];
|
|
1558
|
+
input.foregroundControl.currentAgent = task.agent;
|
|
1559
|
+
input.foregroundControl.currentIndex = index;
|
|
1560
|
+
input.foregroundControl.currentActivityState = current?.activityState;
|
|
1561
|
+
input.foregroundControl.lastActivityAt = current?.lastActivityAt;
|
|
1562
|
+
input.foregroundControl.currentTool = current?.currentTool;
|
|
1563
|
+
input.foregroundControl.currentToolStartedAt = current?.currentToolStartedAt;
|
|
1564
|
+
input.foregroundControl.currentPath = current?.currentPath;
|
|
1565
|
+
input.foregroundControl.turnCount = current?.turnCount;
|
|
1566
|
+
input.foregroundControl.tokens = current?.tokens;
|
|
1567
|
+
input.foregroundControl.toolCount = current?.toolCount;
|
|
1568
|
+
input.foregroundControl.updatedAt = Date.now();
|
|
1531
1569
|
}
|
|
1570
|
+
if (stepResults.length > 0) input.liveResults[index] = stepResults[0];
|
|
1571
|
+
if (stepProgress.length > 0) input.liveProgress[index] = stepProgress[0];
|
|
1572
|
+
const mergedResults = input.liveResults.filter((result): result is SingleResult => result !== undefined);
|
|
1573
|
+
const mergedProgress = input.liveProgress.filter((progress): progress is AgentProgress => progress !== undefined);
|
|
1574
|
+
input.onUpdate?.({
|
|
1575
|
+
content: progressUpdate.content,
|
|
1576
|
+
details: {
|
|
1577
|
+
mode: "parallel",
|
|
1578
|
+
results: mergedResults,
|
|
1579
|
+
progress: mergedProgress,
|
|
1580
|
+
controlEvents: progressUpdate.details?.controlEvents,
|
|
1581
|
+
totalSteps: input.tasks.length,
|
|
1582
|
+
},
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1532
1585
|
: undefined,
|
|
1533
1586
|
}).finally(() => {
|
|
1534
1587
|
if (input.foregroundControl?.currentIndex === index) {
|
|
@@ -1539,7 +1592,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
1539
1592
|
});
|
|
1540
1593
|
}
|
|
1541
1594
|
|
|
1542
|
-
async function runParallelPath(data: ExecutionContextData, deps:
|
|
1595
|
+
async function runParallelPath(data: ExecutionContextData, deps: ResolvedExecutorDeps): Promise<SubagentToolResult> {
|
|
1543
1596
|
const {
|
|
1544
1597
|
params,
|
|
1545
1598
|
effectiveCwd,
|
|
@@ -1585,7 +1638,9 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1585
1638
|
agentConfigs.push(config);
|
|
1586
1639
|
}
|
|
1587
1640
|
|
|
1588
|
-
const
|
|
1641
|
+
const depthPolicy = resolveSubagentDepthPolicy(ctx, deps.config.maxSubagentDepth);
|
|
1642
|
+
const currentMaxSubagentDepth = depthPolicy.maxSubagentDepth;
|
|
1643
|
+
const workflowStageSubagentGuard = depthPolicy.workflowStageSubagentGuard;
|
|
1589
1644
|
const maxSubagentDepths = agentConfigs.map((config) =>
|
|
1590
1645
|
resolveChildMaxSubagentDepth(currentMaxSubagentDepth, config.maxSubagentDepth),
|
|
1591
1646
|
);
|
|
@@ -1658,7 +1713,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1658
1713
|
}
|
|
1659
1714
|
|
|
1660
1715
|
if (result.runInBackground) {
|
|
1661
|
-
if (!isAsyncAvailable()) {
|
|
1716
|
+
if (!deps.runtime.isAsyncAvailable()) {
|
|
1662
1717
|
return {
|
|
1663
1718
|
content: [{ type: "text", text: `Background mode requires upstream jiti for TypeScript execution but it could not be found. Ensure the ${APP_NAME}-subagents package dependencies are installed.` }],
|
|
1664
1719
|
isError: true,
|
|
@@ -1688,7 +1743,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1688
1743
|
...(progress !== undefined ? { progress } : {}),
|
|
1689
1744
|
};
|
|
1690
1745
|
});
|
|
1691
|
-
return executeAsyncChain(id, {
|
|
1746
|
+
return deps.runtime.executeAsyncChain(id, {
|
|
1692
1747
|
chain: [{ parallel: parallelTasks, concurrency: parallelConcurrency, worktree: params.worktree }],
|
|
1693
1748
|
resultMode: "parallel",
|
|
1694
1749
|
agents,
|
|
@@ -1703,6 +1758,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1703
1758
|
chainSkills: [],
|
|
1704
1759
|
sessionFilesByFlatIndex: tasks.map((_, index) => sessionFileForIndex(index)),
|
|
1705
1760
|
maxSubagentDepth: currentMaxSubagentDepth,
|
|
1761
|
+
workflowStageSubagentGuard,
|
|
1706
1762
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
1707
1763
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
1708
1764
|
controlConfig,
|
|
@@ -1767,6 +1823,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1767
1823
|
artifactsDir,
|
|
1768
1824
|
maxOutput: params.maxOutput,
|
|
1769
1825
|
paramsCwd: effectiveCwd,
|
|
1826
|
+
workflowStageSubagentGuard,
|
|
1770
1827
|
availableModels,
|
|
1771
1828
|
modelOverrides,
|
|
1772
1829
|
behaviors,
|
|
@@ -1782,6 +1839,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1782
1839
|
liveProgress,
|
|
1783
1840
|
onUpdate,
|
|
1784
1841
|
worktreeSetup,
|
|
1842
|
+
runtime: deps.runtime,
|
|
1785
1843
|
});
|
|
1786
1844
|
for (let i = 0; i < results.length; i++) {
|
|
1787
1845
|
const run = results[i]!;
|
|
@@ -1860,7 +1918,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1860
1918
|
}
|
|
1861
1919
|
}
|
|
1862
1920
|
|
|
1863
|
-
async function runSinglePath(data: ExecutionContextData, deps:
|
|
1921
|
+
async function runSinglePath(data: ExecutionContextData, deps: ResolvedExecutorDeps): Promise<SubagentToolResult> {
|
|
1864
1922
|
const {
|
|
1865
1923
|
params,
|
|
1866
1924
|
effectiveCwd,
|
|
@@ -1902,7 +1960,9 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1902
1960
|
const rawOutput = params.output !== undefined ? params.output : agentConfig.output;
|
|
1903
1961
|
let effectiveOutput = normalizeSingleOutputOverride(rawOutput, agentConfig.output);
|
|
1904
1962
|
const effectiveOutputMode = params.outputMode ?? "inline";
|
|
1905
|
-
const
|
|
1963
|
+
const depthPolicy = resolveSubagentDepthPolicy(ctx, deps.config.maxSubagentDepth);
|
|
1964
|
+
const currentMaxSubagentDepth = depthPolicy.maxSubagentDepth;
|
|
1965
|
+
const workflowStageSubagentGuard = depthPolicy.workflowStageSubagentGuard;
|
|
1906
1966
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, agentConfig.maxSubagentDepth);
|
|
1907
1967
|
|
|
1908
1968
|
if (params.clarify === true && ctx.hasUI) {
|
|
@@ -1938,7 +1998,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1938
1998
|
if (override?.skills !== undefined) skillOverride = override.skills;
|
|
1939
1999
|
|
|
1940
2000
|
if (result.runInBackground) {
|
|
1941
|
-
if (!isAsyncAvailable()) {
|
|
2001
|
+
if (!deps.runtime.isAsyncAvailable()) {
|
|
1942
2002
|
return {
|
|
1943
2003
|
content: [{ type: "text", text: `Background mode requires upstream jiti for TypeScript execution but it could not be found. Ensure the ${APP_NAME}-subagents package dependencies are installed.` }],
|
|
1944
2004
|
isError: true,
|
|
@@ -1953,7 +2013,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1953
2013
|
currentModelProvider: ctx.model?.provider,
|
|
1954
2014
|
currentModel: currentModelFullId(ctx.model),
|
|
1955
2015
|
};
|
|
1956
|
-
return executeAsyncSingle(id, {
|
|
2016
|
+
return deps.runtime.executeAsyncSingle(id, {
|
|
1957
2017
|
agent: params.agent!,
|
|
1958
2018
|
task: params.context === "fork" ? wrapForkTask(task) : task,
|
|
1959
2019
|
agentConfig,
|
|
@@ -1971,6 +2031,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1971
2031
|
outputMode: effectiveOutputMode,
|
|
1972
2032
|
modelOverride,
|
|
1973
2033
|
maxSubagentDepth,
|
|
2034
|
+
workflowStageSubagentGuard,
|
|
1974
2035
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
1975
2036
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
1976
2037
|
controlConfig,
|
|
@@ -2014,7 +2075,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
2014
2075
|
}
|
|
2015
2076
|
|
|
2016
2077
|
const forwardSingleUpdate = onUpdate
|
|
2017
|
-
? (update:
|
|
2078
|
+
? (update: SubagentToolResult) => {
|
|
2018
2079
|
if (foregroundControl) {
|
|
2019
2080
|
const firstProgress = update.details?.progress?.[0];
|
|
2020
2081
|
foregroundControl.currentAgent = params.agent;
|
|
@@ -2033,7 +2094,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
2033
2094
|
}
|
|
2034
2095
|
: undefined;
|
|
2035
2096
|
|
|
2036
|
-
const r = await runSync(ctx.cwd, agents, params.agent!, task, {
|
|
2097
|
+
const r = await deps.runtime.runSync(ctx.cwd, agents, params.agent!, task, {
|
|
2037
2098
|
cwd: effectiveCwd,
|
|
2038
2099
|
signal,
|
|
2039
2100
|
interruptSignal: interruptController.signal,
|
|
@@ -2049,6 +2110,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
2049
2110
|
outputPath,
|
|
2050
2111
|
outputMode: effectiveOutputMode,
|
|
2051
2112
|
maxSubagentDepth,
|
|
2113
|
+
workflowStageSubagentGuard,
|
|
2052
2114
|
onUpdate: forwardSingleUpdate,
|
|
2053
2115
|
controlConfig,
|
|
2054
2116
|
onControlEvent,
|
|
@@ -2145,22 +2207,23 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
2145
2207
|
};
|
|
2146
2208
|
}
|
|
2147
2209
|
|
|
2148
|
-
export function createSubagentExecutor(
|
|
2210
|
+
export function createSubagentExecutor(rawDeps: ExecutorDeps): {
|
|
2149
2211
|
execute: (
|
|
2150
2212
|
id: string,
|
|
2151
2213
|
params: SubagentParamsLike,
|
|
2152
2214
|
signal: AbortSignal,
|
|
2153
|
-
onUpdate: ((r:
|
|
2215
|
+
onUpdate: ((r: SubagentToolResult) => void) | undefined,
|
|
2154
2216
|
ctx: ExtensionContext,
|
|
2155
|
-
) => Promise<
|
|
2217
|
+
) => Promise<SubagentToolResult>;
|
|
2156
2218
|
} {
|
|
2219
|
+
const deps: ResolvedExecutorDeps = { ...rawDeps, runtime: resolveSubagentExecutorRuntimeDeps(rawDeps.runtime) };
|
|
2157
2220
|
const execute = async (
|
|
2158
2221
|
_id: string,
|
|
2159
2222
|
params: SubagentParamsLike,
|
|
2160
2223
|
signal: AbortSignal,
|
|
2161
|
-
onUpdate: ((r:
|
|
2224
|
+
onUpdate: ((r: SubagentToolResult) => void) | undefined,
|
|
2162
2225
|
ctx: ExtensionContext,
|
|
2163
|
-
): Promise<
|
|
2226
|
+
): Promise<SubagentToolResult> => {
|
|
2164
2227
|
deps.state.baseCwd = ctx.cwd;
|
|
2165
2228
|
deps.state.foregroundRuns ??= new Map();
|
|
2166
2229
|
deps.state.foregroundControls ??= new Map();
|
|
@@ -2219,7 +2282,12 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
2219
2282
|
const foreground = getForegroundControl(deps.state, undefined);
|
|
2220
2283
|
if (foreground) return foregroundStatusResult(foreground);
|
|
2221
2284
|
}
|
|
2222
|
-
return inspectSubagentStatus(
|
|
2285
|
+
return inspectSubagentStatus({
|
|
2286
|
+
action: "status",
|
|
2287
|
+
id: paramsWithResolvedCwd.id,
|
|
2288
|
+
runId: paramsWithResolvedCwd.runId,
|
|
2289
|
+
dir: paramsWithResolvedCwd.dir,
|
|
2290
|
+
}, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
|
|
2223
2291
|
}
|
|
2224
2292
|
if (params.action === "resume") {
|
|
2225
2293
|
return resumeAsyncRun({ params: paramsWithResolvedCwd, requestCwd, ctx, deps });
|
|
@@ -2278,16 +2346,15 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
2278
2346
|
return handleManagementAction(params.action, paramsWithResolvedCwd, { ...ctx, cwd: requestCwd });
|
|
2279
2347
|
}
|
|
2280
2348
|
|
|
2281
|
-
const
|
|
2349
|
+
const depthPolicy = resolveSubagentDepthPolicy(ctx, deps.config.maxSubagentDepth);
|
|
2350
|
+
const { blocked, depth, maxDepth, workflowStageGuard } = checkSubagentDepth(depthPolicy.maxSubagentDepth);
|
|
2351
|
+
const workflowStageSubagentGuard = workflowStageGuard || depthPolicy.workflowStageSubagentGuard;
|
|
2282
2352
|
if (blocked) {
|
|
2283
2353
|
return {
|
|
2284
2354
|
content: [
|
|
2285
2355
|
{
|
|
2286
2356
|
type: "text",
|
|
2287
|
-
text:
|
|
2288
|
-
`Nested subagent call blocked (depth=${depth}, max=${maxDepth}). ` +
|
|
2289
|
-
"You are running at the maximum subagent nesting depth. " +
|
|
2290
|
-
"Complete your current task directly without delegating to further subagents.",
|
|
2357
|
+
text: subagentDepthBlockedMessage(depth, maxDepth, { workflowStageGuard: workflowStageSubagentGuard }),
|
|
2291
2358
|
},
|
|
2292
2359
|
],
|
|
2293
2360
|
isError: true,
|
|
@@ -2385,7 +2452,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
2385
2452
|
sessionFileForIndex(idx) ?? path.join(sessionDirForIndex(idx), "session.jsonl");
|
|
2386
2453
|
|
|
2387
2454
|
const onUpdateWithContext = onUpdate
|
|
2388
|
-
? (r:
|
|
2455
|
+
? (r: SubagentToolResult) => onUpdate(withForkContext(r, effectiveParams.context))
|
|
2389
2456
|
: undefined;
|
|
2390
2457
|
|
|
2391
2458
|
const execData: ExecutionContextData = {
|
|
@@ -2428,7 +2495,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
2428
2495
|
deps.state.lastForegroundControlId = runId;
|
|
2429
2496
|
}
|
|
2430
2497
|
|
|
2431
|
-
const writeNestedForegroundEvent = (type: "subagent.nested.started" | "subagent.nested.completed", result?:
|
|
2498
|
+
const writeNestedForegroundEvent = (type: "subagent.nested.started" | "subagent.nested.completed", result?: SubagentToolResult): void => {
|
|
2432
2499
|
if (!inheritedNestedRoute || !nestedParentAddress) return;
|
|
2433
2500
|
const now = Date.now();
|
|
2434
2501
|
const details = result?.details;
|