pi-subagents 0.24.4 → 0.27.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 +29 -0
- package/README.md +145 -27
- package/package.json +1 -1
- package/prompts/parallel-context-build.md +3 -1
- package/prompts/parallel-handoff-plan.md +3 -1
- package/prompts/review-loop.md +1 -1
- package/skills/pi-subagents/SKILL.md +71 -20
- package/src/agents/agent-management.ts +57 -15
- package/src/agents/agent-serializer.ts +3 -2
- package/src/agents/agents.ts +47 -16
- package/src/agents/chain-serializer.ts +120 -0
- package/src/extension/fanout-child.ts +171 -0
- package/src/extension/index.ts +7 -2
- package/src/extension/schemas.ts +138 -5
- package/src/intercom/result-intercom.ts +108 -0
- package/src/runs/background/async-execution.ts +185 -10
- package/src/runs/background/async-job-tracker.ts +41 -6
- package/src/runs/background/async-resume.ts +28 -15
- package/src/runs/background/async-status.ts +71 -31
- package/src/runs/background/result-watcher.ts +111 -54
- package/src/runs/background/run-id-resolver.ts +83 -0
- package/src/runs/background/run-status.ts +89 -4
- package/src/runs/background/stale-run-reconciler.ts +46 -1
- package/src/runs/background/subagent-runner.ts +648 -42
- package/src/runs/foreground/chain-execution.ts +331 -118
- package/src/runs/foreground/execution.ts +226 -10
- package/src/runs/foreground/subagent-executor.ts +377 -14
- package/src/runs/shared/acceptance-contract.ts +291 -0
- package/src/runs/shared/acceptance-evaluation.ts +221 -0
- package/src/runs/shared/acceptance-finalization.ts +161 -0
- package/src/runs/shared/acceptance-reports.ts +127 -0
- package/src/runs/shared/acceptance.ts +22 -0
- package/src/runs/shared/chain-outputs.ts +101 -0
- package/src/runs/shared/completion-guard.ts +26 -3
- package/src/runs/shared/dynamic-fanout.ts +293 -0
- package/src/runs/shared/nested-events.ts +819 -0
- package/src/runs/shared/nested-path.ts +52 -0
- package/src/runs/shared/nested-render.ts +115 -0
- package/src/runs/shared/parallel-utils.ts +31 -1
- package/src/runs/shared/pi-args.ts +73 -5
- package/src/runs/shared/structured-output.ts +77 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +77 -7
- package/src/runs/shared/workflow-graph.ts +206 -0
- package/src/shared/formatters.ts +2 -2
- package/src/shared/settings.ts +53 -4
- package/src/shared/types.ts +345 -0
- package/src/slash/slash-commands.ts +41 -3
- package/src/tui/render.ts +268 -43
|
@@ -20,9 +20,11 @@ import {
|
|
|
20
20
|
createParallelDirs,
|
|
21
21
|
suppressProgressForReadOnlyTask,
|
|
22
22
|
aggregateParallelOutputs,
|
|
23
|
+
isDynamicParallelStep,
|
|
23
24
|
isParallelStep,
|
|
24
25
|
type StepOverrides,
|
|
25
26
|
type ChainStep,
|
|
27
|
+
type ParallelStep,
|
|
26
28
|
type SequentialStep,
|
|
27
29
|
type ParallelTaskResult,
|
|
28
30
|
type ResolvedStepBehavior,
|
|
@@ -51,6 +53,7 @@ import {
|
|
|
51
53
|
type ControlEvent,
|
|
52
54
|
type Details,
|
|
53
55
|
type IntercomEventBus,
|
|
56
|
+
type NestedRouteInfo,
|
|
54
57
|
type ResolvedControlConfig,
|
|
55
58
|
type SingleResult,
|
|
56
59
|
MAX_CONCURRENCY,
|
|
@@ -58,6 +61,11 @@ import {
|
|
|
58
61
|
} from "../../shared/types.ts";
|
|
59
62
|
import { resolveModelCandidate } from "../shared/model-fallback.ts";
|
|
60
63
|
import { validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
64
|
+
import { buildWorkflowGraphSnapshot } from "../shared/workflow-graph.ts";
|
|
65
|
+
import { ChainOutputValidationError, outputEntryFromResult, resolveOutputReferences, validateChainOutputBindings } from "../shared/chain-outputs.ts";
|
|
66
|
+
import { createStructuredOutputRuntime } from "../shared/structured-output.ts";
|
|
67
|
+
import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection, type DynamicCollectedResult } from "../shared/dynamic-fanout.ts";
|
|
68
|
+
import type { ChainOutputMap } from "../../shared/types.ts";
|
|
61
69
|
|
|
62
70
|
interface ChainExecutionDetailsInput {
|
|
63
71
|
results: SingleResult[];
|
|
@@ -66,12 +74,18 @@ interface ChainExecutionDetailsInput {
|
|
|
66
74
|
allArtifactPaths: ArtifactPaths[];
|
|
67
75
|
artifactsDir: string;
|
|
68
76
|
chainAgents: string[];
|
|
77
|
+
chainSteps: ChainStep[];
|
|
69
78
|
totalSteps: number;
|
|
70
79
|
currentStepIndex?: number;
|
|
80
|
+
runId: string;
|
|
81
|
+
outputs?: ChainOutputMap;
|
|
82
|
+
currentFlatIndex?: number;
|
|
83
|
+
dynamicChildren?: Record<number, Array<{ agent: string; label?: string; flatIndex: number; itemKey: string; outputName?: string; structured?: boolean; error?: string }>>;
|
|
84
|
+
dynamicGroupStatuses?: Record<number, { status: "pending" | "running" | "completed" | "failed" | "paused" | "detached"; error?: string; acceptance?: SingleResult["acceptance"] }>;
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
interface ParallelChainRunInput {
|
|
74
|
-
step:
|
|
88
|
+
step: ParallelStep;
|
|
75
89
|
parallelTemplates: string[];
|
|
76
90
|
parallelBehaviors: ResolvedStepBehavior[];
|
|
77
91
|
agents: AgentConfig[];
|
|
@@ -104,14 +118,23 @@ interface ParallelChainRunInput {
|
|
|
104
118
|
lastActivityAt?: number;
|
|
105
119
|
currentTool?: string;
|
|
106
120
|
currentToolStartedAt?: number;
|
|
121
|
+
currentPath?: string;
|
|
122
|
+
turnCount?: number;
|
|
123
|
+
tokens?: number;
|
|
124
|
+
toolCount?: number;
|
|
107
125
|
interrupt?: () => boolean;
|
|
108
126
|
};
|
|
109
127
|
results: SingleResult[];
|
|
110
128
|
allProgress: AgentProgress[];
|
|
129
|
+
outputs: ChainOutputMap;
|
|
111
130
|
chainAgents: string[];
|
|
131
|
+
chainSteps: ChainStep[];
|
|
112
132
|
totalSteps: number;
|
|
133
|
+
dynamicChildren?: ChainExecutionDetailsInput["dynamicChildren"];
|
|
134
|
+
dynamicGroupStatuses?: ChainExecutionDetailsInput["dynamicGroupStatuses"];
|
|
113
135
|
worktreeSetup?: WorktreeSetup;
|
|
114
136
|
maxSubagentDepth: number;
|
|
137
|
+
nestedRoute?: NestedRouteInfo;
|
|
115
138
|
}
|
|
116
139
|
|
|
117
140
|
function buildChainExecutionDetails(input: ChainExecutionDetailsInput): Details {
|
|
@@ -123,6 +146,17 @@ function buildChainExecutionDetails(input: ChainExecutionDetailsInput): Details
|
|
|
123
146
|
chainAgents: input.chainAgents,
|
|
124
147
|
totalSteps: input.totalSteps,
|
|
125
148
|
currentStepIndex: input.currentStepIndex,
|
|
149
|
+
outputs: input.outputs,
|
|
150
|
+
workflowGraph: buildWorkflowGraphSnapshot({
|
|
151
|
+
runId: input.runId,
|
|
152
|
+
mode: "chain",
|
|
153
|
+
steps: input.chainSteps,
|
|
154
|
+
results: input.results,
|
|
155
|
+
currentStepIndex: input.currentStepIndex,
|
|
156
|
+
currentFlatIndex: input.currentFlatIndex,
|
|
157
|
+
dynamicChildren: input.dynamicChildren,
|
|
158
|
+
dynamicGroupStatuses: input.dynamicGroupStatuses,
|
|
159
|
+
}),
|
|
126
160
|
});
|
|
127
161
|
}
|
|
128
162
|
|
|
@@ -189,7 +223,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
189
223
|
templateHasPrevious ? undefined : input.prev,
|
|
190
224
|
);
|
|
191
225
|
|
|
192
|
-
let taskStr = taskTemplate;
|
|
226
|
+
let taskStr = resolveOutputReferences(taskTemplate, input.outputs);
|
|
193
227
|
taskStr = taskStr.replace(/\{task\}/g, input.originalTask);
|
|
194
228
|
taskStr = taskStr.replace(/\{previous\}/g, input.prev);
|
|
195
229
|
taskStr = taskStr.replace(/\{chain_dir\}/g, input.chainDir);
|
|
@@ -224,6 +258,9 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
224
258
|
};
|
|
225
259
|
}
|
|
226
260
|
|
|
261
|
+
const structuredRuntime = task.outputSchema
|
|
262
|
+
? createStructuredOutputRuntime(task.outputSchema, path.join(input.chainDir, "structured-output"))
|
|
263
|
+
: undefined;
|
|
227
264
|
const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskStr, {
|
|
228
265
|
cwd: taskCwd,
|
|
229
266
|
signal: input.signal,
|
|
@@ -244,10 +281,14 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
244
281
|
onControlEvent: input.onControlEvent,
|
|
245
282
|
intercomSessionName: input.childIntercomTarget?.(task.agent, input.globalTaskIndex + taskIndex),
|
|
246
283
|
orchestratorIntercomTarget: input.orchestratorIntercomTarget,
|
|
284
|
+
nestedRoute: input.nestedRoute,
|
|
247
285
|
modelOverride: effectiveModel,
|
|
248
286
|
availableModels: input.availableModels,
|
|
249
287
|
preferredModelProvider: input.ctx.model?.provider,
|
|
250
288
|
skills: behavior.skills === false ? [] : behavior.skills,
|
|
289
|
+
structuredOutput: structuredRuntime,
|
|
290
|
+
acceptance: task.acceptance,
|
|
291
|
+
acceptanceContext: { mode: "chain" },
|
|
251
292
|
onUpdate: input.onUpdate
|
|
252
293
|
? (progressUpdate) => {
|
|
253
294
|
const stepResults = progressUpdate.details?.results || [];
|
|
@@ -276,6 +317,17 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
276
317
|
chainAgents: input.chainAgents,
|
|
277
318
|
totalSteps: input.totalSteps,
|
|
278
319
|
currentStepIndex: input.stepIndex,
|
|
320
|
+
outputs: input.outputs,
|
|
321
|
+
workflowGraph: buildWorkflowGraphSnapshot({
|
|
322
|
+
runId: input.runId,
|
|
323
|
+
mode: "chain",
|
|
324
|
+
steps: input.chainSteps,
|
|
325
|
+
results: input.results.concat(stepResults),
|
|
326
|
+
currentStepIndex: input.stepIndex,
|
|
327
|
+
currentFlatIndex: input.globalTaskIndex + taskIndex,
|
|
328
|
+
dynamicChildren: input.dynamicChildren,
|
|
329
|
+
dynamicGroupStatuses: input.dynamicGroupStatuses,
|
|
330
|
+
}),
|
|
279
331
|
},
|
|
280
332
|
});
|
|
281
333
|
}
|
|
@@ -326,11 +378,17 @@ interface ChainExecutionParams {
|
|
|
326
378
|
lastActivityAt?: number;
|
|
327
379
|
currentTool?: string;
|
|
328
380
|
currentToolStartedAt?: number;
|
|
381
|
+
currentPath?: string;
|
|
382
|
+
turnCount?: number;
|
|
383
|
+
tokens?: number;
|
|
384
|
+
toolCount?: number;
|
|
329
385
|
interrupt?: () => boolean;
|
|
330
386
|
};
|
|
331
387
|
chainSkills?: string[];
|
|
332
388
|
chainDir?: string;
|
|
389
|
+
dynamicFanoutMaxItems?: number;
|
|
333
390
|
maxSubagentDepth: number;
|
|
391
|
+
nestedRoute?: NestedRouteInfo;
|
|
334
392
|
worktreeSetupHook?: string;
|
|
335
393
|
worktreeSetupHookTimeoutMs?: number;
|
|
336
394
|
}
|
|
@@ -376,22 +434,60 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
376
434
|
} = params;
|
|
377
435
|
const chainSkills = chainSkillsParam ?? [];
|
|
378
436
|
|
|
437
|
+
const results: SingleResult[] = [];
|
|
438
|
+
const outputs: ChainOutputMap = {};
|
|
439
|
+
const dynamicChildren: ChainExecutionDetailsInput["dynamicChildren"] = {};
|
|
440
|
+
const dynamicGroupStatuses: ChainExecutionDetailsInput["dynamicGroupStatuses"] = {};
|
|
379
441
|
const allProgress: AgentProgress[] = [];
|
|
380
442
|
const allArtifactPaths: ArtifactPaths[] = [];
|
|
381
443
|
|
|
382
444
|
const chainAgents: string[] = chainSteps.map((step) =>
|
|
383
445
|
isParallelStep(step)
|
|
384
446
|
? `[${step.parallel.map((t) => t.agent).join("+")}]`
|
|
447
|
+
: isDynamicParallelStep(step)
|
|
448
|
+
? `expand:${step.parallel.agent}`
|
|
385
449
|
: (step as SequentialStep).agent,
|
|
386
450
|
);
|
|
387
451
|
const totalSteps = chainSteps.length;
|
|
388
452
|
|
|
453
|
+
const makeDetailsInput = (overrides: Pick<Partial<ChainExecutionDetailsInput>, "currentStepIndex" | "currentFlatIndex"> = {}): ChainExecutionDetailsInput => ({
|
|
454
|
+
results,
|
|
455
|
+
...(includeProgress !== undefined ? { includeProgress } : {}),
|
|
456
|
+
allProgress,
|
|
457
|
+
allArtifactPaths,
|
|
458
|
+
artifactsDir,
|
|
459
|
+
chainAgents,
|
|
460
|
+
chainSteps,
|
|
461
|
+
totalSteps,
|
|
462
|
+
runId,
|
|
463
|
+
outputs,
|
|
464
|
+
dynamicChildren,
|
|
465
|
+
dynamicGroupStatuses,
|
|
466
|
+
...overrides,
|
|
467
|
+
});
|
|
468
|
+
|
|
389
469
|
const firstStep = chainSteps[0]!;
|
|
390
470
|
const originalTask = params.task
|
|
391
|
-
?? (isParallelStep(firstStep)
|
|
471
|
+
?? (isParallelStep(firstStep)
|
|
472
|
+
? firstStep.parallel[0]!.task!
|
|
473
|
+
: isDynamicParallelStep(firstStep)
|
|
474
|
+
? firstStep.parallel.task!
|
|
475
|
+
: (firstStep as SequentialStep).task!);
|
|
476
|
+
try {
|
|
477
|
+
validateChainOutputBindings(chainSteps, { maxItems: params.dynamicFanoutMaxItems });
|
|
478
|
+
} catch (error) {
|
|
479
|
+
if (error instanceof ChainOutputValidationError) {
|
|
480
|
+
return {
|
|
481
|
+
content: [{ type: "text", text: error.message }],
|
|
482
|
+
isError: true,
|
|
483
|
+
details: buildChainExecutionDetails(makeDetailsInput()),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
throw error;
|
|
487
|
+
}
|
|
392
488
|
|
|
393
489
|
const chainDir = createChainDir(runId, chainDirBase);
|
|
394
|
-
const hasParallelSteps = chainSteps.some(isParallelStep);
|
|
490
|
+
const hasParallelSteps = chainSteps.some((step) => isParallelStep(step) || isDynamicParallelStep(step));
|
|
395
491
|
let templates: ResolvedTemplates = resolveChainTemplates(chainSteps);
|
|
396
492
|
const shouldClarify = clarify !== false && ctx.hasUI && !hasParallelSteps;
|
|
397
493
|
let tuiBehaviorOverrides: (BehaviorOverride | undefined)[] | undefined;
|
|
@@ -408,7 +504,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
408
504
|
return {
|
|
409
505
|
content: [{ type: "text", text: `Unknown agent: ${step.agent}` }],
|
|
410
506
|
isError: true,
|
|
411
|
-
details: {
|
|
507
|
+
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: seqSteps.indexOf(step) })),
|
|
412
508
|
};
|
|
413
509
|
}
|
|
414
510
|
agentConfigs.push(config);
|
|
@@ -453,7 +549,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
453
549
|
removeChainDir(chainDir);
|
|
454
550
|
return {
|
|
455
551
|
content: [{ type: "text", text: "Chain cancelled" }],
|
|
456
|
-
details:
|
|
552
|
+
details: buildChainExecutionDetails(makeDetailsInput()),
|
|
457
553
|
};
|
|
458
554
|
}
|
|
459
555
|
|
|
@@ -475,7 +571,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
475
571
|
});
|
|
476
572
|
return {
|
|
477
573
|
content: [{ type: "text", text: "Launching in background..." }],
|
|
478
|
-
details:
|
|
574
|
+
details: buildChainExecutionDetails(makeDetailsInput()),
|
|
479
575
|
requestedAsync: { chain: updatedChain, chainSkills },
|
|
480
576
|
};
|
|
481
577
|
}
|
|
@@ -484,7 +580,6 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
484
580
|
tuiBehaviorOverrides = result.behaviorOverrides;
|
|
485
581
|
}
|
|
486
582
|
|
|
487
|
-
const results: SingleResult[] = [];
|
|
488
583
|
let prev = "";
|
|
489
584
|
let globalTaskIndex = 0;
|
|
490
585
|
let progressCreated = false;
|
|
@@ -502,16 +597,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
502
597
|
if (worktreeTaskCwdConflict) {
|
|
503
598
|
return buildChainExecutionErrorResult(
|
|
504
599
|
`parallel chain step ${stepIndex + 1}: ${formatWorktreeTaskCwdConflict(worktreeTaskCwdConflict, parallelCwd)}`,
|
|
505
|
-
{
|
|
506
|
-
results,
|
|
507
|
-
includeProgress,
|
|
508
|
-
allProgress,
|
|
509
|
-
allArtifactPaths,
|
|
510
|
-
artifactsDir,
|
|
511
|
-
chainAgents,
|
|
512
|
-
totalSteps,
|
|
513
|
-
currentStepIndex: stepIndex,
|
|
514
|
-
},
|
|
600
|
+
makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }),
|
|
515
601
|
);
|
|
516
602
|
}
|
|
517
603
|
try {
|
|
@@ -523,16 +609,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
523
609
|
});
|
|
524
610
|
} catch (error) {
|
|
525
611
|
const message = error instanceof Error ? error.message : String(error);
|
|
526
|
-
return buildChainExecutionErrorResult(message, {
|
|
527
|
-
results,
|
|
528
|
-
includeProgress,
|
|
529
|
-
allProgress,
|
|
530
|
-
allArtifactPaths,
|
|
531
|
-
artifactsDir,
|
|
532
|
-
chainAgents,
|
|
533
|
-
totalSteps,
|
|
534
|
-
currentStepIndex: stepIndex,
|
|
535
|
-
});
|
|
612
|
+
return buildChainExecutionErrorResult(message, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
536
613
|
}
|
|
537
614
|
}
|
|
538
615
|
|
|
@@ -546,16 +623,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
546
623
|
? (path.isAbsolute(behavior.output) ? behavior.output : path.join(chainDir, behavior.output))
|
|
547
624
|
: undefined;
|
|
548
625
|
const validationError = validateFileOnlyOutputMode(behavior.outputMode, outputPath, `Parallel chain step ${stepIndex + 1} task ${taskIndex + 1} (${step.parallel[taskIndex]!.agent})`);
|
|
549
|
-
if (validationError) return buildChainExecutionErrorResult(validationError, {
|
|
550
|
-
results,
|
|
551
|
-
includeProgress,
|
|
552
|
-
allProgress,
|
|
553
|
-
allArtifactPaths,
|
|
554
|
-
artifactsDir,
|
|
555
|
-
chainAgents,
|
|
556
|
-
totalSteps,
|
|
557
|
-
currentStepIndex: stepIndex,
|
|
558
|
-
});
|
|
626
|
+
if (validationError) return buildChainExecutionErrorResult(validationError, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex + taskIndex }));
|
|
559
627
|
}
|
|
560
628
|
progressCreated = ensureParallelProgressFile(chainDir, progressCreated, parallelBehaviors);
|
|
561
629
|
createParallelDirs(chainDir, stepIndex, step.parallel.length, agentNames);
|
|
@@ -584,13 +652,18 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
584
652
|
onUpdate,
|
|
585
653
|
results,
|
|
586
654
|
allProgress,
|
|
655
|
+
outputs,
|
|
587
656
|
chainAgents,
|
|
657
|
+
chainSteps,
|
|
588
658
|
totalSteps,
|
|
659
|
+
dynamicChildren,
|
|
660
|
+
dynamicGroupStatuses,
|
|
589
661
|
controlConfig,
|
|
590
662
|
onControlEvent,
|
|
591
663
|
childIntercomTarget,
|
|
592
664
|
orchestratorIntercomTarget,
|
|
593
665
|
foregroundControl,
|
|
666
|
+
nestedRoute: params.nestedRoute,
|
|
594
667
|
worktreeSetup,
|
|
595
668
|
maxSubagentDepth: params.maxSubagentDepth,
|
|
596
669
|
});
|
|
@@ -601,21 +674,15 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
601
674
|
if (result.progress) allProgress.push(result.progress);
|
|
602
675
|
if (result.artifactPaths) allArtifactPaths.push(result.artifactPaths);
|
|
603
676
|
}
|
|
604
|
-
|
|
605
|
-
const interrupted = parallelResults
|
|
677
|
+
const interruptedIndexInStep = parallelResults.findIndex((result) => result.interrupted);
|
|
678
|
+
const interrupted = interruptedIndexInStep >= 0 ? parallelResults[interruptedIndexInStep] : undefined;
|
|
606
679
|
if (interrupted) {
|
|
607
680
|
return {
|
|
608
681
|
content: [{ type: "text", text: `Chain paused after interrupt at step ${stepIndex + 1} (${interrupted.agent}). Waiting for explicit next action.` }],
|
|
609
|
-
details: buildChainExecutionDetails({
|
|
610
|
-
results,
|
|
611
|
-
includeProgress,
|
|
612
|
-
allProgress,
|
|
613
|
-
allArtifactPaths,
|
|
614
|
-
artifactsDir,
|
|
615
|
-
chainAgents,
|
|
616
|
-
totalSteps,
|
|
682
|
+
details: buildChainExecutionDetails(makeDetailsInput({
|
|
617
683
|
currentStepIndex: stepIndex,
|
|
618
|
-
|
|
684
|
+
currentFlatIndex: globalTaskIndex - step.parallel.length + interruptedIndexInStep,
|
|
685
|
+
})),
|
|
619
686
|
};
|
|
620
687
|
}
|
|
621
688
|
const detachedIndexInStep = parallelResults.findIndex((result) => result.detached);
|
|
@@ -623,16 +690,10 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
623
690
|
if (detached) {
|
|
624
691
|
return {
|
|
625
692
|
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${detached.agent}). Reply to the supervisor request first. After the child exits, start a fresh follow-up if needed.` }],
|
|
626
|
-
details: buildChainExecutionDetails({
|
|
627
|
-
results,
|
|
628
|
-
includeProgress,
|
|
629
|
-
allProgress,
|
|
630
|
-
allArtifactPaths,
|
|
631
|
-
artifactsDir,
|
|
632
|
-
chainAgents,
|
|
633
|
-
totalSteps,
|
|
693
|
+
details: buildChainExecutionDetails(makeDetailsInput({
|
|
634
694
|
currentStepIndex: stepIndex,
|
|
635
|
-
|
|
695
|
+
currentFlatIndex: globalTaskIndex - step.parallel.length + detachedIndexInStep,
|
|
696
|
+
})),
|
|
636
697
|
};
|
|
637
698
|
}
|
|
638
699
|
|
|
@@ -651,19 +712,18 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
651
712
|
return {
|
|
652
713
|
content: [{ type: "text", text: summary }],
|
|
653
714
|
isError: true,
|
|
654
|
-
details: buildChainExecutionDetails({
|
|
655
|
-
results,
|
|
656
|
-
includeProgress,
|
|
657
|
-
allProgress,
|
|
658
|
-
allArtifactPaths,
|
|
659
|
-
artifactsDir,
|
|
660
|
-
chainAgents,
|
|
661
|
-
totalSteps,
|
|
715
|
+
details: buildChainExecutionDetails(makeDetailsInput({
|
|
662
716
|
currentStepIndex: stepIndex,
|
|
663
|
-
|
|
717
|
+
currentFlatIndex: globalTaskIndex - step.parallel.length + failures[0]!.originalIndex,
|
|
718
|
+
})),
|
|
664
719
|
};
|
|
665
720
|
}
|
|
666
721
|
|
|
722
|
+
for (let taskIndex = 0; taskIndex < parallelResults.length; taskIndex++) {
|
|
723
|
+
const outputName = step.parallel[taskIndex]?.as;
|
|
724
|
+
if (outputName) outputs[outputName] = outputEntryFromResult(parallelResults[taskIndex]!, stepIndex);
|
|
725
|
+
}
|
|
726
|
+
|
|
667
727
|
const taskResults: ParallelTaskResult[] = parallelResults.map((result, i) => {
|
|
668
728
|
const outputTarget = parallelBehaviors[i]?.output;
|
|
669
729
|
const outputTargetPath = typeof outputTarget === "string"
|
|
@@ -689,6 +749,184 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
689
749
|
} finally {
|
|
690
750
|
if (worktreeSetup) cleanupWorktrees(worktreeSetup);
|
|
691
751
|
}
|
|
752
|
+
} else if (isDynamicParallelStep(step)) {
|
|
753
|
+
if (Object.hasOwn(step, "acceptance")) {
|
|
754
|
+
const message = `Dynamic fanout step ${stepIndex + 1} does not support group-level acceptance; set acceptance on the child template instead.`;
|
|
755
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: message };
|
|
756
|
+
return buildChainExecutionErrorResult(message, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
757
|
+
}
|
|
758
|
+
let materialized: ReturnType<typeof materializeDynamicParallelStep>;
|
|
759
|
+
try {
|
|
760
|
+
materialized = materializeDynamicParallelStep(step, outputs, stepIndex, { maxItems: params.dynamicFanoutMaxItems });
|
|
761
|
+
} catch (error) {
|
|
762
|
+
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
763
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: message };
|
|
764
|
+
return buildChainExecutionErrorResult(message, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
dynamicChildren[stepIndex] = materialized.items.map((item, itemIndex) => ({
|
|
768
|
+
agent: step.parallel.agent,
|
|
769
|
+
label: materialized.parallel[itemIndex]?.label,
|
|
770
|
+
flatIndex: globalTaskIndex + itemIndex,
|
|
771
|
+
itemKey: item.key,
|
|
772
|
+
structured: Boolean(step.parallel.outputSchema),
|
|
773
|
+
}));
|
|
774
|
+
|
|
775
|
+
if (materialized.parallel.length === 0) {
|
|
776
|
+
const collection: DynamicCollectedResult[] = [];
|
|
777
|
+
try {
|
|
778
|
+
validateDynamicCollection(step.collect.outputSchema, collection);
|
|
779
|
+
} catch (error) {
|
|
780
|
+
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
781
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: message };
|
|
782
|
+
return buildChainExecutionErrorResult(message, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
783
|
+
}
|
|
784
|
+
outputs[step.collect.as] = {
|
|
785
|
+
text: JSON.stringify(collection),
|
|
786
|
+
structured: collection,
|
|
787
|
+
agent: step.parallel.agent,
|
|
788
|
+
stepIndex,
|
|
789
|
+
};
|
|
790
|
+
dynamicGroupStatuses[stepIndex] = { status: "completed" };
|
|
791
|
+
prev = "Dynamic fanout produced 0 results.";
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const dynamicParallelStep: ParallelStep = {
|
|
796
|
+
parallel: materialized.parallel,
|
|
797
|
+
concurrency: step.concurrency,
|
|
798
|
+
failFast: step.failFast,
|
|
799
|
+
};
|
|
800
|
+
const parallelTemplates = materialized.parallel.map((task) => task.task ?? "{previous}");
|
|
801
|
+
const parallelBehaviors = resolveParallelBehaviors(dynamicParallelStep.parallel, agents, stepIndex, chainSkills)
|
|
802
|
+
.map((behavior, taskIndex) => suppressProgressForReadOnlyTask(behavior, parallelTemplates[taskIndex] ?? dynamicParallelStep.parallel[taskIndex]?.task, originalTask));
|
|
803
|
+
|
|
804
|
+
for (let taskIndex = 0; taskIndex < dynamicParallelStep.parallel.length; taskIndex++) {
|
|
805
|
+
const behavior = parallelBehaviors[taskIndex]!;
|
|
806
|
+
const outputPath = typeof behavior.output === "string"
|
|
807
|
+
? (path.isAbsolute(behavior.output) ? behavior.output : path.join(chainDir, behavior.output))
|
|
808
|
+
: undefined;
|
|
809
|
+
const validationError = validateFileOnlyOutputMode(behavior.outputMode, outputPath, `Dynamic chain step ${stepIndex + 1} item ${taskIndex + 1} (${dynamicParallelStep.parallel[taskIndex]!.agent})`);
|
|
810
|
+
if (validationError) {
|
|
811
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: validationError };
|
|
812
|
+
return buildChainExecutionErrorResult(validationError, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex + taskIndex }));
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
progressCreated = ensureParallelProgressFile(chainDir, progressCreated, parallelBehaviors);
|
|
817
|
+
createParallelDirs(chainDir, stepIndex, dynamicParallelStep.parallel.length, dynamicParallelStep.parallel.map((task) => task.agent));
|
|
818
|
+
const parallelResults = await runParallelChainTasks({
|
|
819
|
+
step: dynamicParallelStep,
|
|
820
|
+
parallelTemplates,
|
|
821
|
+
parallelBehaviors,
|
|
822
|
+
agents,
|
|
823
|
+
stepIndex,
|
|
824
|
+
availableModels,
|
|
825
|
+
chainDir,
|
|
826
|
+
prev,
|
|
827
|
+
originalTask,
|
|
828
|
+
ctx,
|
|
829
|
+
intercomEvents,
|
|
830
|
+
cwd,
|
|
831
|
+
runId,
|
|
832
|
+
globalTaskIndex,
|
|
833
|
+
sessionDirForIndex,
|
|
834
|
+
sessionFileForIndex,
|
|
835
|
+
shareEnabled,
|
|
836
|
+
artifactConfig,
|
|
837
|
+
artifactsDir,
|
|
838
|
+
signal,
|
|
839
|
+
onUpdate,
|
|
840
|
+
results,
|
|
841
|
+
allProgress,
|
|
842
|
+
outputs,
|
|
843
|
+
chainAgents,
|
|
844
|
+
chainSteps,
|
|
845
|
+
totalSteps,
|
|
846
|
+
dynamicChildren,
|
|
847
|
+
dynamicGroupStatuses,
|
|
848
|
+
controlConfig,
|
|
849
|
+
onControlEvent,
|
|
850
|
+
childIntercomTarget,
|
|
851
|
+
orchestratorIntercomTarget,
|
|
852
|
+
foregroundControl,
|
|
853
|
+
nestedRoute: params.nestedRoute,
|
|
854
|
+
maxSubagentDepth: params.maxSubagentDepth,
|
|
855
|
+
});
|
|
856
|
+
globalTaskIndex += dynamicParallelStep.parallel.length;
|
|
857
|
+
|
|
858
|
+
for (const result of parallelResults) {
|
|
859
|
+
results.push(result);
|
|
860
|
+
if (result.progress) allProgress.push(result.progress);
|
|
861
|
+
if (result.artifactPaths) allArtifactPaths.push(result.artifactPaths);
|
|
862
|
+
}
|
|
863
|
+
const collected = collectDynamicResults(step, materialized.items, parallelResults);
|
|
864
|
+
const interruptedIndexInStep = parallelResults.findIndex((result) => result.interrupted);
|
|
865
|
+
const interrupted = interruptedIndexInStep >= 0 ? parallelResults[interruptedIndexInStep] : undefined;
|
|
866
|
+
if (interrupted) {
|
|
867
|
+
return {
|
|
868
|
+
content: [{ type: "text", text: `Chain paused after interrupt at step ${stepIndex + 1} (${interrupted.agent}). Waiting for explicit next action.` }],
|
|
869
|
+
details: buildChainExecutionDetails(makeDetailsInput({
|
|
870
|
+
currentStepIndex: stepIndex,
|
|
871
|
+
currentFlatIndex: globalTaskIndex - dynamicParallelStep.parallel.length + interruptedIndexInStep,
|
|
872
|
+
})),
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
const detachedIndexInStep = parallelResults.findIndex((result) => result.detached);
|
|
876
|
+
const detached = detachedIndexInStep >= 0 ? parallelResults[detachedIndexInStep] : undefined;
|
|
877
|
+
if (detached) {
|
|
878
|
+
return {
|
|
879
|
+
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${detached.agent}). Reply to the supervisor request first. After the child exits, start a fresh follow-up if needed.` }],
|
|
880
|
+
details: buildChainExecutionDetails(makeDetailsInput({
|
|
881
|
+
currentStepIndex: stepIndex,
|
|
882
|
+
currentFlatIndex: globalTaskIndex - dynamicParallelStep.parallel.length + detachedIndexInStep,
|
|
883
|
+
})),
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
const failures = parallelResults
|
|
887
|
+
.map((result, originalIndex) => ({ ...result, originalIndex }))
|
|
888
|
+
.filter((result) => result.exitCode !== 0 && result.exitCode !== -1);
|
|
889
|
+
if (failures.length > 0) {
|
|
890
|
+
const failureSummary = failures
|
|
891
|
+
.map((failure) => `- Item ${failure.originalIndex + 1} (${failure.agent}, key ${materialized.items[failure.originalIndex]?.key ?? failure.originalIndex}): ${failure.error || "failed"}`)
|
|
892
|
+
.join("\n");
|
|
893
|
+
const errorMsg = `Dynamic step ${stepIndex + 1} failed:\n${failureSummary}`;
|
|
894
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: errorMsg };
|
|
895
|
+
const summary = buildChainSummary(chainSteps, results, chainDir, "failed", {
|
|
896
|
+
index: stepIndex,
|
|
897
|
+
error: errorMsg,
|
|
898
|
+
});
|
|
899
|
+
return {
|
|
900
|
+
content: [{ type: "text", text: summary }],
|
|
901
|
+
isError: true,
|
|
902
|
+
details: buildChainExecutionDetails(makeDetailsInput({
|
|
903
|
+
currentStepIndex: stepIndex,
|
|
904
|
+
currentFlatIndex: globalTaskIndex - dynamicParallelStep.parallel.length + failures[0]!.originalIndex,
|
|
905
|
+
})),
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
try {
|
|
909
|
+
validateDynamicCollection(step.collect.outputSchema, collected);
|
|
910
|
+
} catch (error) {
|
|
911
|
+
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
912
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: message };
|
|
913
|
+
return buildChainExecutionErrorResult(message, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex - dynamicParallelStep.parallel.length }));
|
|
914
|
+
}
|
|
915
|
+
outputs[step.collect.as] = {
|
|
916
|
+
text: JSON.stringify(collected),
|
|
917
|
+
structured: collected,
|
|
918
|
+
agent: step.parallel.agent,
|
|
919
|
+
stepIndex,
|
|
920
|
+
};
|
|
921
|
+
dynamicGroupStatuses[stepIndex] = { status: "completed" };
|
|
922
|
+
const taskResults: ParallelTaskResult[] = parallelResults.map((result, i) => ({
|
|
923
|
+
agent: result.agent,
|
|
924
|
+
taskIndex: i,
|
|
925
|
+
output: getSingleResultOutput(result),
|
|
926
|
+
exitCode: result.exitCode,
|
|
927
|
+
error: result.error,
|
|
928
|
+
}));
|
|
929
|
+
prev = aggregateParallelOutputs(taskResults, (i, agent) => `=== Dynamic Item ${i + 1} (${agent}, key ${materialized.items[i]?.key ?? i}) ===`);
|
|
692
930
|
} else {
|
|
693
931
|
const seqStep = step as SequentialStep;
|
|
694
932
|
const stepTemplate = stepTemplates as string;
|
|
@@ -699,7 +937,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
699
937
|
return {
|
|
700
938
|
content: [{ type: "text", text: `Unknown agent: ${seqStep.agent}` }],
|
|
701
939
|
isError: true,
|
|
702
|
-
details: {
|
|
940
|
+
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex })),
|
|
703
941
|
};
|
|
704
942
|
}
|
|
705
943
|
|
|
@@ -729,7 +967,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
729
967
|
templateHasPrevious ? undefined : prev,
|
|
730
968
|
);
|
|
731
969
|
|
|
732
|
-
let stepTask = stepTemplate;
|
|
970
|
+
let stepTask = resolveOutputReferences(stepTemplate, outputs);
|
|
733
971
|
stepTask = stepTask.replace(/\{task\}/g, originalTask);
|
|
734
972
|
stepTask = stepTask.replace(/\{previous\}/g, prev);
|
|
735
973
|
stepTask = stepTask.replace(/\{chain_dir\}/g, chainDir);
|
|
@@ -746,16 +984,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
746
984
|
: undefined;
|
|
747
985
|
const validationError = validateFileOnlyOutputMode(behavior.outputMode, outputPath, `Chain step ${stepIndex + 1} (${seqStep.agent})`);
|
|
748
986
|
if (validationError) {
|
|
749
|
-
return buildChainExecutionErrorResult(validationError, {
|
|
750
|
-
results,
|
|
751
|
-
includeProgress,
|
|
752
|
-
allProgress,
|
|
753
|
-
allArtifactPaths,
|
|
754
|
-
artifactsDir,
|
|
755
|
-
chainAgents,
|
|
756
|
-
totalSteps,
|
|
757
|
-
currentStepIndex: stepIndex,
|
|
758
|
-
});
|
|
987
|
+
return buildChainExecutionErrorResult(validationError, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
759
988
|
}
|
|
760
989
|
const maxSubagentDepth = resolveChildMaxSubagentDepth(params.maxSubagentDepth, agentConfig.maxSubagentDepth);
|
|
761
990
|
const interruptController = new AbortController();
|
|
@@ -773,6 +1002,9 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
773
1002
|
};
|
|
774
1003
|
}
|
|
775
1004
|
|
|
1005
|
+
const structuredRuntime = seqStep.outputSchema
|
|
1006
|
+
? createStructuredOutputRuntime(seqStep.outputSchema, path.join(chainDir, "structured-output"))
|
|
1007
|
+
: undefined;
|
|
776
1008
|
const r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
|
|
777
1009
|
cwd: resolveChildCwd(cwd ?? ctx.cwd, seqStep.cwd),
|
|
778
1010
|
signal,
|
|
@@ -793,10 +1025,14 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
793
1025
|
onControlEvent,
|
|
794
1026
|
intercomSessionName: childIntercomTarget?.(seqStep.agent, globalTaskIndex),
|
|
795
1027
|
orchestratorIntercomTarget,
|
|
1028
|
+
nestedRoute: params.nestedRoute,
|
|
796
1029
|
modelOverride: effectiveModel,
|
|
797
1030
|
availableModels,
|
|
798
1031
|
preferredModelProvider: ctx.model?.provider,
|
|
799
1032
|
skills: behavior.skills === false ? [] : behavior.skills,
|
|
1033
|
+
structuredOutput: structuredRuntime,
|
|
1034
|
+
acceptance: seqStep.acceptance,
|
|
1035
|
+
acceptanceContext: { mode: "chain" },
|
|
800
1036
|
onUpdate: onUpdate
|
|
801
1037
|
? (p) => {
|
|
802
1038
|
const stepResults = p.details?.results || [];
|
|
@@ -825,6 +1061,17 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
825
1061
|
chainAgents,
|
|
826
1062
|
totalSteps,
|
|
827
1063
|
currentStepIndex: stepIndex,
|
|
1064
|
+
outputs,
|
|
1065
|
+
workflowGraph: buildWorkflowGraphSnapshot({
|
|
1066
|
+
runId,
|
|
1067
|
+
mode: "chain",
|
|
1068
|
+
steps: chainSteps,
|
|
1069
|
+
results: results.concat(stepResults),
|
|
1070
|
+
currentStepIndex: stepIndex,
|
|
1071
|
+
currentFlatIndex: globalTaskIndex,
|
|
1072
|
+
dynamicChildren,
|
|
1073
|
+
dynamicGroupStatuses,
|
|
1074
|
+
}),
|
|
828
1075
|
},
|
|
829
1076
|
});
|
|
830
1077
|
}
|
|
@@ -844,31 +1091,13 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
844
1091
|
if (r.interrupted) {
|
|
845
1092
|
return {
|
|
846
1093
|
content: [{ type: "text", text: `Chain paused after interrupt at step ${stepIndex + 1} (${r.agent}). Waiting for explicit next action.` }],
|
|
847
|
-
details: buildChainExecutionDetails({
|
|
848
|
-
results,
|
|
849
|
-
includeProgress,
|
|
850
|
-
allProgress,
|
|
851
|
-
allArtifactPaths,
|
|
852
|
-
artifactsDir,
|
|
853
|
-
chainAgents,
|
|
854
|
-
totalSteps,
|
|
855
|
-
currentStepIndex: stepIndex,
|
|
856
|
-
}),
|
|
1094
|
+
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex - 1 })),
|
|
857
1095
|
};
|
|
858
1096
|
}
|
|
859
1097
|
if (r.detached) {
|
|
860
1098
|
return {
|
|
861
1099
|
content: [{ type: "text", text: `Chain detached for intercom coordination at step ${stepIndex + 1} (${r.agent}). Reply to the supervisor request first. After the child exits, start a fresh follow-up if needed.` }],
|
|
862
|
-
details: buildChainExecutionDetails({
|
|
863
|
-
results,
|
|
864
|
-
includeProgress,
|
|
865
|
-
allProgress,
|
|
866
|
-
allArtifactPaths,
|
|
867
|
-
artifactsDir,
|
|
868
|
-
chainAgents,
|
|
869
|
-
totalSteps,
|
|
870
|
-
currentStepIndex: stepIndex,
|
|
871
|
-
}),
|
|
1100
|
+
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex - 1 })),
|
|
872
1101
|
};
|
|
873
1102
|
}
|
|
874
1103
|
|
|
@@ -879,16 +1108,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
879
1108
|
});
|
|
880
1109
|
return {
|
|
881
1110
|
content: [{ type: "text", text: summary }],
|
|
882
|
-
details: buildChainExecutionDetails({
|
|
883
|
-
results,
|
|
884
|
-
includeProgress,
|
|
885
|
-
allProgress,
|
|
886
|
-
allArtifactPaths,
|
|
887
|
-
artifactsDir,
|
|
888
|
-
chainAgents,
|
|
889
|
-
totalSteps,
|
|
890
|
-
currentStepIndex: stepIndex,
|
|
891
|
-
}),
|
|
1111
|
+
details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex - 1 })),
|
|
892
1112
|
isError: true,
|
|
893
1113
|
};
|
|
894
1114
|
}
|
|
@@ -911,6 +1131,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
911
1131
|
}
|
|
912
1132
|
}
|
|
913
1133
|
|
|
1134
|
+
if (seqStep.as) outputs[seqStep.as] = outputEntryFromResult(r, stepIndex);
|
|
914
1135
|
prev = getSingleResultOutput(r);
|
|
915
1136
|
}
|
|
916
1137
|
}
|
|
@@ -919,14 +1140,6 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
919
1140
|
|
|
920
1141
|
return {
|
|
921
1142
|
content: [{ type: "text", text: summary }],
|
|
922
|
-
details: buildChainExecutionDetails(
|
|
923
|
-
results,
|
|
924
|
-
includeProgress,
|
|
925
|
-
allProgress,
|
|
926
|
-
allArtifactPaths,
|
|
927
|
-
artifactsDir,
|
|
928
|
-
chainAgents,
|
|
929
|
-
totalSteps,
|
|
930
|
-
}),
|
|
1143
|
+
details: buildChainExecutionDetails(makeDetailsInput()),
|
|
931
1144
|
};
|
|
932
1145
|
}
|