pi-subagents 0.28.0 → 0.30.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 +31 -0
- package/README.md +26 -62
- package/package.json +1 -1
- package/skills/pi-subagents/SKILL.md +29 -35
- package/src/agents/agent-management.ts +29 -22
- package/src/agents/agent-selection.ts +2 -0
- package/src/agents/agent-serializer.ts +5 -10
- package/src/agents/agents.ts +339 -47
- package/src/agents/chain-serializer.ts +4 -9
- package/src/agents/proactive-skills.ts +191 -0
- package/src/extension/doctor.ts +4 -3
- package/src/extension/fanout-child.ts +1 -3
- package/src/extension/index.ts +6 -9
- package/src/extension/schemas.ts +63 -26
- package/src/intercom/intercom-bridge.ts +11 -1
- package/src/intercom/result-intercom.ts +0 -5
- package/src/runs/background/async-execution.ts +186 -74
- package/src/runs/background/async-resume.ts +53 -5
- package/src/runs/background/async-status.ts +4 -1
- package/src/runs/background/chain-append.ts +282 -0
- package/src/runs/background/chain-root-attachment.ts +161 -0
- package/src/runs/background/run-status.ts +2 -7
- package/src/runs/background/subagent-runner.ts +160 -219
- package/src/runs/foreground/chain-execution.ts +62 -58
- package/src/runs/foreground/execution.ts +39 -343
- package/src/runs/foreground/subagent-executor.ts +316 -111
- package/src/runs/shared/acceptance.ts +605 -22
- package/src/runs/shared/chain-outputs.ts +23 -8
- package/src/runs/shared/completion-guard.ts +3 -26
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/model-fallback.ts +38 -0
- package/src/runs/shared/parallel-utils.ts +13 -10
- package/src/runs/shared/pi-args.ts +3 -2
- package/src/runs/shared/subagent-control.ts +8 -11
- package/src/runs/shared/subagent-prompt-runtime.ts +3 -2
- package/src/runs/shared/workflow-graph.ts +2 -6
- package/src/shared/atomic-json.ts +68 -11
- package/src/shared/settings.ts +1 -0
- package/src/shared/types.ts +20 -49
- package/src/shared/utils.ts +2 -8
- package/src/slash/slash-bridge.ts +3 -1
- package/src/slash/slash-commands.ts +1 -1
- package/src/tui/render.ts +14 -29
- package/src/runs/shared/acceptance-contract.ts +0 -318
- package/src/runs/shared/acceptance-evaluation.ts +0 -221
- package/src/runs/shared/acceptance-finalization.ts +0 -173
- package/src/runs/shared/acceptance-reports.ts +0 -127
|
@@ -8,8 +8,6 @@ import { appendJsonl, getArtifactPaths } from "../../shared/artifacts.ts";
|
|
|
8
8
|
import { PI_CODING_AGENT_PACKAGE, getPiSpawnCommand, resolveInstalledPiPackageRoot } from "../shared/pi-spawn.ts";
|
|
9
9
|
import { captureSingleOutputSnapshot, finalizeSingleOutput, formatSavedOutputReference, resolveSingleOutput, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
10
10
|
import {
|
|
11
|
-
type AcceptanceFinalizationTurn,
|
|
12
|
-
type AcceptanceLedger,
|
|
13
11
|
type ActivityState,
|
|
14
12
|
type ArtifactConfig,
|
|
15
13
|
type ArtifactPaths,
|
|
@@ -19,9 +17,7 @@ import {
|
|
|
19
17
|
type ModelAttempt,
|
|
20
18
|
type NestedRouteInfo,
|
|
21
19
|
type ResolvedControlConfig,
|
|
22
|
-
type ResourceLimitExceeded,
|
|
23
20
|
type SubagentRunMode,
|
|
24
|
-
type TokenUsage,
|
|
25
21
|
type Usage,
|
|
26
22
|
type WorkflowGraphSnapshot,
|
|
27
23
|
DEFAULT_MAX_OUTPUT,
|
|
@@ -54,8 +50,8 @@ import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelSt
|
|
|
54
50
|
import { nestedSummaryFromAsyncStatus, writeNestedEvent } from "../shared/nested-events.ts";
|
|
55
51
|
import { formatModelAttemptNote, isRetryableModelFailure } from "../shared/model-fallback.ts";
|
|
56
52
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
57
|
-
import { detectSubagentError, extractTextFromContent, extractToolArgsPreview,
|
|
58
|
-
import { evaluateCompletionMutationGuard
|
|
53
|
+
import { detectSubagentError, extractTextFromContent, extractToolArgsPreview, getFinalOutput } from "../../shared/utils.ts";
|
|
54
|
+
import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
|
|
59
55
|
import {
|
|
60
56
|
createMutatingFailureState,
|
|
61
57
|
didMutatingToolFail,
|
|
@@ -68,6 +64,7 @@ import {
|
|
|
68
64
|
summarizeRecentMutatingFailures,
|
|
69
65
|
} from "../shared/long-running-guard.ts";
|
|
70
66
|
import { parseSessionTokens } from "../../shared/session-tokens.ts";
|
|
67
|
+
import type { TokenUsage } from "../../shared/types.ts";
|
|
71
68
|
import {
|
|
72
69
|
cleanupWorktrees,
|
|
73
70
|
createWorktrees,
|
|
@@ -80,19 +77,9 @@ import {
|
|
|
80
77
|
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
81
78
|
import { writeInitialProgressFile } from "../../shared/settings.ts";
|
|
82
79
|
import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts";
|
|
83
|
-
import {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
attachFinalizationToLedger,
|
|
87
|
-
buildFinalizationProcessFailureLedger,
|
|
88
|
-
createFinalizationProcessFailureTurn,
|
|
89
|
-
createFinalizationTurn,
|
|
90
|
-
evaluateAcceptance,
|
|
91
|
-
formatAcceptanceFinalizationPrompt,
|
|
92
|
-
formatAcceptancePrompt,
|
|
93
|
-
shouldRunAcceptanceFinalization,
|
|
94
|
-
stripAcceptanceReport,
|
|
95
|
-
} from "../shared/acceptance.ts";
|
|
80
|
+
import { acceptanceFailureMessage, aggregateAcceptanceReport, evaluateAcceptance, formatAcceptancePrompt, stripAcceptanceReport } from "../shared/acceptance.ts";
|
|
81
|
+
import { waitForImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
82
|
+
import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests } from "./chain-append.ts";
|
|
96
83
|
|
|
97
84
|
interface SubagentRunConfig {
|
|
98
85
|
id: string;
|
|
@@ -140,8 +127,7 @@ interface StepResult {
|
|
|
140
127
|
structuredOutput?: unknown;
|
|
141
128
|
structuredOutputPath?: string;
|
|
142
129
|
structuredOutputSchemaPath?: string;
|
|
143
|
-
acceptance?: AcceptanceLedger;
|
|
144
|
-
resourceLimitExceeded?: ResourceLimitExceeded;
|
|
130
|
+
acceptance?: import("../../shared/types.ts").AcceptanceLedger;
|
|
145
131
|
}
|
|
146
132
|
|
|
147
133
|
const ASYNC_INTERRUPT_SIGNAL: NodeJS.Signals = process.platform === "win32" ? "SIGBREAK" : "SIGUSR2";
|
|
@@ -236,7 +222,6 @@ interface RunPiStreamingResult {
|
|
|
236
222
|
finalOutput: string;
|
|
237
223
|
interrupted?: boolean;
|
|
238
224
|
observedMutationAttempt?: boolean;
|
|
239
|
-
resourceLimitExceeded?: ResourceLimitExceeded;
|
|
240
225
|
}
|
|
241
226
|
|
|
242
227
|
function runPiStreaming(
|
|
@@ -250,8 +235,6 @@ function runPiStreaming(
|
|
|
250
235
|
childEventContext?: ChildEventContext,
|
|
251
236
|
registerInterrupt?: (interrupt: (() => void) | undefined) => void,
|
|
252
237
|
onChildEvent?: (event: ChildEvent) => void,
|
|
253
|
-
maxExecutionTimeMs?: number,
|
|
254
|
-
maxTokens?: number,
|
|
255
238
|
): Promise<RunPiStreamingResult> {
|
|
256
239
|
return new Promise((resolve) => {
|
|
257
240
|
const outputStream = fs.createWriteStream(outputFile, { flags: "w" });
|
|
@@ -275,10 +258,7 @@ function runPiStreaming(
|
|
|
275
258
|
let error: string | undefined;
|
|
276
259
|
let assistantError: string | undefined;
|
|
277
260
|
let interrupted = false;
|
|
278
|
-
let resourceLimitExceeded: ResourceLimitExceeded | undefined;
|
|
279
261
|
let observedMutationAttempt = false;
|
|
280
|
-
let resourceLimitTimer: NodeJS.Timeout | undefined;
|
|
281
|
-
let resourceLimitEscalationTimer: NodeJS.Timeout | undefined;
|
|
282
262
|
const rawStdoutLines: string[] = [];
|
|
283
263
|
|
|
284
264
|
const writeOutputLine = (line: string) => {
|
|
@@ -292,19 +272,6 @@ function runPiStreaming(
|
|
|
292
272
|
}
|
|
293
273
|
};
|
|
294
274
|
|
|
295
|
-
const triggerResourceLimit = (kind: ResourceLimitExceeded["kind"], limit: number, observed?: number) => {
|
|
296
|
-
if (settled || resourceLimitExceeded) return;
|
|
297
|
-
const message = formatResourceLimitExceeded({ agent: childEventContext?.agent ?? "subagent", kind, limit, observed });
|
|
298
|
-
resourceLimitExceeded = { kind, limit, ...(observed !== undefined ? { observed } : {}), message };
|
|
299
|
-
error = message;
|
|
300
|
-
writeOutputLine(message);
|
|
301
|
-
trySignalChild(child, "SIGINT");
|
|
302
|
-
resourceLimitEscalationTimer = setTimeout(() => {
|
|
303
|
-
if (!settled) trySignalChild(child, "SIGTERM");
|
|
304
|
-
}, 1000);
|
|
305
|
-
resourceLimitEscalationTimer.unref?.();
|
|
306
|
-
};
|
|
307
|
-
|
|
308
275
|
const appendChildEvent = (event: Record<string, unknown>) => {
|
|
309
276
|
if (!childEventContext) return;
|
|
310
277
|
appendJsonl(childEventContext.eventsPath, JSON.stringify({
|
|
@@ -359,10 +326,6 @@ function runPiStreaming(
|
|
|
359
326
|
usage.cacheRead += eventUsage.cacheRead ?? 0;
|
|
360
327
|
usage.cacheWrite += eventUsage.cacheWrite ?? 0;
|
|
361
328
|
usage.cost += eventUsage.cost?.total ?? 0;
|
|
362
|
-
const observedTokens = usage.input + usage.output;
|
|
363
|
-
if (maxTokens !== undefined && observedTokens >= maxTokens) {
|
|
364
|
-
triggerResourceLimit("maxTokens", maxTokens, observedTokens);
|
|
365
|
-
}
|
|
366
329
|
}
|
|
367
330
|
const stopReason = (event.message as { stopReason?: string }).stopReason;
|
|
368
331
|
const hasToolCall = Array.isArray(event.message.content)
|
|
@@ -398,12 +361,6 @@ function runPiStreaming(
|
|
|
398
361
|
let finalDrainTimer: NodeJS.Timeout | undefined;
|
|
399
362
|
let finalHardKillTimer: NodeJS.Timeout | undefined;
|
|
400
363
|
let settled = false;
|
|
401
|
-
if (maxExecutionTimeMs !== undefined) {
|
|
402
|
-
resourceLimitTimer = setTimeout(() => {
|
|
403
|
-
triggerResourceLimit("maxExecutionTimeMs", maxExecutionTimeMs);
|
|
404
|
-
}, maxExecutionTimeMs);
|
|
405
|
-
resourceLimitTimer.unref?.();
|
|
406
|
-
}
|
|
407
364
|
const clearStdioGuard = attachPostExitStdioGuard(child, { idleMs: 2000, hardMs: 8000 });
|
|
408
365
|
child.stdout.on("data", (chunk: Buffer) => {
|
|
409
366
|
const text = chunk.toString();
|
|
@@ -417,7 +374,7 @@ function runPiStreaming(
|
|
|
417
374
|
processStderrText(chunk.toString());
|
|
418
375
|
});
|
|
419
376
|
registerInterrupt?.(() => {
|
|
420
|
-
if (settled
|
|
377
|
+
if (settled) return;
|
|
421
378
|
interrupted = true;
|
|
422
379
|
if (!error) error = "Interrupted. Waiting for explicit next action.";
|
|
423
380
|
trySignalChild(child, "SIGINT");
|
|
@@ -434,14 +391,6 @@ function runPiStreaming(
|
|
|
434
391
|
clearTimeout(finalHardKillTimer);
|
|
435
392
|
finalHardKillTimer = undefined;
|
|
436
393
|
}
|
|
437
|
-
if (resourceLimitTimer) {
|
|
438
|
-
clearTimeout(resourceLimitTimer);
|
|
439
|
-
resourceLimitTimer = undefined;
|
|
440
|
-
}
|
|
441
|
-
if (resourceLimitEscalationTimer) {
|
|
442
|
-
clearTimeout(resourceLimitEscalationTimer);
|
|
443
|
-
resourceLimitEscalationTimer = undefined;
|
|
444
|
-
}
|
|
445
394
|
};
|
|
446
395
|
function startFinalDrain(): void {
|
|
447
396
|
if (childExited || finalDrainTimer || settled) return;
|
|
@@ -473,12 +422,12 @@ function runPiStreaming(
|
|
|
473
422
|
if (stdoutBuf.trim()) processStdoutLine(stdoutBuf);
|
|
474
423
|
if (stderrBuf.trim()) appendChildLine("subagent.child.stderr", stderrBuf);
|
|
475
424
|
outputStream.end();
|
|
476
|
-
const finalOutput =
|
|
477
|
-
const finalError =
|
|
425
|
+
const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
|
|
426
|
+
const finalError = error ?? assistantError;
|
|
478
427
|
const forcedDrainAfterFinalSuccess = forcedTerminationSignal && cleanTerminalAssistantStopReceived && !finalError;
|
|
479
428
|
resolve({
|
|
480
429
|
stderr,
|
|
481
|
-
exitCode:
|
|
430
|
+
exitCode: interrupted || forcedDrainAfterFinalSuccess ? 0 : forcedTerminationSignal || signal ? (exitCode ?? 1) : exitCode,
|
|
482
431
|
messages,
|
|
483
432
|
usage,
|
|
484
433
|
model,
|
|
@@ -486,7 +435,6 @@ function runPiStreaming(
|
|
|
486
435
|
finalOutput,
|
|
487
436
|
interrupted,
|
|
488
437
|
observedMutationAttempt,
|
|
489
|
-
resourceLimitExceeded,
|
|
490
438
|
});
|
|
491
439
|
});
|
|
492
440
|
|
|
@@ -496,9 +444,9 @@ function runPiStreaming(
|
|
|
496
444
|
clearDrainTimers();
|
|
497
445
|
clearStdioGuard();
|
|
498
446
|
outputStream.end();
|
|
499
|
-
const finalOutput =
|
|
447
|
+
const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
|
|
500
448
|
const spawnErrorMessage = spawnError instanceof Error ? spawnError.message : String(spawnError);
|
|
501
|
-
resolve({ stderr, exitCode: 1, messages, usage, model, error:
|
|
449
|
+
resolve({ stderr, exitCode: 1, messages, usage, model, error: error ?? assistantError ?? spawnErrorMessage, finalOutput, observedMutationAttempt });
|
|
502
450
|
});
|
|
503
451
|
});
|
|
504
452
|
}
|
|
@@ -653,9 +601,32 @@ async function runSingleStep(
|
|
|
653
601
|
structuredOutput?: unknown;
|
|
654
602
|
structuredOutputPath?: string;
|
|
655
603
|
structuredOutputSchemaPath?: string;
|
|
656
|
-
acceptance?: AcceptanceLedger;
|
|
657
|
-
resourceLimitExceeded?: ResourceLimitExceeded;
|
|
604
|
+
acceptance?: import("../../shared/types.ts").AcceptanceLedger;
|
|
658
605
|
}> {
|
|
606
|
+
if (step.importAsyncRoot) {
|
|
607
|
+
const imported = await waitForImportedAsyncRoot(step.importAsyncRoot);
|
|
608
|
+
try {
|
|
609
|
+
fs.writeFileSync(ctx.outputFile, imported.output, "utf-8");
|
|
610
|
+
} catch {
|
|
611
|
+
// Output files are observability only for imported roots.
|
|
612
|
+
}
|
|
613
|
+
return {
|
|
614
|
+
agent: imported.agent,
|
|
615
|
+
output: imported.output,
|
|
616
|
+
exitCode: imported.exitCode,
|
|
617
|
+
error: imported.error,
|
|
618
|
+
sessionFile: imported.sessionFile,
|
|
619
|
+
intercomTarget: imported.intercomTarget,
|
|
620
|
+
model: imported.model,
|
|
621
|
+
attemptedModels: imported.attemptedModels,
|
|
622
|
+
modelAttempts: imported.modelAttempts,
|
|
623
|
+
structuredOutput: imported.structuredOutput,
|
|
624
|
+
structuredOutputPath: imported.structuredOutputPath,
|
|
625
|
+
structuredOutputSchemaPath: imported.structuredOutputSchemaPath,
|
|
626
|
+
acceptance: imported.acceptance,
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
|
|
659
630
|
const effectiveStructuredOutput = step.structuredOutput ?? (step.structuredOutputSchema
|
|
660
631
|
? createStructuredOutputRuntime(step.structuredOutputSchema, path.join(path.dirname(ctx.outputFile), "structured-output"))
|
|
661
632
|
: undefined);
|
|
@@ -715,6 +686,7 @@ async function runSingleStep(
|
|
|
715
686
|
inheritSkills: step.inheritSkills,
|
|
716
687
|
tools: step.tools,
|
|
717
688
|
extensions: step.extensions,
|
|
689
|
+
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
718
690
|
systemPrompt: step.systemPrompt,
|
|
719
691
|
systemPromptMode: step.systemPromptMode,
|
|
720
692
|
mcpDirectTools: step.mcpDirectTools,
|
|
@@ -742,8 +714,6 @@ async function runSingleStep(
|
|
|
742
714
|
{ eventsPath, runId: ctx.id, stepIndex: ctx.flatIndex, agent: step.agent },
|
|
743
715
|
ctx.registerInterrupt,
|
|
744
716
|
ctx.onChildEvent,
|
|
745
|
-
step.maxExecutionTimeMs,
|
|
746
|
-
step.maxTokens,
|
|
747
717
|
);
|
|
748
718
|
cleanupTempDir(tempDir);
|
|
749
719
|
|
|
@@ -759,15 +729,7 @@ async function runSingleStep(
|
|
|
759
729
|
if (structured.error) structuredError = structured.error;
|
|
760
730
|
else structuredOutput = structured.value;
|
|
761
731
|
}
|
|
762
|
-
const
|
|
763
|
-
agent: step.agent,
|
|
764
|
-
task: taskForCompletionGuard,
|
|
765
|
-
completionGuardEnabled: step.completionGuard !== false,
|
|
766
|
-
usesAcceptanceContract: step.effectiveAcceptance?.explicit === true,
|
|
767
|
-
tools: step.tools,
|
|
768
|
-
mcpDirectTools: step.mcpDirectTools,
|
|
769
|
-
});
|
|
770
|
-
const completionGuard = run.exitCode === 0 && !run.error && !hiddenError?.hasError && completionPolicy === "mutation-guard"
|
|
732
|
+
const completionGuard = run.exitCode === 0 && !run.error && !hiddenError?.hasError && step.completionGuard !== false
|
|
771
733
|
? evaluateCompletionMutationGuard({
|
|
772
734
|
agent: step.agent,
|
|
773
735
|
task: taskForCompletionGuard,
|
|
@@ -780,7 +742,7 @@ async function runSingleStep(
|
|
|
780
742
|
const completionGuardError = completionGuardTriggered
|
|
781
743
|
? "Subagent completed without making edits for an implementation task.\nIt appears to have returned planning or scratchpad output instead of applying changes."
|
|
782
744
|
: undefined;
|
|
783
|
-
const effectiveExitCode =
|
|
745
|
+
const effectiveExitCode = completionGuardTriggered
|
|
784
746
|
? 1
|
|
785
747
|
: structuredError
|
|
786
748
|
? 1
|
|
@@ -808,8 +770,8 @@ async function runSingleStep(
|
|
|
808
770
|
completionGuardTriggeredFinal = completionGuardTriggered;
|
|
809
771
|
finalOutputSnapshot = outputSnapshot;
|
|
810
772
|
finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput } as RunPiStreamingResult & { structuredOutput?: unknown };
|
|
811
|
-
if (attempt.success ||
|
|
812
|
-
if (
|
|
773
|
+
if (attempt.success || completionGuardTriggered) break;
|
|
774
|
+
if (!isRetryableModelFailure(error) || index === candidates.length - 1) break;
|
|
813
775
|
attemptNotes.push(formatModelAttemptNote(attempt, candidates[index + 1]));
|
|
814
776
|
}
|
|
815
777
|
|
|
@@ -821,12 +783,12 @@ async function runSingleStep(
|
|
|
821
783
|
const output = resolvedOutput.fullOutput;
|
|
822
784
|
const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, output) : undefined;
|
|
823
785
|
let outputForSummary = output;
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
786
|
+
if (attemptNotes.length > 0) {
|
|
787
|
+
outputForSummary = `${attemptNotes.join("\n")}\n\n${outputForSummary}`.trim();
|
|
788
|
+
}
|
|
827
789
|
const outputForAcceptance = rawOutput;
|
|
828
|
-
|
|
829
|
-
|
|
790
|
+
const finalizedOutput = finalizeSingleOutput({
|
|
791
|
+
fullOutput: outputForSummary,
|
|
830
792
|
outputPath: step.outputPath,
|
|
831
793
|
outputMode: step.outputMode,
|
|
832
794
|
exitCode: finalResult?.exitCode ?? 1,
|
|
@@ -835,117 +797,13 @@ async function runSingleStep(
|
|
|
835
797
|
saveError: resolvedOutput.saveError,
|
|
836
798
|
});
|
|
837
799
|
outputForSummary = finalizedOutput.displayOutput;
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
output: outputForAcceptance,
|
|
845
|
-
cwd: step.cwd ?? ctx.cwd,
|
|
846
|
-
})
|
|
800
|
+
const acceptance = step.effectiveAcceptance
|
|
801
|
+
? await evaluateAcceptance({
|
|
802
|
+
acceptance: step.effectiveAcceptance,
|
|
803
|
+
output: outputForAcceptance,
|
|
804
|
+
cwd: step.cwd ?? ctx.cwd,
|
|
805
|
+
})
|
|
847
806
|
: undefined;
|
|
848
|
-
if (acceptance && step.effectiveAcceptance && shouldRunAcceptanceFinalization(step.effectiveAcceptance) && (finalResult?.exitCode ?? 1) === 0 && !finalResult?.interrupted) {
|
|
849
|
-
const sessionFile = step.sessionFile ?? (sessionDir ? findLatestSessionFile(sessionDir) ?? undefined : undefined);
|
|
850
|
-
const maxTurns = step.effectiveAcceptance.finalization.maxTurns;
|
|
851
|
-
const turns: AcceptanceFinalizationTurn[] = [];
|
|
852
|
-
if (!sessionFile) {
|
|
853
|
-
const message = "Acceptance finalization requires a session file for same-session continuation.";
|
|
854
|
-
turns.push(createFinalizationProcessFailureTurn({ turn: 1, prompt: "", message }));
|
|
855
|
-
acceptance = buildFinalizationProcessFailureLedger({ initialLedger: acceptance, turns, maxTurns, message });
|
|
856
|
-
} else {
|
|
857
|
-
const selfReviewAcceptance = acceptanceSelfReviewConfig(step.effectiveAcceptance);
|
|
858
|
-
let previousFailure = acceptanceFailureMessage(acceptance);
|
|
859
|
-
let authoritativeLedger = acceptance;
|
|
860
|
-
for (let turn = 1; turn <= maxTurns; turn++) {
|
|
861
|
-
const prompt = formatAcceptanceFinalizationPrompt({
|
|
862
|
-
acceptance: step.effectiveAcceptance,
|
|
863
|
-
initialOutput: outputForAcceptance,
|
|
864
|
-
initialLedger: acceptance,
|
|
865
|
-
turn,
|
|
866
|
-
maxTurns,
|
|
867
|
-
...(previousFailure ? { previousFailure } : {}),
|
|
868
|
-
});
|
|
869
|
-
const { args, env, tempDir } = buildPiArgs({
|
|
870
|
-
baseArgs: ["--mode", "json", "-p"],
|
|
871
|
-
task: prompt,
|
|
872
|
-
sessionEnabled: true,
|
|
873
|
-
sessionFile,
|
|
874
|
-
model: finalResult?.model ?? step.model,
|
|
875
|
-
thinking: step.thinking,
|
|
876
|
-
inheritProjectContext: step.inheritProjectContext,
|
|
877
|
-
inheritSkills: step.inheritSkills,
|
|
878
|
-
tools: step.tools,
|
|
879
|
-
extensions: step.extensions,
|
|
880
|
-
systemPrompt: step.systemPrompt,
|
|
881
|
-
systemPromptMode: step.systemPromptMode,
|
|
882
|
-
mcpDirectTools: step.mcpDirectTools,
|
|
883
|
-
cwd: step.cwd ?? ctx.cwd,
|
|
884
|
-
promptFileStem: `${step.agent}-acceptance-finalization`,
|
|
885
|
-
intercomSessionName: ctx.childIntercomTarget,
|
|
886
|
-
orchestratorIntercomTarget: ctx.orchestratorIntercomTarget,
|
|
887
|
-
runId: ctx.id,
|
|
888
|
-
childAgentName: step.agent,
|
|
889
|
-
childIndex: ctx.flatIndex,
|
|
890
|
-
parentEventSink: ctx.nestedRoute?.eventSink,
|
|
891
|
-
parentControlInbox: ctx.nestedRoute?.controlInbox,
|
|
892
|
-
parentRootRunId: ctx.nestedRoute?.rootRunId,
|
|
893
|
-
parentCapabilityToken: ctx.nestedRoute?.capabilityToken,
|
|
894
|
-
});
|
|
895
|
-
ctx.onAttemptStart?.({ model: finalResult?.model ?? step.model, thinking: resolveEffectiveThinking(finalResult?.model ?? step.model, step.thinking) });
|
|
896
|
-
const finalizationRun = await runPiStreaming(
|
|
897
|
-
args,
|
|
898
|
-
step.cwd ?? ctx.cwd,
|
|
899
|
-
`${ctx.outputFile}.finalization-${turn}.log`,
|
|
900
|
-
env,
|
|
901
|
-
ctx.piPackageRoot,
|
|
902
|
-
ctx.piArgv1,
|
|
903
|
-
step.maxSubagentDepth,
|
|
904
|
-
{ eventsPath, runId: ctx.id, stepIndex: ctx.flatIndex, agent: step.agent },
|
|
905
|
-
ctx.registerInterrupt,
|
|
906
|
-
ctx.onChildEvent,
|
|
907
|
-
step.maxExecutionTimeMs,
|
|
908
|
-
step.maxTokens,
|
|
909
|
-
);
|
|
910
|
-
cleanupTempDir(tempDir);
|
|
911
|
-
modelAttempts.push({
|
|
912
|
-
model: finalResult?.model ?? finalizationRun.model ?? step.model ?? "default",
|
|
913
|
-
success: finalizationRun.exitCode === 0 && !finalizationRun.error,
|
|
914
|
-
exitCode: finalizationRun.exitCode,
|
|
915
|
-
error: finalizationRun.error,
|
|
916
|
-
usage: finalizationRun.usage,
|
|
917
|
-
});
|
|
918
|
-
const finalizationOutput = finalizationRun.finalOutput;
|
|
919
|
-
if (finalizationRun.exitCode !== 0 || finalizationRun.error || finalizationRun.interrupted) {
|
|
920
|
-
const message = finalizationRun.error ?? "Acceptance finalization turn did not complete successfully.";
|
|
921
|
-
turns.push(createFinalizationProcessFailureTurn({ turn, prompt, rawOutput: finalizationOutput, message }));
|
|
922
|
-
acceptance = buildFinalizationProcessFailureLedger({ initialLedger: acceptance, turns, maxTurns, message });
|
|
923
|
-
break;
|
|
924
|
-
}
|
|
925
|
-
const selfReviewLedger = await evaluateAcceptance({
|
|
926
|
-
acceptance: selfReviewAcceptance,
|
|
927
|
-
output: finalizationOutput,
|
|
928
|
-
cwd: step.cwd ?? ctx.cwd,
|
|
929
|
-
});
|
|
930
|
-
authoritativeLedger = selfReviewLedger;
|
|
931
|
-
turns.push(createFinalizationTurn({ turn, prompt, rawOutput: finalizationOutput, ledger: selfReviewLedger }));
|
|
932
|
-
const failure = acceptanceFailureMessage(selfReviewLedger);
|
|
933
|
-
if (!failure) {
|
|
934
|
-
authoritativeLedger = step.effectiveAcceptance === selfReviewAcceptance
|
|
935
|
-
? selfReviewLedger
|
|
936
|
-
: await evaluateAcceptance({
|
|
937
|
-
acceptance: step.effectiveAcceptance,
|
|
938
|
-
output: finalizationOutput,
|
|
939
|
-
cwd: step.cwd ?? ctx.cwd,
|
|
940
|
-
});
|
|
941
|
-
acceptance = attachFinalizationToLedger({ initialLedger: acceptance, authoritativeLedger, turns, status: "completed", maxTurns });
|
|
942
|
-
break;
|
|
943
|
-
}
|
|
944
|
-
previousFailure = failure;
|
|
945
|
-
if (turn === maxTurns) acceptance = attachFinalizationToLedger({ initialLedger: acceptance, authoritativeLedger, turns, status: "failed", maxTurns });
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
807
|
const acceptanceFailure = acceptance ? acceptanceFailureMessage(acceptance) : undefined;
|
|
950
808
|
const acceptanceCanFailRun = acceptanceFailure && acceptance?.explicit && (finalResult?.exitCode ?? 1) === 0 && !finalResult?.interrupted;
|
|
951
809
|
const effectiveFinalExitCode = acceptanceCanFailRun ? 1 : finalResult?.exitCode ?? 1;
|
|
@@ -968,7 +826,6 @@ async function runSingleStep(
|
|
|
968
826
|
model: finalResult?.model,
|
|
969
827
|
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
970
828
|
modelAttempts,
|
|
971
|
-
resourceLimitExceeded: finalResult?.resourceLimitExceeded,
|
|
972
829
|
skills: step.skills,
|
|
973
830
|
timestamp: Date.now(),
|
|
974
831
|
}, null, 2),
|
|
@@ -994,7 +851,6 @@ async function runSingleStep(
|
|
|
994
851
|
structuredOutputPath: effectiveStructuredOutput?.outputPath,
|
|
995
852
|
structuredOutputSchemaPath: effectiveStructuredOutput?.schemaPath,
|
|
996
853
|
acceptance,
|
|
997
|
-
resourceLimitExceeded: finalResult?.resourceLimitExceeded,
|
|
998
854
|
};
|
|
999
855
|
}
|
|
1000
856
|
|
|
@@ -1283,7 +1139,46 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1283
1139
|
writeAtomicJson(statusPath, statusPayload);
|
|
1284
1140
|
emitNestedSelfEvent(statusPayload.state === "running" || statusPayload.state === "queued" ? "subagent.nested.updated" : "subagent.nested.completed");
|
|
1285
1141
|
};
|
|
1286
|
-
const
|
|
1142
|
+
const consumePendingAppendRequests = (): void => {
|
|
1143
|
+
if (statusPayload.mode !== "chain" || statusPayload.state !== "running") return;
|
|
1144
|
+
const requests = consumeChainAppendRequests(asyncDir);
|
|
1145
|
+
if (requests.length === 0) {
|
|
1146
|
+
const pendingAppends = countPendingChainAppendRequests(asyncDir);
|
|
1147
|
+
if ((statusPayload.pendingAppends ?? 0) !== pendingAppends) {
|
|
1148
|
+
statusPayload.pendingAppends = pendingAppends;
|
|
1149
|
+
statusPayload.lastUpdate = Date.now();
|
|
1150
|
+
writeStatusPayload();
|
|
1151
|
+
}
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
const appendedSteps = requests.flatMap((request) => request.steps);
|
|
1155
|
+
steps.push(...appendedSteps);
|
|
1156
|
+
const now = Date.now();
|
|
1157
|
+
const pendingAppends = countPendingChainAppendRequests(asyncDir);
|
|
1158
|
+
const added = appendRunnerStepsToStatus({
|
|
1159
|
+
status: statusPayload,
|
|
1160
|
+
steps: appendedSteps,
|
|
1161
|
+
now,
|
|
1162
|
+
pendingAppends,
|
|
1163
|
+
});
|
|
1164
|
+
mutatingFailureStates.push(...Array.from({ length: added.addedFlatSteps }, () => createMutatingFailureState()));
|
|
1165
|
+
pendingToolResults.push(...Array.from({ length: added.addedFlatSteps }, () => undefined));
|
|
1166
|
+
if (config.childIntercomTargets) {
|
|
1167
|
+
config.childIntercomTargets = statusPayload.steps.map((statusStep, index) => resolveSubagentIntercomTarget(id, statusStep.agent, index));
|
|
1168
|
+
}
|
|
1169
|
+
writeStatusPayload();
|
|
1170
|
+
for (const request of requests) {
|
|
1171
|
+
appendJsonl(eventsPath, JSON.stringify({
|
|
1172
|
+
type: "subagent.chain.append.accepted",
|
|
1173
|
+
ts: now,
|
|
1174
|
+
runId: id,
|
|
1175
|
+
requestId: request.id,
|
|
1176
|
+
stepCount: request.steps.length,
|
|
1177
|
+
pendingAppends,
|
|
1178
|
+
}));
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
const markDynamicGraphGroup = (stepIndex: number, status: "completed" | "failed" | "running", error?: string, acceptance?: import("../../shared/types.ts").AcceptanceLedger): void => {
|
|
1287
1182
|
const groupNode = statusPayload.workflowGraph?.nodes.find((node) => node.id === `step-${stepIndex}`);
|
|
1288
1183
|
if (!groupNode) return;
|
|
1289
1184
|
groupNode.status = status;
|
|
@@ -1574,10 +1469,14 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1574
1469
|
);
|
|
1575
1470
|
|
|
1576
1471
|
let flatIndex = 0;
|
|
1472
|
+
let stepCursor = 0;
|
|
1577
1473
|
|
|
1578
|
-
|
|
1474
|
+
while (true) {
|
|
1579
1475
|
if (interrupted) break;
|
|
1580
|
-
|
|
1476
|
+
consumePendingAppendRequests();
|
|
1477
|
+
if (stepCursor >= steps.length) break;
|
|
1478
|
+
const stepIndex = stepCursor++;
|
|
1479
|
+
const step = steps[stepIndex]!;
|
|
1581
1480
|
|
|
1582
1481
|
if (isDynamicRunnerGroup(step)) {
|
|
1583
1482
|
const groupStartFlatIndex = flatIndex;
|
|
@@ -1625,9 +1524,36 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1625
1524
|
placeholder.durationMs = 0;
|
|
1626
1525
|
}
|
|
1627
1526
|
previousOutput = "Dynamic fanout produced 0 results.";
|
|
1527
|
+
const groupAcceptance = step.effectiveAcceptance?.explicit
|
|
1528
|
+
? await evaluateAcceptance({
|
|
1529
|
+
acceptance: step.effectiveAcceptance,
|
|
1530
|
+
output: "",
|
|
1531
|
+
report: aggregateAcceptanceReport({
|
|
1532
|
+
results: [],
|
|
1533
|
+
notes: "Dynamic fanout produced 0 results.",
|
|
1534
|
+
}),
|
|
1535
|
+
cwd,
|
|
1536
|
+
})
|
|
1537
|
+
: undefined;
|
|
1538
|
+
if (placeholder && groupAcceptance) placeholder.acceptance = groupAcceptance;
|
|
1539
|
+
const groupAcceptanceFailure = groupAcceptance ? acceptanceFailureMessage(groupAcceptance) : undefined;
|
|
1540
|
+
if (groupAcceptanceFailure) {
|
|
1541
|
+
statusPayload.state = "failed";
|
|
1542
|
+
statusPayload.error = groupAcceptanceFailure;
|
|
1543
|
+
if (placeholder) {
|
|
1544
|
+
placeholder.status = "failed";
|
|
1545
|
+
placeholder.error = groupAcceptanceFailure;
|
|
1546
|
+
placeholder.exitCode = 1;
|
|
1547
|
+
}
|
|
1548
|
+
markDynamicGraphGroup(stepIndex, "failed", groupAcceptanceFailure, groupAcceptance);
|
|
1549
|
+
statusPayload.lastUpdate = now;
|
|
1550
|
+
writeStatusPayload();
|
|
1551
|
+
results.push({ agent: step.parallel.agent, output: groupAcceptanceFailure, error: groupAcceptanceFailure, success: false, exitCode: 1, acceptance: groupAcceptance });
|
|
1552
|
+
break;
|
|
1553
|
+
}
|
|
1628
1554
|
flatIndex++;
|
|
1629
1555
|
statusPayload.lastUpdate = now;
|
|
1630
|
-
markDynamicGraphGroup(stepIndex, "completed");
|
|
1556
|
+
markDynamicGraphGroup(stepIndex, "completed", undefined, groupAcceptance);
|
|
1631
1557
|
writeStatusPayload();
|
|
1632
1558
|
continue;
|
|
1633
1559
|
}
|
|
@@ -1759,14 +1685,12 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1759
1685
|
statusPayload.steps[fi].structuredOutputPath = singleResult.structuredOutputPath;
|
|
1760
1686
|
statusPayload.steps[fi].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
|
|
1761
1687
|
statusPayload.steps[fi].acceptance = singleResult.acceptance;
|
|
1762
|
-
statusPayload.steps[fi].resourceLimitExceeded = singleResult.resourceLimitExceeded;
|
|
1763
1688
|
statusPayload.lastUpdate = taskEndTime;
|
|
1764
1689
|
writeStatusPayload();
|
|
1765
1690
|
appendJsonl(eventsPath, JSON.stringify({
|
|
1766
1691
|
type: singleResult.exitCode === 0 ? "subagent.step.completed" : "subagent.step.failed",
|
|
1767
1692
|
ts: taskEndTime, runId: id, stepIndex: fi, agent: task.agent,
|
|
1768
1693
|
exitCode: singleResult.exitCode, durationMs: taskEndTime - taskStartTime,
|
|
1769
|
-
resourceLimitExceeded: singleResult.resourceLimitExceeded,
|
|
1770
1694
|
}));
|
|
1771
1695
|
if (singleResult.exitCode !== 0 && failFast) aborted = true;
|
|
1772
1696
|
return { ...singleResult, skipped: false };
|
|
@@ -1791,7 +1715,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1791
1715
|
structuredOutputPath: pr.structuredOutputPath,
|
|
1792
1716
|
structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
|
|
1793
1717
|
acceptance: pr.acceptance,
|
|
1794
|
-
resourceLimitExceeded: pr.resourceLimitExceeded,
|
|
1795
1718
|
});
|
|
1796
1719
|
}
|
|
1797
1720
|
const collection = collectDynamicResults(step as Parameters<typeof collectDynamicResults>[0], materialized.items, parallelResults);
|
|
@@ -1806,7 +1729,31 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1806
1729
|
stepIndex,
|
|
1807
1730
|
};
|
|
1808
1731
|
statusPayload.outputs = outputs;
|
|
1809
|
-
|
|
1732
|
+
const groupAcceptance = step.effectiveAcceptance
|
|
1733
|
+
? await evaluateAcceptance({
|
|
1734
|
+
acceptance: step.effectiveAcceptance,
|
|
1735
|
+
output: "",
|
|
1736
|
+
report: aggregateAcceptanceReport({
|
|
1737
|
+
results: parallelResults,
|
|
1738
|
+
notes: `Dynamic fanout collected ${collection.length} result(s) into ${step.collect.as}.`,
|
|
1739
|
+
}),
|
|
1740
|
+
cwd,
|
|
1741
|
+
})
|
|
1742
|
+
: undefined;
|
|
1743
|
+
const groupAcceptanceFailure = groupAcceptance ? acceptanceFailureMessage(groupAcceptance) : undefined;
|
|
1744
|
+
markDynamicGraphGroup(stepIndex, groupAcceptanceFailure ? "failed" : "completed", groupAcceptanceFailure, groupAcceptance);
|
|
1745
|
+
if (groupAcceptanceFailure) {
|
|
1746
|
+
results.push({
|
|
1747
|
+
agent: step.parallel.agent,
|
|
1748
|
+
output: groupAcceptanceFailure,
|
|
1749
|
+
error: groupAcceptanceFailure,
|
|
1750
|
+
success: false,
|
|
1751
|
+
exitCode: 1,
|
|
1752
|
+
structuredOutput: collection,
|
|
1753
|
+
acceptance: groupAcceptance,
|
|
1754
|
+
});
|
|
1755
|
+
statusPayload.error = groupAcceptanceFailure;
|
|
1756
|
+
}
|
|
1810
1757
|
} catch (error) {
|
|
1811
1758
|
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
1812
1759
|
results.push({ agent: step.parallel.agent, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection });
|
|
@@ -1958,7 +1905,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1958
1905
|
outputs,
|
|
1959
1906
|
sessionDir: taskSessionDir,
|
|
1960
1907
|
artifactsDir, artifactConfig, id,
|
|
1961
|
-
flatIndex: fi, flatStepCount:
|
|
1908
|
+
flatIndex: fi, flatStepCount: Math.max(statusPayload.steps.length, 1),
|
|
1962
1909
|
outputFile: path.join(asyncDir, `output-${fi}.log`),
|
|
1963
1910
|
piPackageRoot: config.piPackageRoot,
|
|
1964
1911
|
piArgv1: config.piArgv1,
|
|
@@ -1991,7 +1938,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1991
1938
|
statusPayload.steps[fi].structuredOutputPath = singleResult.structuredOutputPath;
|
|
1992
1939
|
statusPayload.steps[fi].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
|
|
1993
1940
|
statusPayload.steps[fi].acceptance = singleResult.acceptance;
|
|
1994
|
-
statusPayload.steps[fi].resourceLimitExceeded = singleResult.resourceLimitExceeded;
|
|
1995
1941
|
statusPayload.lastUpdate = taskEndTime;
|
|
1996
1942
|
writeStatusPayload();
|
|
1997
1943
|
|
|
@@ -1999,7 +1945,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
1999
1945
|
type: singleResult.exitCode === 0 ? "subagent.step.completed" : "subagent.step.failed",
|
|
2000
1946
|
ts: taskEndTime, runId: id, stepIndex: fi, agent: task.agent,
|
|
2001
1947
|
exitCode: singleResult.exitCode, durationMs: taskDuration,
|
|
2002
|
-
resourceLimitExceeded: singleResult.resourceLimitExceeded,
|
|
2003
1948
|
}));
|
|
2004
1949
|
if (singleResult.completionGuardTriggered) {
|
|
2005
1950
|
const event = buildControlEvent({
|
|
@@ -2058,7 +2003,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2058
2003
|
structuredOutputPath: pr.structuredOutputPath,
|
|
2059
2004
|
structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
|
|
2060
2005
|
acceptance: pr.acceptance,
|
|
2061
|
-
resourceLimitExceeded: pr.resourceLimitExceeded,
|
|
2062
2006
|
});
|
|
2063
2007
|
}
|
|
2064
2008
|
for (let t = 0; t < group.parallel.length; t++) {
|
|
@@ -2126,7 +2070,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2126
2070
|
outputs,
|
|
2127
2071
|
sessionDir: config.sessionDir,
|
|
2128
2072
|
artifactsDir, artifactConfig, id,
|
|
2129
|
-
flatIndex, flatStepCount:
|
|
2073
|
+
flatIndex, flatStepCount: Math.max(statusPayload.steps.length, 1),
|
|
2130
2074
|
outputFile: path.join(asyncDir, `output-${flatIndex}.log`),
|
|
2131
2075
|
piPackageRoot: config.piPackageRoot,
|
|
2132
2076
|
piArgv1: config.piArgv1,
|
|
@@ -2160,7 +2104,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2160
2104
|
structuredOutputPath: singleResult.structuredOutputPath,
|
|
2161
2105
|
structuredOutputSchemaPath: singleResult.structuredOutputSchemaPath,
|
|
2162
2106
|
acceptance: singleResult.acceptance,
|
|
2163
|
-
resourceLimitExceeded: singleResult.resourceLimitExceeded,
|
|
2164
2107
|
});
|
|
2165
2108
|
if (seqStep.outputName) {
|
|
2166
2109
|
outputs[seqStep.outputName] = outputEntryFromAsyncResult({
|
|
@@ -2206,7 +2149,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2206
2149
|
statusPayload.steps[flatIndex].structuredOutputPath = singleResult.structuredOutputPath;
|
|
2207
2150
|
statusPayload.steps[flatIndex].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
|
|
2208
2151
|
statusPayload.steps[flatIndex].acceptance = singleResult.acceptance;
|
|
2209
|
-
statusPayload.steps[flatIndex].resourceLimitExceeded = singleResult.resourceLimitExceeded;
|
|
2210
2152
|
if (stepTokens) {
|
|
2211
2153
|
statusPayload.steps[flatIndex].tokens = stepTokens;
|
|
2212
2154
|
statusPayload.totalTokens = { ...previousCumulativeTokens };
|
|
@@ -2223,7 +2165,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2223
2165
|
exitCode: singleResult.exitCode,
|
|
2224
2166
|
durationMs: stepEndTime - stepStartTime,
|
|
2225
2167
|
tokens: stepTokens,
|
|
2226
|
-
resourceLimitExceeded: singleResult.resourceLimitExceeded,
|
|
2227
2168
|
}));
|
|
2228
2169
|
if (singleResult.completionGuardTriggered) {
|
|
2229
2170
|
const event = buildControlEvent({
|
|
@@ -2260,11 +2201,12 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2260
2201
|
}
|
|
2261
2202
|
|
|
2262
2203
|
const resultMode = config.resultMode ?? statusPayload.mode;
|
|
2263
|
-
const
|
|
2264
|
-
|
|
2204
|
+
const finalFlatAgents = statusPayload.steps.map((step) => step.agent);
|
|
2205
|
+
const agentName = finalFlatAgents.length === 1
|
|
2206
|
+
? finalFlatAgents[0]!
|
|
2265
2207
|
: resultMode === "parallel"
|
|
2266
|
-
? `parallel:${
|
|
2267
|
-
: `chain:${
|
|
2208
|
+
? `parallel:${finalFlatAgents.join("+")}`
|
|
2209
|
+
: `chain:${finalFlatAgents.join("->")}`;
|
|
2268
2210
|
let sessionFile: string | undefined;
|
|
2269
2211
|
let shareUrl: string | undefined;
|
|
2270
2212
|
let gistUrl: string | undefined;
|
|
@@ -2370,7 +2312,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
2370
2312
|
structuredOutputPath: r.structuredOutputPath,
|
|
2371
2313
|
structuredOutputSchemaPath: r.structuredOutputSchemaPath,
|
|
2372
2314
|
acceptance: r.acceptance,
|
|
2373
|
-
resourceLimitExceeded: r.resourceLimitExceeded,
|
|
2374
2315
|
})),
|
|
2375
2316
|
outputs,
|
|
2376
2317
|
workflowGraph: statusPayload.workflowGraph,
|