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
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
|
-
import { existsSync } from "node:fs";
|
|
6
|
+
import { existsSync, mkdtempSync, unlinkSync } from "node:fs";
|
|
7
|
+
import * as os from "node:os";
|
|
8
|
+
import * as path from "node:path";
|
|
7
9
|
import type { Message } from "@earendil-works/pi-ai";
|
|
8
10
|
import type { AgentConfig } from "../../agents/agents.ts";
|
|
9
11
|
import {
|
|
@@ -13,10 +15,13 @@ import {
|
|
|
13
15
|
writeMetadata,
|
|
14
16
|
} from "../../shared/artifacts.ts";
|
|
15
17
|
import {
|
|
18
|
+
type AcceptanceFinalizationTurn,
|
|
19
|
+
type AcceptanceLedger,
|
|
16
20
|
type AgentProgress,
|
|
17
21
|
type ArtifactPaths,
|
|
18
22
|
type ControlEvent,
|
|
19
23
|
type ModelAttempt,
|
|
24
|
+
type ResolvedAcceptanceConfig,
|
|
20
25
|
type RunSyncOptions,
|
|
21
26
|
type SingleResult,
|
|
22
27
|
type Usage,
|
|
@@ -41,11 +46,12 @@ import {
|
|
|
41
46
|
extractTextFromContent,
|
|
42
47
|
} from "../../shared/utils.ts";
|
|
43
48
|
import { buildSkillInjection, resolveSkillsWithFallback } from "../../agents/skills.ts";
|
|
44
|
-
import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
|
|
49
|
+
import { evaluateCompletionMutationGuard, resolveCompletionPolicy, type CompletionPolicy } from "../shared/completion-guard.ts";
|
|
45
50
|
import { getPiSpawnCommand } from "../shared/pi-spawn.ts";
|
|
46
51
|
import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
|
|
47
52
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
48
53
|
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
|
|
54
|
+
import { readStructuredOutput } from "../shared/structured-output.ts";
|
|
49
55
|
import { captureSingleOutputSnapshot, formatSavedOutputReference, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
50
56
|
import {
|
|
51
57
|
buildModelCandidates,
|
|
@@ -63,8 +69,23 @@ import {
|
|
|
63
69
|
shouldEscalateMutatingFailures,
|
|
64
70
|
summarizeRecentMutatingFailures,
|
|
65
71
|
} from "../shared/long-running-guard.ts";
|
|
72
|
+
import {
|
|
73
|
+
acceptanceFailureMessage,
|
|
74
|
+
acceptanceSelfReviewConfig,
|
|
75
|
+
attachFinalizationToLedger,
|
|
76
|
+
buildFinalizationProcessFailureLedger,
|
|
77
|
+
createFinalizationProcessFailureTurn,
|
|
78
|
+
createFinalizationTurn,
|
|
79
|
+
evaluateAcceptance,
|
|
80
|
+
formatAcceptanceFinalizationPrompt,
|
|
81
|
+
formatAcceptancePrompt,
|
|
82
|
+
resolveEffectiveAcceptance,
|
|
83
|
+
shouldRunAcceptanceFinalization,
|
|
84
|
+
stripAcceptanceReport,
|
|
85
|
+
} from "../shared/acceptance.ts";
|
|
66
86
|
|
|
67
87
|
const artifactOutputByResult = new WeakMap<SingleResult, string>();
|
|
88
|
+
const acceptanceOutputByResult = new WeakMap<SingleResult, string>();
|
|
68
89
|
|
|
69
90
|
function emptyUsage(): Usage {
|
|
70
91
|
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
|
|
@@ -87,6 +108,17 @@ function appendRecentOutput(progress: AgentProgress, lines: string[]): void {
|
|
|
87
108
|
}
|
|
88
109
|
}
|
|
89
110
|
|
|
111
|
+
function stripAcceptanceReportsFromMessages(messages: Message[] | undefined): void {
|
|
112
|
+
for (const message of messages ?? []) {
|
|
113
|
+
if (message.role !== "assistant" || !Array.isArray(message.content)) continue;
|
|
114
|
+
for (const part of message.content) {
|
|
115
|
+
if (part.type === "text" && "text" in part && typeof part.text === "string") {
|
|
116
|
+
part.text = stripAcceptanceReport(part.text);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
90
122
|
function snapshotProgress(progress: AgentProgress): AgentProgress {
|
|
91
123
|
return {
|
|
92
124
|
...progress,
|
|
@@ -133,6 +165,8 @@ async function runSingleAttempt(
|
|
|
133
165
|
artifactPaths?: ArtifactPaths;
|
|
134
166
|
attemptNotes: string[];
|
|
135
167
|
outputSnapshot?: SingleOutputSnapshot;
|
|
168
|
+
originalTask?: string;
|
|
169
|
+
completionPolicy: CompletionPolicy;
|
|
136
170
|
},
|
|
137
171
|
): Promise<SingleResult> {
|
|
138
172
|
const modelArg = applyThinkingSuffix(model, agent.thinking);
|
|
@@ -158,11 +192,16 @@ async function runSingleAttempt(
|
|
|
158
192
|
runId: options.runId,
|
|
159
193
|
childAgentName: agent.name,
|
|
160
194
|
childIndex: options.index ?? 0,
|
|
195
|
+
parentEventSink: options.nestedRoute?.eventSink,
|
|
196
|
+
parentControlInbox: options.nestedRoute?.controlInbox,
|
|
197
|
+
parentRootRunId: options.nestedRoute?.rootRunId,
|
|
198
|
+
parentCapabilityToken: options.nestedRoute?.capabilityToken,
|
|
199
|
+
structuredOutput: options.structuredOutput,
|
|
161
200
|
});
|
|
162
201
|
|
|
163
202
|
const result: SingleResult = {
|
|
164
203
|
agent: agent.name,
|
|
165
|
-
task,
|
|
204
|
+
task: shared.originalTask ?? task,
|
|
166
205
|
exitCode: 0,
|
|
167
206
|
messages: [],
|
|
168
207
|
usage: emptyUsage(),
|
|
@@ -172,6 +211,13 @@ async function runSingleAttempt(
|
|
|
172
211
|
skillsWarning: shared.skillsWarning,
|
|
173
212
|
};
|
|
174
213
|
const startTime = Date.now();
|
|
214
|
+
if (options.structuredOutput) {
|
|
215
|
+
try {
|
|
216
|
+
if (existsSync(options.structuredOutput.outputPath)) unlinkSync(options.structuredOutput.outputPath);
|
|
217
|
+
} catch {
|
|
218
|
+
// Missing/stale structured-output files are handled after the child exits.
|
|
219
|
+
}
|
|
220
|
+
}
|
|
175
221
|
const controlConfig = options.controlConfig ?? DEFAULT_CONTROL_CONFIG;
|
|
176
222
|
let interruptedByControl = false;
|
|
177
223
|
const allControlEvents: ControlEvent[] = [];
|
|
@@ -651,6 +697,21 @@ async function runSingleAttempt(
|
|
|
651
697
|
: `${errInfo.errorType} failed with exit code ${errInfo.exitCode}`;
|
|
652
698
|
}
|
|
653
699
|
}
|
|
700
|
+
if (options.structuredOutput && result.exitCode === 0 && !result.error) {
|
|
701
|
+
const structured = readStructuredOutput({
|
|
702
|
+
schema: options.structuredOutput.schema,
|
|
703
|
+
schemaPath: options.structuredOutput.schemaPath,
|
|
704
|
+
outputPath: options.structuredOutput.outputPath,
|
|
705
|
+
});
|
|
706
|
+
result.structuredOutputSchemaPath = options.structuredOutput.schemaPath;
|
|
707
|
+
result.structuredOutputPath = options.structuredOutput.outputPath;
|
|
708
|
+
if (structured.error) {
|
|
709
|
+
result.exitCode = 1;
|
|
710
|
+
result.error = structured.error;
|
|
711
|
+
} else {
|
|
712
|
+
result.structuredOutput = structured.value;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
654
715
|
|
|
655
716
|
progress.status = result.exitCode === 0 ? "completed" : "failed";
|
|
656
717
|
progress.durationMs = Date.now() - startTime;
|
|
@@ -667,17 +728,19 @@ async function runSingleAttempt(
|
|
|
667
728
|
durationMs: progress.durationMs,
|
|
668
729
|
};
|
|
669
730
|
|
|
670
|
-
|
|
671
|
-
|
|
731
|
+
const acceptanceOutput = getFinalOutput(result.messages);
|
|
732
|
+
let fullOutput = stripAcceptanceReport(acceptanceOutput);
|
|
733
|
+
const completionGuard = result.exitCode === 0 && !result.error && shared.completionPolicy === "mutation-guard"
|
|
672
734
|
? evaluateCompletionMutationGuard({
|
|
673
735
|
agent: agent.name,
|
|
674
|
-
task,
|
|
736
|
+
task: shared.originalTask ?? task,
|
|
675
737
|
messages: result.messages,
|
|
676
738
|
tools: agent.tools,
|
|
677
739
|
mcpDirectTools: agent.mcpDirectTools,
|
|
678
740
|
})
|
|
679
741
|
: undefined;
|
|
680
|
-
|
|
742
|
+
const completionGuardTriggered = completionGuard?.triggered === true && !observedMutationAttempt;
|
|
743
|
+
if (completionGuardTriggered) {
|
|
681
744
|
result.exitCode = 1;
|
|
682
745
|
result.error = "Subagent completed without making edits for an implementation task.\nIt appears to have returned planning or scratchpad output instead of applying changes.";
|
|
683
746
|
progress.status = "failed";
|
|
@@ -695,7 +758,7 @@ async function runSingleAttempt(
|
|
|
695
758
|
}
|
|
696
759
|
if (options.outputPath && result.exitCode === 0) {
|
|
697
760
|
const resolvedOutput = resolveSingleOutput(options.outputPath, fullOutput, shared.outputSnapshot);
|
|
698
|
-
fullOutput = resolvedOutput.fullOutput;
|
|
761
|
+
fullOutput = stripAcceptanceReport(resolvedOutput.fullOutput);
|
|
699
762
|
result.savedOutputPath = resolvedOutput.savedPath;
|
|
700
763
|
result.outputSaveError = resolvedOutput.saveError;
|
|
701
764
|
if (resolvedOutput.savedPath) {
|
|
@@ -703,6 +766,7 @@ async function runSingleAttempt(
|
|
|
703
766
|
}
|
|
704
767
|
}
|
|
705
768
|
artifactOutputByResult.set(result, fullOutput);
|
|
769
|
+
acceptanceOutputByResult.set(result, acceptanceOutput);
|
|
706
770
|
result.outputMode = options.outputMode ?? "inline";
|
|
707
771
|
result.finalOutput = options.outputMode === "file-only" && result.savedOutputPath && result.outputReference
|
|
708
772
|
? result.outputReference.message
|
|
@@ -725,6 +789,99 @@ async function runSingleAttempt(
|
|
|
725
789
|
return result;
|
|
726
790
|
}
|
|
727
791
|
|
|
792
|
+
async function runAcceptanceFinalizationLoop(input: {
|
|
793
|
+
runtimeCwd: string;
|
|
794
|
+
agent: AgentConfig;
|
|
795
|
+
result: SingleResult;
|
|
796
|
+
initialLedger: AcceptanceLedger;
|
|
797
|
+
initialOutput: string;
|
|
798
|
+
acceptance: ResolvedAcceptanceConfig;
|
|
799
|
+
options: RunSyncOptions;
|
|
800
|
+
systemPrompt: string;
|
|
801
|
+
resolvedSkillNames?: string[];
|
|
802
|
+
skillsWarning?: string;
|
|
803
|
+
}): Promise<AcceptanceLedger> {
|
|
804
|
+
const sessionFile = input.result.sessionFile ?? input.options.sessionFile;
|
|
805
|
+
const maxTurns = input.acceptance.finalization.maxTurns;
|
|
806
|
+
const turns: AcceptanceFinalizationTurn[] = [];
|
|
807
|
+
if (!sessionFile) {
|
|
808
|
+
const message = "Acceptance finalization requires a session file for same-session continuation.";
|
|
809
|
+
turns.push(createFinalizationProcessFailureTurn({ turn: 1, prompt: "", message }));
|
|
810
|
+
return buildFinalizationProcessFailureLedger({ initialLedger: input.initialLedger, turns, maxTurns, message });
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const selfReviewAcceptance = acceptanceSelfReviewConfig(input.acceptance);
|
|
814
|
+
let previousFailure = acceptanceFailureMessage(input.initialLedger);
|
|
815
|
+
let authoritativeLedger = input.initialLedger;
|
|
816
|
+
for (let turn = 1; turn <= maxTurns; turn++) {
|
|
817
|
+
const prompt = formatAcceptanceFinalizationPrompt({
|
|
818
|
+
acceptance: input.acceptance,
|
|
819
|
+
initialOutput: input.initialOutput,
|
|
820
|
+
initialLedger: input.initialLedger,
|
|
821
|
+
turn,
|
|
822
|
+
maxTurns,
|
|
823
|
+
...(previousFailure ? { previousFailure } : {}),
|
|
824
|
+
});
|
|
825
|
+
const finalizationOptions: RunSyncOptions = { ...input.options, sessionFile, outputMode: "inline" };
|
|
826
|
+
delete finalizationOptions.sessionDir;
|
|
827
|
+
delete finalizationOptions.outputPath;
|
|
828
|
+
delete finalizationOptions.structuredOutput;
|
|
829
|
+
delete finalizationOptions.onUpdate;
|
|
830
|
+
finalizationOptions.allowIntercomDetach = false;
|
|
831
|
+
const finalizationResult = await runSingleAttempt(
|
|
832
|
+
input.runtimeCwd,
|
|
833
|
+
input.agent,
|
|
834
|
+
prompt,
|
|
835
|
+
input.result.model,
|
|
836
|
+
finalizationOptions,
|
|
837
|
+
{
|
|
838
|
+
sessionEnabled: true,
|
|
839
|
+
systemPrompt: input.systemPrompt,
|
|
840
|
+
resolvedSkillNames: input.resolvedSkillNames,
|
|
841
|
+
skillsWarning: input.skillsWarning,
|
|
842
|
+
attemptNotes: [],
|
|
843
|
+
originalTask: prompt,
|
|
844
|
+
completionPolicy: "acceptance-contract",
|
|
845
|
+
},
|
|
846
|
+
);
|
|
847
|
+
sumUsage(input.result.usage, finalizationResult.usage);
|
|
848
|
+
input.result.progressSummary = {
|
|
849
|
+
toolCount: (input.result.progressSummary?.toolCount ?? 0) + (finalizationResult.progressSummary?.toolCount ?? 0),
|
|
850
|
+
tokens: input.result.usage.input + input.result.usage.output,
|
|
851
|
+
durationMs: (input.result.progressSummary?.durationMs ?? 0) + (finalizationResult.progressSummary?.durationMs ?? 0),
|
|
852
|
+
};
|
|
853
|
+
if (finalizationResult.controlEvents?.length) {
|
|
854
|
+
input.result.controlEvents = [...(input.result.controlEvents ?? []), ...finalizationResult.controlEvents];
|
|
855
|
+
}
|
|
856
|
+
const rawOutput = acceptanceOutputByResult.get(finalizationResult) ?? getFinalOutput(finalizationResult.messages) ?? finalizationResult.finalOutput ?? "";
|
|
857
|
+
if (finalizationResult.exitCode !== 0 || finalizationResult.error || finalizationResult.detached || finalizationResult.interrupted) {
|
|
858
|
+
const message = finalizationResult.error ?? "Acceptance finalization turn did not complete successfully.";
|
|
859
|
+
turns.push(createFinalizationProcessFailureTurn({ turn, prompt, rawOutput, message }));
|
|
860
|
+
return buildFinalizationProcessFailureLedger({ initialLedger: input.initialLedger, turns, maxTurns, message });
|
|
861
|
+
}
|
|
862
|
+
const selfReviewLedger = await evaluateAcceptance({
|
|
863
|
+
acceptance: selfReviewAcceptance,
|
|
864
|
+
output: rawOutput,
|
|
865
|
+
cwd: input.options.cwd ?? input.runtimeCwd,
|
|
866
|
+
});
|
|
867
|
+
authoritativeLedger = selfReviewLedger;
|
|
868
|
+
turns.push(createFinalizationTurn({ turn, prompt, rawOutput, ledger: selfReviewLedger }));
|
|
869
|
+
const failure = acceptanceFailureMessage(selfReviewLedger);
|
|
870
|
+
if (!failure) {
|
|
871
|
+
authoritativeLedger = input.acceptance === selfReviewAcceptance
|
|
872
|
+
? selfReviewLedger
|
|
873
|
+
: await evaluateAcceptance({
|
|
874
|
+
acceptance: input.acceptance,
|
|
875
|
+
output: rawOutput,
|
|
876
|
+
cwd: input.options.cwd ?? input.runtimeCwd,
|
|
877
|
+
});
|
|
878
|
+
return attachFinalizationToLedger({ initialLedger: input.initialLedger, authoritativeLedger, turns, status: "completed", maxTurns });
|
|
879
|
+
}
|
|
880
|
+
previousFailure = failure;
|
|
881
|
+
}
|
|
882
|
+
return attachFinalizationToLedger({ initialLedger: input.initialLedger, authoritativeLedger, turns, status: "failed", maxTurns });
|
|
883
|
+
}
|
|
884
|
+
|
|
728
885
|
/**
|
|
729
886
|
* Run a subagent synchronously (blocking until complete)
|
|
730
887
|
*/
|
|
@@ -760,6 +917,21 @@ export async function runSync(
|
|
|
760
917
|
}
|
|
761
918
|
|
|
762
919
|
const shareEnabled = options.share === true;
|
|
920
|
+
const effectiveAcceptance = resolveEffectiveAcceptance({
|
|
921
|
+
explicit: options.acceptance,
|
|
922
|
+
agentName,
|
|
923
|
+
task,
|
|
924
|
+
mode: options.acceptanceContext?.mode ?? "single",
|
|
925
|
+
async: options.acceptanceContext?.async,
|
|
926
|
+
dynamic: options.acceptanceContext?.dynamic,
|
|
927
|
+
dynamicGroup: options.acceptanceContext?.dynamicGroup,
|
|
928
|
+
});
|
|
929
|
+
if (shouldRunAcceptanceFinalization(effectiveAcceptance) && !options.sessionFile) {
|
|
930
|
+
const sessionDir = options.sessionDir ?? mkdtempSync(path.join(os.tmpdir(), "pi-subagent-finalization-"));
|
|
931
|
+
options.sessionFile = path.join(sessionDir, "session.jsonl");
|
|
932
|
+
}
|
|
933
|
+
const acceptancePrompt = formatAcceptancePrompt(effectiveAcceptance);
|
|
934
|
+
const taskWithAcceptance = acceptancePrompt ? `${task}\n${acceptancePrompt}` : task;
|
|
763
935
|
const sessionEnabled = Boolean(options.sessionFile || options.sessionDir) || shareEnabled;
|
|
764
936
|
const skillNames = options.skills ?? agent.skills ?? [];
|
|
765
937
|
const skillCwd = options.cwd ?? runtimeCwd;
|
|
@@ -799,7 +971,7 @@ export async function runSync(
|
|
|
799
971
|
artifactPathsResult = getArtifactPaths(options.artifactsDir, options.runId, agentName, options.index);
|
|
800
972
|
ensureArtifactsDir(options.artifactsDir);
|
|
801
973
|
if (options.artifactConfig?.includeInput !== false) {
|
|
802
|
-
|
|
974
|
+
writeArtifact(artifactPathsResult.inputPath, `# Task for ${agentName}\n\n${taskWithAcceptance}`);
|
|
803
975
|
}
|
|
804
976
|
if (options.artifactConfig?.includeJsonl !== false) {
|
|
805
977
|
jsonlPath = artifactPathsResult.jsonlPath;
|
|
@@ -812,7 +984,7 @@ export async function runSync(
|
|
|
812
984
|
const candidate = modelsToTry[i];
|
|
813
985
|
if (candidate) attemptedModels.push(candidate);
|
|
814
986
|
const outputSnapshot = captureSingleOutputSnapshot(options.outputPath);
|
|
815
|
-
const result = await runSingleAttempt(runtimeCwd, agent,
|
|
987
|
+
const result = await runSingleAttempt(runtimeCwd, agent, taskWithAcceptance, candidate, options, {
|
|
816
988
|
sessionEnabled,
|
|
817
989
|
systemPrompt,
|
|
818
990
|
resolvedSkillNames: resolvedSkills.length > 0 ? resolvedSkills.map((skill) => skill.name) : undefined,
|
|
@@ -821,6 +993,15 @@ export async function runSync(
|
|
|
821
993
|
artifactPaths: artifactPathsResult,
|
|
822
994
|
attemptNotes,
|
|
823
995
|
outputSnapshot,
|
|
996
|
+
originalTask: task,
|
|
997
|
+
completionPolicy: resolveCompletionPolicy({
|
|
998
|
+
agent: agent.name,
|
|
999
|
+
task,
|
|
1000
|
+
completionGuardEnabled: agent.completionGuard !== false,
|
|
1001
|
+
usesAcceptanceContract: effectiveAcceptance.explicit,
|
|
1002
|
+
tools: agent.tools,
|
|
1003
|
+
mcpDirectTools: agent.mcpDirectTools,
|
|
1004
|
+
}),
|
|
824
1005
|
});
|
|
825
1006
|
lastResult = result;
|
|
826
1007
|
sumUsage(aggregateUsage, result.usage);
|
|
@@ -910,5 +1091,40 @@ export async function runSync(
|
|
|
910
1091
|
if (sessionFile) result.sessionFile = sessionFile;
|
|
911
1092
|
}
|
|
912
1093
|
|
|
1094
|
+
const initialAcceptanceOutput = acceptanceOutputByResult.get(result) ?? result.finalOutput ?? "";
|
|
1095
|
+
const acceptanceForInitialReport = shouldRunAcceptanceFinalization(effectiveAcceptance)
|
|
1096
|
+
? acceptanceSelfReviewConfig(effectiveAcceptance)
|
|
1097
|
+
: effectiveAcceptance;
|
|
1098
|
+
const initialAcceptance = await evaluateAcceptance({
|
|
1099
|
+
acceptance: acceptanceForInitialReport,
|
|
1100
|
+
output: initialAcceptanceOutput,
|
|
1101
|
+
cwd: options.cwd ?? runtimeCwd,
|
|
1102
|
+
});
|
|
1103
|
+
result.acceptance = initialAcceptance;
|
|
1104
|
+
if (shouldRunAcceptanceFinalization(effectiveAcceptance) && result.exitCode === 0 && !result.detached && !result.interrupted) {
|
|
1105
|
+
result.acceptance = await runAcceptanceFinalizationLoop({
|
|
1106
|
+
runtimeCwd,
|
|
1107
|
+
agent,
|
|
1108
|
+
result,
|
|
1109
|
+
initialLedger: initialAcceptance,
|
|
1110
|
+
initialOutput: initialAcceptanceOutput,
|
|
1111
|
+
acceptance: effectiveAcceptance,
|
|
1112
|
+
options,
|
|
1113
|
+
systemPrompt,
|
|
1114
|
+
resolvedSkillNames: resolvedSkills.length > 0 ? resolvedSkills.map((skill) => skill.name) : undefined,
|
|
1115
|
+
...(missingSkills.length > 0 ? { skillsWarning: `Skills not found: ${missingSkills.join(", ")}` } : {}),
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
const acceptanceFailure = acceptanceFailureMessage(result.acceptance);
|
|
1119
|
+
stripAcceptanceReportsFromMessages(result.messages);
|
|
1120
|
+
if (acceptanceFailure && result.acceptance.explicit && result.exitCode === 0 && !result.detached && !result.interrupted) {
|
|
1121
|
+
result.exitCode = 1;
|
|
1122
|
+
result.error = result.error ? `${result.error}\n${acceptanceFailure}` : acceptanceFailure;
|
|
1123
|
+
if (result.progress) {
|
|
1124
|
+
result.progress.status = "failed";
|
|
1125
|
+
result.progress.error = result.error;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
913
1129
|
return result;
|
|
914
1130
|
}
|