pi-subagents 0.18.1 → 0.19.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 +11 -0
- package/README.md +2 -2
- package/agent-manager-chain-detail.ts +50 -6
- package/agent-manager-detail.ts +15 -2
- package/agent-manager.ts +76 -23
- package/async-execution.ts +45 -18
- package/chain-execution.ts +12 -2
- package/execution.ts +2 -4
- package/index.ts +1 -1
- package/intercom-bridge.ts +3 -3
- package/package.json +5 -1
- package/prompts/parallel-review.md +8 -0
- package/schemas.ts +4 -1
- package/settings.ts +5 -0
- package/slash-commands.ts +27 -28
- package/subagent-executor.ts +102 -18
- package/subagent-runner.ts +8 -0
- package/subagents-status.ts +216 -2
- package/worktree.ts +19 -10
package/settings.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { AgentConfig } from "./agents.ts";
|
|
|
8
8
|
import { normalizeSkillInput } from "./skills.ts";
|
|
9
9
|
import { CHAIN_RUNS_DIR } from "./types.ts";
|
|
10
10
|
const CHAIN_DIR_MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
11
|
+
const INITIAL_PROGRESS_CONTENT = "# Progress\n\n## Status\nIn Progress\n\n## Tasks\n\n## Files Changed\n\n## Notes\n";
|
|
11
12
|
|
|
12
13
|
// =============================================================================
|
|
13
14
|
// Behavior Resolution Types
|
|
@@ -224,6 +225,10 @@ function resolveChainPath(filePath: string, chainDir: string): string {
|
|
|
224
225
|
* Build chain instructions from resolved behavior.
|
|
225
226
|
* These are appended to the task to tell the agent what to read/write.
|
|
226
227
|
*/
|
|
228
|
+
export function writeInitialProgressFile(progressDir: string): void {
|
|
229
|
+
fs.writeFileSync(path.join(progressDir, "progress.md"), INITIAL_PROGRESS_CONTENT);
|
|
230
|
+
}
|
|
231
|
+
|
|
227
232
|
export function buildChainInstructions(
|
|
228
233
|
behavior: ResolvedStepBehavior,
|
|
229
234
|
chainDir: string,
|
package/slash-commands.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { AgentManagerComponent, type ManagerResult } from "./agent-manager.ts";
|
|
|
8
8
|
import { SubagentsStatusComponent } from "./subagents-status.ts";
|
|
9
9
|
import { discoverAvailableSkills } from "./skills.ts";
|
|
10
10
|
import type { SubagentParamsLike } from "./subagent-executor.ts";
|
|
11
|
+
import { isParallelStep, type ChainStep } from "./settings.ts";
|
|
11
12
|
import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
|
|
12
13
|
import {
|
|
13
14
|
applySlashUpdate,
|
|
@@ -308,48 +309,43 @@ async function openAgentManager(
|
|
|
308
309
|
);
|
|
309
310
|
if (!result) return;
|
|
310
311
|
|
|
312
|
+
const launchOptions: SubagentParamsLike = {
|
|
313
|
+
clarify: !result.skipClarify && !result.background,
|
|
314
|
+
agentScope: "both",
|
|
315
|
+
...(result.fork ? { context: "fork" as const } : {}),
|
|
316
|
+
...(result.background ? { async: true } : {}),
|
|
317
|
+
};
|
|
318
|
+
|
|
311
319
|
if (result.action === "chain") {
|
|
312
320
|
const chain = result.agents.map((name, i) => ({
|
|
313
321
|
agent: name,
|
|
314
322
|
...(i === 0 ? { task: result.task } : {}),
|
|
315
323
|
}));
|
|
316
|
-
await runSlashSubagent(pi, ctx, {
|
|
317
|
-
chain,
|
|
318
|
-
task: result.task,
|
|
319
|
-
clarify: true,
|
|
320
|
-
agentScope: "both",
|
|
321
|
-
});
|
|
324
|
+
await runSlashSubagent(pi, ctx, { chain, task: result.task, ...launchOptions });
|
|
322
325
|
return;
|
|
323
326
|
}
|
|
324
327
|
|
|
325
328
|
if (result.action === "launch") {
|
|
326
|
-
await runSlashSubagent(pi, ctx, {
|
|
327
|
-
agent: result.agent,
|
|
328
|
-
task: result.task,
|
|
329
|
-
clarify: !result.skipClarify,
|
|
330
|
-
agentScope: "both",
|
|
331
|
-
});
|
|
329
|
+
await runSlashSubagent(pi, ctx, { agent: result.agent, task: result.task, ...launchOptions });
|
|
332
330
|
} else if (result.action === "launch-chain") {
|
|
333
|
-
const chainParam = result.chain.steps.map((step) =>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
task: result.task,
|
|
345
|
-
clarify: !result.skipClarify,
|
|
346
|
-
agentScope: "both",
|
|
331
|
+
const chainParam = (result.chain.steps as unknown as ChainStep[]).map((step) => {
|
|
332
|
+
if (isParallelStep(step)) return result.worktree ? { ...step, worktree: true } : { ...step };
|
|
333
|
+
return {
|
|
334
|
+
agent: step.agent,
|
|
335
|
+
task: step.task || undefined,
|
|
336
|
+
output: step.output,
|
|
337
|
+
reads: step.reads,
|
|
338
|
+
progress: step.progress,
|
|
339
|
+
skill: step.skill ?? (step as typeof step & { skills?: string[] | false }).skills,
|
|
340
|
+
model: step.model,
|
|
341
|
+
};
|
|
347
342
|
});
|
|
343
|
+
await runSlashSubagent(pi, ctx, { chain: chainParam, task: result.task, ...launchOptions });
|
|
348
344
|
} else if (result.action === "parallel") {
|
|
349
345
|
await runSlashSubagent(pi, ctx, {
|
|
350
346
|
tasks: result.tasks,
|
|
351
|
-
|
|
352
|
-
|
|
347
|
+
...launchOptions,
|
|
348
|
+
...(result.worktree ? { worktree: true } : {}),
|
|
353
349
|
});
|
|
354
350
|
}
|
|
355
351
|
}
|
|
@@ -503,8 +499,11 @@ export function registerSlashCommands(
|
|
|
503
499
|
const tasks = parsed.steps.map(({ name, config, task: stepTask }) => ({
|
|
504
500
|
agent: name,
|
|
505
501
|
task: stepTask ?? parsed.task,
|
|
502
|
+
...(config.output !== undefined ? { output: config.output } : {}),
|
|
503
|
+
...(config.reads !== undefined ? { reads: config.reads } : {}),
|
|
506
504
|
...(config.model ? { model: config.model } : {}),
|
|
507
505
|
...(config.skill !== undefined ? { skill: config.skill } : {}),
|
|
506
|
+
...(config.progress !== undefined ? { progress: config.progress } : {}),
|
|
508
507
|
}));
|
|
509
508
|
const params: SubagentParamsLike = { tasks, clarify: false, agentScope: "both" };
|
|
510
509
|
if (bg) params.async = true;
|
package/subagent-executor.ts
CHANGED
|
@@ -14,16 +14,20 @@ import { resolveModelCandidate } from "./model-fallback.ts";
|
|
|
14
14
|
import { aggregateParallelOutputs } from "./parallel-utils.ts";
|
|
15
15
|
import { recordRun } from "./run-history.ts";
|
|
16
16
|
import {
|
|
17
|
+
buildChainInstructions,
|
|
18
|
+
writeInitialProgressFile,
|
|
17
19
|
getStepAgents,
|
|
18
20
|
isParallelStep,
|
|
19
21
|
resolveStepBehavior,
|
|
20
22
|
type ChainStep,
|
|
23
|
+
type ResolvedStepBehavior,
|
|
21
24
|
type SequentialStep,
|
|
25
|
+
type StepOverrides,
|
|
22
26
|
} from "./settings.ts";
|
|
23
27
|
import { discoverAvailableSkills, normalizeSkillInput } from "./skills.ts";
|
|
24
28
|
import { executeAsyncChain, executeAsyncSingle, isAsyncAvailable } from "./async-execution.ts";
|
|
25
29
|
import { createForkContextResolver } from "./fork-context.ts";
|
|
26
|
-
import { applyIntercomBridgeToAgent, resolveIntercomBridge, resolveIntercomSessionTarget, resolveSubagentIntercomTarget, type IntercomBridgeState } from "./intercom-bridge.ts";
|
|
30
|
+
import { applyIntercomBridgeToAgent, INTERCOM_BRIDGE_MARKER, resolveIntercomBridge, resolveIntercomSessionTarget, resolveSubagentIntercomTarget, type IntercomBridgeState } from "./intercom-bridge.ts";
|
|
27
31
|
import { formatControlIntercomMessage, formatControlNoticeMessage, resolveControlConfig, shouldNotifyControlEvent } from "./subagent-control.ts";
|
|
28
32
|
import { finalizeSingleOutput, injectSingleOutputInstruction, resolveSingleOutputPath } from "./single-output.ts";
|
|
29
33
|
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, readStatus, resolveChildCwd } from "./utils.ts";
|
|
@@ -46,6 +50,7 @@ import {
|
|
|
46
50
|
type ControlEvent,
|
|
47
51
|
type Details,
|
|
48
52
|
type ExtensionConfig,
|
|
53
|
+
type IntercomEventBus,
|
|
49
54
|
type MaxOutputConfig,
|
|
50
55
|
type ResolvedControlConfig,
|
|
51
56
|
type SingleResult,
|
|
@@ -68,6 +73,9 @@ interface TaskParam {
|
|
|
68
73
|
task: string;
|
|
69
74
|
cwd?: string;
|
|
70
75
|
count?: number;
|
|
76
|
+
output?: string | boolean;
|
|
77
|
+
reads?: string[] | boolean;
|
|
78
|
+
progress?: boolean;
|
|
71
79
|
model?: string;
|
|
72
80
|
skill?: string | string[] | boolean;
|
|
73
81
|
}
|
|
@@ -544,6 +552,9 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
|
|
|
544
552
|
cwd: task.cwd,
|
|
545
553
|
...(modelOverrides[index] ? { model: modelOverrides[index] } : {}),
|
|
546
554
|
...(skillOverrides[index] !== undefined ? { skill: skillOverrides[index] } : {}),
|
|
555
|
+
...(task.output === true ? (agentConfigs[index]?.output ? { output: agentConfigs[index]!.output } : {}) : task.output !== undefined ? { output: task.output } : {}),
|
|
556
|
+
...(task.reads !== undefined && task.reads !== true ? { reads: task.reads } : {}),
|
|
557
|
+
...(task.progress !== undefined ? { progress: task.progress } : {}),
|
|
547
558
|
}));
|
|
548
559
|
return executeAsyncChain(id, {
|
|
549
560
|
chain: [{
|
|
@@ -669,6 +680,7 @@ async function runChainPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
669
680
|
task: params.task,
|
|
670
681
|
agents,
|
|
671
682
|
ctx,
|
|
683
|
+
intercomEvents: deps.pi.events,
|
|
672
684
|
signal,
|
|
673
685
|
runId,
|
|
674
686
|
cwd: effectiveCwd,
|
|
@@ -741,6 +753,7 @@ interface ForegroundParallelRunInput {
|
|
|
741
753
|
taskTexts: string[];
|
|
742
754
|
agents: AgentConfig[];
|
|
743
755
|
ctx: ExtensionContext;
|
|
756
|
+
intercomEvents: IntercomEventBus;
|
|
744
757
|
signal: AbortSignal;
|
|
745
758
|
runId: string;
|
|
746
759
|
sessionDirForIndex: (idx?: number) => string | undefined;
|
|
@@ -749,12 +762,12 @@ interface ForegroundParallelRunInput {
|
|
|
749
762
|
artifactConfig: ArtifactConfig;
|
|
750
763
|
artifactsDir: string;
|
|
751
764
|
maxOutput?: MaxOutputConfig;
|
|
752
|
-
paramsCwd
|
|
765
|
+
paramsCwd: string;
|
|
753
766
|
maxSubagentDepths: number[];
|
|
754
767
|
availableModels: ModelInfo[];
|
|
755
768
|
modelOverrides: (string | undefined)[];
|
|
756
|
-
skillOverrides: (string[] | false | undefined)[];
|
|
757
769
|
behaviors: Array<ReturnType<typeof resolveStepBehavior>>;
|
|
770
|
+
firstProgressIndex: number;
|
|
758
771
|
controlConfig: ResolvedControlConfig;
|
|
759
772
|
onControlEvent?: (event: ControlEvent) => void;
|
|
760
773
|
childIntercomTarget?: (agent: string, index: number) => string | undefined;
|
|
@@ -822,12 +835,11 @@ function buildChainWorktreeTaskCwdError(chain: ChainStep[], sharedCwd: string):
|
|
|
822
835
|
|
|
823
836
|
function resolveParallelTaskCwd(
|
|
824
837
|
task: TaskParam,
|
|
825
|
-
paramsCwd: string
|
|
838
|
+
paramsCwd: string,
|
|
826
839
|
worktreeSetup: WorktreeSetup | undefined,
|
|
827
840
|
index: number,
|
|
828
|
-
): string
|
|
841
|
+
): string {
|
|
829
842
|
if (worktreeSetup) return worktreeSetup.worktrees[index]!.agentCwd;
|
|
830
|
-
if (!paramsCwd) return task.cwd;
|
|
831
843
|
return resolveChildCwd(paramsCwd, task.cwd);
|
|
832
844
|
}
|
|
833
845
|
|
|
@@ -842,11 +854,46 @@ function buildParallelWorktreeSuffix(
|
|
|
842
854
|
return formatWorktreeDiffSummary(diffs);
|
|
843
855
|
}
|
|
844
856
|
|
|
857
|
+
function findDuplicateParallelOutputPath(input: {
|
|
858
|
+
tasks: TaskParam[];
|
|
859
|
+
behaviors: ResolvedStepBehavior[];
|
|
860
|
+
paramsCwd: string;
|
|
861
|
+
ctxCwd: string;
|
|
862
|
+
worktreeSetup?: WorktreeSetup;
|
|
863
|
+
}): string | undefined {
|
|
864
|
+
const seen = new Map<string, { index: number; agent: string }>();
|
|
865
|
+
for (let index = 0; index < input.tasks.length; index++) {
|
|
866
|
+
const behavior = input.behaviors[index];
|
|
867
|
+
if (!behavior?.output) continue;
|
|
868
|
+
const task = input.tasks[index]!;
|
|
869
|
+
const taskCwd = resolveParallelTaskCwd(task, input.paramsCwd, input.worktreeSetup, index);
|
|
870
|
+
const outputPath = resolveSingleOutputPath(behavior.output, input.ctxCwd, taskCwd);
|
|
871
|
+
if (!outputPath) continue;
|
|
872
|
+
const previous = seen.get(outputPath);
|
|
873
|
+
if (previous) {
|
|
874
|
+
return `Parallel tasks ${previous.index + 1} (${previous.agent}) and ${index + 1} (${task.agent}) resolve output to the same path: ${outputPath}. Use distinct output paths.`;
|
|
875
|
+
}
|
|
876
|
+
seen.set(outputPath, { index, agent: task.agent });
|
|
877
|
+
}
|
|
878
|
+
return undefined;
|
|
879
|
+
}
|
|
880
|
+
|
|
845
881
|
async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Promise<SingleResult[]> {
|
|
846
882
|
return mapConcurrent(input.tasks, input.concurrencyLimit, async (task, index) => {
|
|
847
|
-
const
|
|
848
|
-
const effectiveSkills =
|
|
883
|
+
const behavior = input.behaviors[index];
|
|
884
|
+
const effectiveSkills = behavior?.skills;
|
|
849
885
|
const taskCwd = resolveParallelTaskCwd(task, input.paramsCwd, input.worktreeSetup, index);
|
|
886
|
+
const readInstructions = behavior
|
|
887
|
+
? buildChainInstructions({ ...behavior, output: false, progress: false }, taskCwd, false)
|
|
888
|
+
: { prefix: "", suffix: "" };
|
|
889
|
+
const progressInstructions = behavior
|
|
890
|
+
? buildChainInstructions({ ...behavior, output: false, reads: false }, input.paramsCwd, index === input.firstProgressIndex)
|
|
891
|
+
: { prefix: "", suffix: "" };
|
|
892
|
+
const outputPath = resolveSingleOutputPath(behavior?.output, input.ctx.cwd, taskCwd);
|
|
893
|
+
const taskText = injectSingleOutputInstruction(
|
|
894
|
+
`${readInstructions.prefix}${input.taskTexts[index]!}${progressInstructions.suffix}`,
|
|
895
|
+
outputPath,
|
|
896
|
+
);
|
|
850
897
|
const interruptController = new AbortController();
|
|
851
898
|
if (input.foregroundControl) {
|
|
852
899
|
input.foregroundControl.currentAgent = task.agent;
|
|
@@ -861,10 +908,13 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
861
908
|
return true;
|
|
862
909
|
};
|
|
863
910
|
}
|
|
864
|
-
|
|
911
|
+
const agentConfig = input.agents.find((agent) => agent.name === task.agent);
|
|
912
|
+
return runSync(input.ctx.cwd, input.agents, task.agent, taskText, {
|
|
865
913
|
cwd: taskCwd,
|
|
866
914
|
signal: input.signal,
|
|
867
915
|
interruptSignal: interruptController.signal,
|
|
916
|
+
allowIntercomDetach: agentConfig?.systemPrompt?.includes(INTERCOM_BRIDGE_MARKER) === true,
|
|
917
|
+
intercomEvents: input.intercomEvents,
|
|
868
918
|
runId: input.runId,
|
|
869
919
|
index,
|
|
870
920
|
sessionDir: input.sessionDirForIndex(index),
|
|
@@ -873,6 +923,7 @@ async function runForegroundParallelTasks(input: ForegroundParallelRunInput): Pr
|
|
|
873
923
|
artifactsDir: input.artifactConfig.enabled ? input.artifactsDir : undefined,
|
|
874
924
|
artifactConfig: input.artifactConfig,
|
|
875
925
|
maxOutput: input.maxOutput,
|
|
926
|
+
outputPath,
|
|
876
927
|
maxSubagentDepth: input.maxSubagentDepths[index],
|
|
877
928
|
controlConfig: input.controlConfig,
|
|
878
929
|
onControlEvent: input.onControlEvent,
|
|
@@ -983,16 +1034,23 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
983
1034
|
fullId: `${m.provider}/${m.id}`,
|
|
984
1035
|
}));
|
|
985
1036
|
let taskTexts = tasks.map((t) => t.task);
|
|
986
|
-
const modelOverrides: (string | undefined)[] = tasks.map((t, i) =>
|
|
987
|
-
resolveModelCandidate(t.model ?? agentConfigs[i]?.model, availableModels, currentProvider),
|
|
988
|
-
);
|
|
989
1037
|
const skillOverrides: (string[] | false | undefined)[] = tasks.map((t) =>
|
|
990
1038
|
normalizeSkillInput(t.skill),
|
|
991
1039
|
);
|
|
1040
|
+
const behaviorOverrides: StepOverrides[] = tasks.map((task, index) => ({
|
|
1041
|
+
...(task.output !== undefined ? { output: task.output === true ? agentConfigs[index]?.output ?? false : task.output } : {}),
|
|
1042
|
+
...(task.reads !== undefined && task.reads !== true ? { reads: task.reads } : {}),
|
|
1043
|
+
...(task.progress !== undefined ? { progress: task.progress } : {}),
|
|
1044
|
+
...(skillOverrides[index] !== undefined ? { skills: skillOverrides[index] } : {}),
|
|
1045
|
+
...(task.model ? { model: task.model } : {}),
|
|
1046
|
+
}));
|
|
1047
|
+
const modelOverrides: (string | undefined)[] = tasks.map((_, i) =>
|
|
1048
|
+
resolveModelCandidate(behaviorOverrides[i]?.model ?? agentConfigs[i]?.model, availableModels, currentProvider),
|
|
1049
|
+
);
|
|
992
1050
|
|
|
993
1051
|
if (params.clarify === true && ctx.hasUI) {
|
|
994
1052
|
const behaviors = agentConfigs.map((c, i) =>
|
|
995
|
-
resolveStepBehavior(c,
|
|
1053
|
+
resolveStepBehavior(c, behaviorOverrides[i]!),
|
|
996
1054
|
);
|
|
997
1055
|
const availableSkills = discoverAvailableSkills(effectiveCwd);
|
|
998
1056
|
|
|
@@ -1021,8 +1079,17 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1021
1079
|
taskTexts = result.templates;
|
|
1022
1080
|
for (let i = 0; i < result.behaviorOverrides.length; i++) {
|
|
1023
1081
|
const override = result.behaviorOverrides[i];
|
|
1024
|
-
if (override?.model)
|
|
1025
|
-
|
|
1082
|
+
if (override?.model) {
|
|
1083
|
+
modelOverrides[i] = override.model;
|
|
1084
|
+
behaviorOverrides[i]!.model = override.model;
|
|
1085
|
+
}
|
|
1086
|
+
if (override?.output !== undefined) behaviorOverrides[i]!.output = override.output;
|
|
1087
|
+
if (override?.reads !== undefined) behaviorOverrides[i]!.reads = override.reads;
|
|
1088
|
+
if (override?.progress !== undefined) behaviorOverrides[i]!.progress = override.progress;
|
|
1089
|
+
if (override?.skills !== undefined) {
|
|
1090
|
+
skillOverrides[i] = override.skills;
|
|
1091
|
+
behaviorOverrides[i]!.skills = override.skills;
|
|
1092
|
+
}
|
|
1026
1093
|
}
|
|
1027
1094
|
|
|
1028
1095
|
if (result.runInBackground) {
|
|
@@ -1046,6 +1113,9 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1046
1113
|
cwd: t.cwd,
|
|
1047
1114
|
...(modelOverrides[i] ? { model: modelOverrides[i] } : {}),
|
|
1048
1115
|
...(skillOverrides[i] !== undefined ? { skill: skillOverrides[i] } : {}),
|
|
1116
|
+
...(behaviorOverrides[i]?.output !== undefined ? { output: behaviorOverrides[i]!.output } : {}),
|
|
1117
|
+
...(behaviorOverrides[i]?.reads !== undefined ? { reads: behaviorOverrides[i]!.reads } : {}),
|
|
1118
|
+
...(behaviorOverrides[i]?.progress !== undefined ? { progress: behaviorOverrides[i]!.progress } : {}),
|
|
1049
1119
|
}));
|
|
1050
1120
|
return executeAsyncChain(id, {
|
|
1051
1121
|
chain: [{ parallel: parallelTasks, concurrency: parallelConcurrency, worktree: params.worktree }],
|
|
@@ -1070,7 +1140,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1070
1140
|
}
|
|
1071
1141
|
}
|
|
1072
1142
|
|
|
1073
|
-
const behaviors = agentConfigs.map((config) => resolveStepBehavior(config,
|
|
1143
|
+
const behaviors = agentConfigs.map((config, index) => resolveStepBehavior(config, behaviorOverrides[index]!));
|
|
1144
|
+
const firstProgressIndex = behaviors.findIndex((behavior) => behavior.progress);
|
|
1074
1145
|
const liveResults: (SingleResult | undefined)[] = new Array(tasks.length).fill(undefined);
|
|
1075
1146
|
const liveProgress: (AgentProgress | undefined)[] = new Array(tasks.length).fill(undefined);
|
|
1076
1147
|
const foregroundControl = deps.state.foregroundControls.get(runId);
|
|
@@ -1085,6 +1156,18 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1085
1156
|
if (errorResult) return errorResult;
|
|
1086
1157
|
|
|
1087
1158
|
try {
|
|
1159
|
+
const duplicateOutputError = findDuplicateParallelOutputPath({
|
|
1160
|
+
tasks,
|
|
1161
|
+
behaviors,
|
|
1162
|
+
paramsCwd: effectiveCwd,
|
|
1163
|
+
ctxCwd: ctx.cwd,
|
|
1164
|
+
worktreeSetup,
|
|
1165
|
+
});
|
|
1166
|
+
if (duplicateOutputError) return buildParallelModeError(duplicateOutputError);
|
|
1167
|
+
|
|
1168
|
+
const parallelProgressPrecreated = firstProgressIndex !== -1;
|
|
1169
|
+
if (parallelProgressPrecreated) writeInitialProgressFile(effectiveCwd);
|
|
1170
|
+
|
|
1088
1171
|
if (params.context === "fork") {
|
|
1089
1172
|
for (let i = 0; i < taskTexts.length; i++) {
|
|
1090
1173
|
taskTexts[i] = wrapForkTask(taskTexts[i]!);
|
|
@@ -1096,6 +1179,7 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1096
1179
|
taskTexts,
|
|
1097
1180
|
agents,
|
|
1098
1181
|
ctx,
|
|
1182
|
+
intercomEvents: deps.pi.events,
|
|
1099
1183
|
signal,
|
|
1100
1184
|
runId,
|
|
1101
1185
|
sessionDirForIndex,
|
|
@@ -1107,8 +1191,8 @@ async function runParallelPath(data: ExecutionContextData, deps: ExecutorDeps):
|
|
|
1107
1191
|
paramsCwd: effectiveCwd,
|
|
1108
1192
|
availableModels,
|
|
1109
1193
|
modelOverrides,
|
|
1110
|
-
skillOverrides,
|
|
1111
1194
|
behaviors,
|
|
1195
|
+
firstProgressIndex: parallelProgressPrecreated ? -1 : firstProgressIndex,
|
|
1112
1196
|
controlConfig,
|
|
1113
1197
|
onControlEvent,
|
|
1114
1198
|
childIntercomTarget: childIntercomTarget ? (agent, index) => childIntercomTarget(runId, agent, index) : undefined,
|
|
@@ -1345,7 +1429,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
1345
1429
|
cwd: effectiveCwd,
|
|
1346
1430
|
signal,
|
|
1347
1431
|
interruptSignal: interruptController.signal,
|
|
1348
|
-
allowIntercomDetach: agentConfig.systemPrompt?.includes(
|
|
1432
|
+
allowIntercomDetach: agentConfig.systemPrompt?.includes(INTERCOM_BRIDGE_MARKER) === true,
|
|
1349
1433
|
intercomEvents: deps.pi.events,
|
|
1350
1434
|
runId,
|
|
1351
1435
|
sessionDir: sessionDirForIndex(0),
|
package/subagent-runner.ts
CHANGED
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
formatWorktreeTaskCwdConflict,
|
|
52
52
|
type WorktreeSetup,
|
|
53
53
|
} from "./worktree.ts";
|
|
54
|
+
import { writeInitialProgressFile } from "./settings.ts";
|
|
54
55
|
|
|
55
56
|
interface SubagentRunConfig {
|
|
56
57
|
id: string;
|
|
@@ -817,6 +818,12 @@ function appendParallelWorktreeSummary(
|
|
|
817
818
|
return `${previousOutput}\n\n${diffSummary}`;
|
|
818
819
|
}
|
|
819
820
|
|
|
821
|
+
function ensureParallelProgressFile(cwd: string, group: Extract<RunnerStep, { parallel: SubagentStep[] }>): void {
|
|
822
|
+
const progressPath = path.join(cwd, "progress.md");
|
|
823
|
+
if (!group.parallel.some((task) => task.task.includes(`Update progress at: ${progressPath}`))) return;
|
|
824
|
+
writeInitialProgressFile(cwd);
|
|
825
|
+
}
|
|
826
|
+
|
|
820
827
|
async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
821
828
|
const { id, steps, resultPath, cwd, placeholder, taskIndex, totalTasks, maxOutput, artifactsDir, artifactConfig } =
|
|
822
829
|
config;
|
|
@@ -1039,6 +1046,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1039
1046
|
}
|
|
1040
1047
|
|
|
1041
1048
|
try {
|
|
1049
|
+
if (group.worktree) ensureParallelProgressFile(cwd, group);
|
|
1042
1050
|
const groupStartTime = Date.now();
|
|
1043
1051
|
markParallelGroupRunning({
|
|
1044
1052
|
statusPayload,
|