pi-subagents 0.30.0 → 0.31.1
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 +38 -0
- package/README.md +189 -18
- package/agents/context-builder.md +3 -3
- package/agents/planner.md +1 -1
- package/agents/researcher.md +1 -1
- package/agents/scout.md +1 -1
- package/package.json +7 -7
- package/skills/pi-subagents/SKILL.md +5 -0
- package/src/agents/agent-management.ts +170 -6
- package/src/agents/agent-serializer.ts +31 -13
- package/src/agents/agents.ts +207 -23
- package/src/agents/frontmatter.ts +66 -2
- package/src/agents/skills.ts +117 -20
- package/src/extension/doctor.ts +20 -0
- package/src/extension/fanout-child.ts +1 -0
- package/src/extension/index.ts +58 -4
- package/src/extension/schemas.ts +10 -76
- package/src/intercom/intercom-bridge.ts +27 -4
- package/src/profiles/profiles.ts +637 -0
- package/src/runs/background/async-execution.ts +14 -4
- package/src/runs/background/async-job-tracker.ts +56 -11
- package/src/runs/background/async-resume.ts +11 -13
- package/src/runs/background/control-channel.ts +177 -0
- package/src/runs/background/result-watcher.ts +11 -2
- package/src/runs/background/stale-run-reconciler.ts +9 -4
- package/src/runs/background/subagent-runner.ts +86 -3
- package/src/runs/foreground/chain-execution.ts +26 -2
- package/src/runs/foreground/execution.ts +113 -8
- package/src/runs/foreground/subagent-executor.ts +356 -86
- package/src/runs/shared/acceptance.ts +285 -34
- package/src/runs/shared/completion-guard.ts +1 -1
- package/src/runs/shared/dynamic-fanout.ts +4 -2
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +2 -2
- package/src/runs/shared/parallel-utils.ts +6 -1
- package/src/runs/shared/pi-args.ts +9 -1
- package/src/runs/shared/single-output.ts +15 -1
- package/src/runs/shared/subagent-prompt-runtime.ts +1 -0
- package/src/shared/settings.ts +1 -0
- package/src/shared/types.ts +9 -2
- package/src/shared/utils.ts +19 -1
- package/src/slash/prompt-template-bridge.ts +26 -3
- package/src/slash/slash-commands.ts +642 -43
- package/src/tui/render.ts +265 -13
|
@@ -102,6 +102,7 @@ interface ParallelChainRunInput {
|
|
|
102
102
|
globalTaskIndex: number;
|
|
103
103
|
sessionDirForIndex: (idx?: number) => string | undefined;
|
|
104
104
|
sessionFileForIndex?: (idx?: number) => string | undefined;
|
|
105
|
+
sessionFileForTask?: (agentName: string, idx?: number) => string | undefined;
|
|
105
106
|
shareEnabled: boolean;
|
|
106
107
|
artifactConfig: ArtifactConfig;
|
|
107
108
|
artifactsDir: string;
|
|
@@ -136,6 +137,8 @@ interface ParallelChainRunInput {
|
|
|
136
137
|
worktreeSetup?: WorktreeSetup;
|
|
137
138
|
maxSubagentDepth: number;
|
|
138
139
|
nestedRoute?: NestedRouteInfo;
|
|
140
|
+
timeoutMs?: number;
|
|
141
|
+
deadlineAt?: number;
|
|
139
142
|
}
|
|
140
143
|
|
|
141
144
|
function buildChainExecutionDetails(input: ChainExecutionDetailsInput): Details {
|
|
@@ -266,6 +269,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
266
269
|
? createStructuredOutputRuntime(task.outputSchema, path.join(input.chainDir, "structured-output"))
|
|
267
270
|
: undefined;
|
|
268
271
|
const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskStr, {
|
|
272
|
+
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
269
273
|
cwd: taskCwd,
|
|
270
274
|
signal: input.signal,
|
|
271
275
|
interruptSignal: interruptController.signal,
|
|
@@ -274,7 +278,8 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
274
278
|
runId: input.runId,
|
|
275
279
|
index: input.globalTaskIndex + taskIndex,
|
|
276
280
|
sessionDir: input.sessionDirForIndex(input.globalTaskIndex + taskIndex),
|
|
277
|
-
sessionFile: input.
|
|
281
|
+
sessionFile: input.sessionFileForTask?.(task.agent, input.globalTaskIndex + taskIndex)
|
|
282
|
+
?? input.sessionFileForIndex?.(input.globalTaskIndex + taskIndex),
|
|
278
283
|
share: input.shareEnabled,
|
|
279
284
|
artifactsDir: input.artifactConfig.enabled ? input.artifactsDir : undefined,
|
|
280
285
|
artifactConfig: input.artifactConfig,
|
|
@@ -293,6 +298,8 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
293
298
|
structuredOutput: structuredRuntime,
|
|
294
299
|
acceptance: task.acceptance,
|
|
295
300
|
acceptanceContext: { mode: "chain" },
|
|
301
|
+
timeoutMs: input.timeoutMs,
|
|
302
|
+
deadlineAt: input.deadlineAt,
|
|
296
303
|
onUpdate: input.onUpdate
|
|
297
304
|
? (progressUpdate) => {
|
|
298
305
|
const stepResults = progressUpdate.details?.results || [];
|
|
@@ -365,6 +372,7 @@ interface ChainExecutionParams {
|
|
|
365
372
|
shareEnabled: boolean;
|
|
366
373
|
sessionDirForIndex: (idx?: number) => string | undefined;
|
|
367
374
|
sessionFileForIndex?: (idx?: number) => string | undefined;
|
|
375
|
+
sessionFileForTask?: (agentName: string, idx?: number) => string | undefined;
|
|
368
376
|
artifactsDir: string;
|
|
369
377
|
artifactConfig: ArtifactConfig;
|
|
370
378
|
includeProgress?: boolean;
|
|
@@ -395,6 +403,8 @@ interface ChainExecutionParams {
|
|
|
395
403
|
nestedRoute?: NestedRouteInfo;
|
|
396
404
|
worktreeSetupHook?: string;
|
|
397
405
|
worktreeSetupHookTimeoutMs?: number;
|
|
406
|
+
timeoutMs?: number;
|
|
407
|
+
deadlineAt?: number;
|
|
398
408
|
}
|
|
399
409
|
|
|
400
410
|
interface ChainExecutionResult {
|
|
@@ -422,6 +432,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
422
432
|
shareEnabled,
|
|
423
433
|
sessionDirForIndex,
|
|
424
434
|
sessionFileForIndex,
|
|
435
|
+
sessionFileForTask,
|
|
425
436
|
artifactsDir,
|
|
426
437
|
artifactConfig,
|
|
427
438
|
includeProgress,
|
|
@@ -584,6 +595,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
584
595
|
tuiBehaviorOverrides = result.behaviorOverrides;
|
|
585
596
|
}
|
|
586
597
|
|
|
598
|
+
const deadlineAt = params.deadlineAt ?? (params.timeoutMs !== undefined ? Date.now() + params.timeoutMs : undefined);
|
|
587
599
|
let prev = "";
|
|
588
600
|
let globalTaskIndex = 0;
|
|
589
601
|
let progressCreated = false;
|
|
@@ -649,6 +661,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
649
661
|
globalTaskIndex,
|
|
650
662
|
sessionDirForIndex,
|
|
651
663
|
sessionFileForIndex,
|
|
664
|
+
sessionFileForTask,
|
|
652
665
|
shareEnabled,
|
|
653
666
|
artifactConfig,
|
|
654
667
|
artifactsDir,
|
|
@@ -670,6 +683,8 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
670
683
|
nestedRoute: params.nestedRoute,
|
|
671
684
|
worktreeSetup,
|
|
672
685
|
maxSubagentDepth: params.maxSubagentDepth,
|
|
686
|
+
timeoutMs: params.timeoutMs,
|
|
687
|
+
deadlineAt,
|
|
673
688
|
});
|
|
674
689
|
globalTaskIndex += step.parallel.length;
|
|
675
690
|
|
|
@@ -739,6 +754,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
739
754
|
output: getSingleResultOutput(result),
|
|
740
755
|
exitCode: result.exitCode,
|
|
741
756
|
error: result.error,
|
|
757
|
+
timedOut: result.timedOut,
|
|
742
758
|
outputTargetPath,
|
|
743
759
|
outputTargetExists: outputTargetPath ? fs.existsSync(outputTargetPath) : undefined,
|
|
744
760
|
};
|
|
@@ -855,6 +871,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
855
871
|
globalTaskIndex,
|
|
856
872
|
sessionDirForIndex,
|
|
857
873
|
sessionFileForIndex,
|
|
874
|
+
sessionFileForTask,
|
|
858
875
|
shareEnabled,
|
|
859
876
|
artifactConfig,
|
|
860
877
|
artifactsDir,
|
|
@@ -875,6 +892,8 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
875
892
|
foregroundControl,
|
|
876
893
|
nestedRoute: params.nestedRoute,
|
|
877
894
|
maxSubagentDepth: params.maxSubagentDepth,
|
|
895
|
+
timeoutMs: params.timeoutMs,
|
|
896
|
+
deadlineAt,
|
|
878
897
|
});
|
|
879
898
|
globalTaskIndex += dynamicParallelStep.parallel.length;
|
|
880
899
|
|
|
@@ -970,6 +989,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
970
989
|
output: getSingleResultOutput(result),
|
|
971
990
|
exitCode: result.exitCode,
|
|
972
991
|
error: result.error,
|
|
992
|
+
timedOut: result.timedOut,
|
|
973
993
|
}));
|
|
974
994
|
prev = aggregateParallelOutputs(taskResults, (i, agent) => `=== Dynamic Item ${i + 1} (${agent}, key ${materialized.items[i]?.key ?? i}) ===`);
|
|
975
995
|
} else {
|
|
@@ -1054,6 +1074,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1054
1074
|
? createStructuredOutputRuntime(seqStep.outputSchema, path.join(chainDir, "structured-output"))
|
|
1055
1075
|
: undefined;
|
|
1056
1076
|
const r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
|
|
1077
|
+
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
1057
1078
|
cwd: resolveChildCwd(cwd ?? ctx.cwd, seqStep.cwd),
|
|
1058
1079
|
signal,
|
|
1059
1080
|
interruptSignal: interruptController.signal,
|
|
@@ -1062,7 +1083,8 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1062
1083
|
runId,
|
|
1063
1084
|
index: globalTaskIndex,
|
|
1064
1085
|
sessionDir: sessionDirForIndex(globalTaskIndex),
|
|
1065
|
-
sessionFile:
|
|
1086
|
+
sessionFile: sessionFileForTask?.(seqStep.agent, globalTaskIndex)
|
|
1087
|
+
?? sessionFileForIndex?.(globalTaskIndex),
|
|
1066
1088
|
share: shareEnabled,
|
|
1067
1089
|
artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
|
|
1068
1090
|
artifactConfig,
|
|
@@ -1081,6 +1103,8 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
|
|
|
1081
1103
|
structuredOutput: structuredRuntime,
|
|
1082
1104
|
acceptance: seqStep.acceptance,
|
|
1083
1105
|
acceptanceContext: { mode: "chain" },
|
|
1106
|
+
timeoutMs: params.timeoutMs,
|
|
1107
|
+
deadlineAt,
|
|
1084
1108
|
onUpdate: onUpdate
|
|
1085
1109
|
? (p) => {
|
|
1086
1110
|
const stepResults = p.details?.results || [];
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
DEFAULT_MAX_OUTPUT,
|
|
24
24
|
INTERCOM_DETACH_REQUEST_EVENT,
|
|
25
25
|
INTERCOM_DETACH_RESPONSE_EVENT,
|
|
26
|
+
type AcceptanceLedger,
|
|
27
|
+
type ResolvedAcceptanceConfig,
|
|
26
28
|
truncateOutput,
|
|
27
29
|
getSubagentDepthEnv,
|
|
28
30
|
} from "../../shared/types.ts";
|
|
@@ -47,7 +49,7 @@ import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
|
|
|
47
49
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
48
50
|
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
|
|
49
51
|
import { readStructuredOutput } from "../shared/structured-output.ts";
|
|
50
|
-
import { captureSingleOutputSnapshot, formatSavedOutputReference, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
52
|
+
import { captureSingleOutputSnapshot, formatSavedOutputReference, injectOutputPathSystemPrompt, resolveSingleOutput, validateFileOnlyOutputMode, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
51
53
|
import {
|
|
52
54
|
buildModelCandidates,
|
|
53
55
|
formatModelAttemptNote,
|
|
@@ -82,6 +84,34 @@ function sumUsage(target: Usage, source: Usage): void {
|
|
|
82
84
|
target.turns += source.turns;
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
function formatTimeoutMessage(timeoutMs: number): string {
|
|
88
|
+
return `Subagent timed out after ${timeoutMs}ms.`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function resolveAttemptTimeout(options: RunSyncOptions): { timeoutMs: number; remainingMs: number; message: string } | undefined {
|
|
92
|
+
if (options.timeoutMs === undefined) return undefined;
|
|
93
|
+
const deadlineAt = options.deadlineAt ?? Date.now() + options.timeoutMs;
|
|
94
|
+
return {
|
|
95
|
+
timeoutMs: options.timeoutMs,
|
|
96
|
+
remainingMs: Math.max(0, deadlineAt - Date.now()),
|
|
97
|
+
message: formatTimeoutMessage(options.timeoutMs),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function buildTimedOutAcceptanceLedger(acceptance: ResolvedAcceptanceConfig): AcceptanceLedger {
|
|
102
|
+
return {
|
|
103
|
+
status: acceptance.level === "none" ? "not-required" : "rejected",
|
|
104
|
+
explicit: acceptance.explicit,
|
|
105
|
+
effectiveAcceptance: acceptance,
|
|
106
|
+
inferredReason: acceptance.inferredReason,
|
|
107
|
+
criteria: acceptance.criteria,
|
|
108
|
+
runtimeChecks: acceptance.level === "none"
|
|
109
|
+
? []
|
|
110
|
+
: [{ id: "timeout", status: "failed", message: "Acceptance was not evaluated because the subagent timed out." }],
|
|
111
|
+
verifyRuns: [],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
85
115
|
function appendRecentOutput(progress: AgentProgress, lines: string[]): void {
|
|
86
116
|
if (lines.length === 0) return;
|
|
87
117
|
progress.recentOutput.push(...lines.filter((line) => line.trim()));
|
|
@@ -162,6 +192,7 @@ async function runSingleAttempt(
|
|
|
162
192
|
systemPromptMode: agent.systemPromptMode,
|
|
163
193
|
inheritProjectContext: agent.inheritProjectContext,
|
|
164
194
|
inheritSkills: agent.inheritSkills,
|
|
195
|
+
requireReadTool: Boolean(shared.resolvedSkillNames?.length),
|
|
165
196
|
tools: agent.tools,
|
|
166
197
|
extensions: agent.extensions,
|
|
167
198
|
subagentOnlyExtensions: agent.subagentOnlyExtensions,
|
|
@@ -178,6 +209,7 @@ async function runSingleAttempt(
|
|
|
178
209
|
parentControlInbox: options.nestedRoute?.controlInbox,
|
|
179
210
|
parentRootRunId: options.nestedRoute?.rootRunId,
|
|
180
211
|
parentCapabilityToken: options.nestedRoute?.capabilityToken,
|
|
212
|
+
parentSessionId: options.parentSessionId,
|
|
181
213
|
structuredOutput: options.structuredOutput,
|
|
182
214
|
});
|
|
183
215
|
|
|
@@ -227,6 +259,21 @@ async function runSingleAttempt(
|
|
|
227
259
|
lastActivityAt: startTime,
|
|
228
260
|
};
|
|
229
261
|
result.progress = progress;
|
|
262
|
+
const attemptTimeout = resolveAttemptTimeout(options);
|
|
263
|
+
if (attemptTimeout?.remainingMs === 0) {
|
|
264
|
+
result.exitCode = 1;
|
|
265
|
+
result.timedOut = true;
|
|
266
|
+
result.error = attemptTimeout.message;
|
|
267
|
+
result.finalOutput = attemptTimeout.message;
|
|
268
|
+
progress.status = "failed";
|
|
269
|
+
progress.error = attemptTimeout.message;
|
|
270
|
+
result.progressSummary = {
|
|
271
|
+
toolCount: progress.toolCount,
|
|
272
|
+
tokens: progress.tokens,
|
|
273
|
+
durationMs: progress.durationMs,
|
|
274
|
+
};
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
230
277
|
const spawnEnv = { ...process.env, ...sharedEnv, ...getSubagentDepthEnv(options.maxSubagentDepth) };
|
|
231
278
|
let observedMutationAttempt = false;
|
|
232
279
|
|
|
@@ -248,6 +295,23 @@ async function runSingleAttempt(
|
|
|
248
295
|
let removeAbortListener: (() => void) | undefined;
|
|
249
296
|
let removeInterruptListener: (() => void) | undefined;
|
|
250
297
|
let activityTimer: NodeJS.Timeout | undefined;
|
|
298
|
+
let timeoutTimer: NodeJS.Timeout | undefined;
|
|
299
|
+
let timeoutTerminationTimer: NodeJS.Timeout | undefined;
|
|
300
|
+
let timeoutHardKillTimer: NodeJS.Timeout | undefined;
|
|
301
|
+
const clearTimeoutTimers = () => {
|
|
302
|
+
if (timeoutTimer) {
|
|
303
|
+
clearTimeout(timeoutTimer);
|
|
304
|
+
timeoutTimer = undefined;
|
|
305
|
+
}
|
|
306
|
+
if (timeoutTerminationTimer) {
|
|
307
|
+
clearTimeout(timeoutTerminationTimer);
|
|
308
|
+
timeoutTerminationTimer = undefined;
|
|
309
|
+
}
|
|
310
|
+
if (timeoutHardKillTimer) {
|
|
311
|
+
clearTimeout(timeoutHardKillTimer);
|
|
312
|
+
timeoutHardKillTimer = undefined;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
251
315
|
|
|
252
316
|
const detachForIntercom = () => {
|
|
253
317
|
detached = true;
|
|
@@ -316,6 +380,7 @@ async function runSingleAttempt(
|
|
|
316
380
|
settled = true;
|
|
317
381
|
clearFinalDrainTimers();
|
|
318
382
|
clearStdioGuard();
|
|
383
|
+
clearTimeoutTimers();
|
|
319
384
|
if (activityTimer) {
|
|
320
385
|
clearInterval(activityTimer);
|
|
321
386
|
activityTimer = undefined;
|
|
@@ -429,7 +494,8 @@ async function runSingleAttempt(
|
|
|
429
494
|
const fireUpdate = () => {
|
|
430
495
|
if (!options.onUpdate || processClosed) return;
|
|
431
496
|
progress.durationMs = Date.now() - startTime;
|
|
432
|
-
|
|
497
|
+
const output = result.timedOut && result.finalOutput ? result.finalOutput : getFinalOutput(result.messages);
|
|
498
|
+
emitUpdateSnapshot(output || "(running...)");
|
|
433
499
|
};
|
|
434
500
|
|
|
435
501
|
const processLine = (line: string) => {
|
|
@@ -555,6 +621,31 @@ async function runSingleAttempt(
|
|
|
555
621
|
activityTimer.unref?.();
|
|
556
622
|
}
|
|
557
623
|
|
|
624
|
+
if (attemptTimeout) {
|
|
625
|
+
timeoutTimer = setTimeout(() => {
|
|
626
|
+
if (processClosed || settled || detached || interruptedByControl) return;
|
|
627
|
+
result.timedOut = true;
|
|
628
|
+
result.error = attemptTimeout.message;
|
|
629
|
+
result.finalOutput = attemptTimeout.message;
|
|
630
|
+
progress.status = "failed";
|
|
631
|
+
progress.error = attemptTimeout.message;
|
|
632
|
+
progress.durationMs = Date.now() - startTime;
|
|
633
|
+
fireUpdate();
|
|
634
|
+
trySignalChild(proc, "SIGINT");
|
|
635
|
+
timeoutTerminationTimer = setTimeout(() => {
|
|
636
|
+
if (processClosed || settled || detached) return;
|
|
637
|
+
trySignalChild(proc, "SIGTERM");
|
|
638
|
+
}, 1000);
|
|
639
|
+
timeoutTerminationTimer.unref?.();
|
|
640
|
+
timeoutHardKillTimer = setTimeout(() => {
|
|
641
|
+
if (processClosed || settled || detached) return;
|
|
642
|
+
trySignalChild(proc, "SIGKILL");
|
|
643
|
+
}, 4000);
|
|
644
|
+
timeoutHardKillTimer.unref?.();
|
|
645
|
+
}, attemptTimeout.remainingMs);
|
|
646
|
+
timeoutTimer.unref?.();
|
|
647
|
+
}
|
|
648
|
+
|
|
558
649
|
let stderrBuf = "";
|
|
559
650
|
|
|
560
651
|
const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
|
|
@@ -625,7 +716,9 @@ async function runSingleAttempt(
|
|
|
625
716
|
if (options.interruptSignal) {
|
|
626
717
|
const interrupt = () => {
|
|
627
718
|
if (processClosed || detached || settled) return;
|
|
719
|
+
if (result.timedOut) return;
|
|
628
720
|
interruptedByControl = true;
|
|
721
|
+
clearTimeoutTimers();
|
|
629
722
|
progress.status = "running";
|
|
630
723
|
progress.durationMs = Date.now() - startTime;
|
|
631
724
|
result.interrupted = true;
|
|
@@ -710,8 +803,14 @@ async function runSingleAttempt(
|
|
|
710
803
|
durationMs: progress.durationMs,
|
|
711
804
|
};
|
|
712
805
|
|
|
713
|
-
|
|
714
|
-
|
|
806
|
+
const acceptanceOutput = getFinalOutput(result.messages);
|
|
807
|
+
let fullOutput = stripAcceptanceReport(acceptanceOutput);
|
|
808
|
+
if (result.timedOut) {
|
|
809
|
+
const timeoutMessage = formatTimeoutMessage(options.timeoutMs ?? 0);
|
|
810
|
+
fullOutput = fullOutput.trim()
|
|
811
|
+
? `${timeoutMessage}\n\nPartial output before timeout:\n${fullOutput}`
|
|
812
|
+
: timeoutMessage;
|
|
813
|
+
}
|
|
715
814
|
const completionGuard = result.exitCode === 0 && !result.error && agent.completionGuard !== false
|
|
716
815
|
? evaluateCompletionMutationGuard({
|
|
717
816
|
agent: agent.name,
|
|
@@ -835,6 +934,7 @@ export async function runSync(
|
|
|
835
934
|
const skillInjection = buildSkillInjection(resolvedSkills);
|
|
836
935
|
systemPrompt = systemPrompt ? `${systemPrompt}\n\n${skillInjection}` : skillInjection;
|
|
837
936
|
}
|
|
937
|
+
systemPrompt = injectOutputPathSystemPrompt(systemPrompt, options.outputPath);
|
|
838
938
|
|
|
839
939
|
const candidates = buildModelCandidates(
|
|
840
940
|
options.modelOverride ?? agent.model,
|
|
@@ -892,6 +992,9 @@ export async function runSync(
|
|
|
892
992
|
usage: { ...result.usage },
|
|
893
993
|
};
|
|
894
994
|
modelAttempts.push(attempt);
|
|
995
|
+
if (result.timedOut) {
|
|
996
|
+
break;
|
|
997
|
+
}
|
|
895
998
|
if (attemptSucceeded) {
|
|
896
999
|
break;
|
|
897
1000
|
}
|
|
@@ -967,14 +1070,16 @@ export async function runSync(
|
|
|
967
1070
|
if (sessionFile) result.sessionFile = sessionFile;
|
|
968
1071
|
}
|
|
969
1072
|
|
|
970
|
-
|
|
1073
|
+
result.acceptance = result.timedOut
|
|
1074
|
+
? buildTimedOutAcceptanceLedger(effectiveAcceptance)
|
|
1075
|
+
: await evaluateAcceptance({
|
|
971
1076
|
acceptance: effectiveAcceptance,
|
|
972
1077
|
output: acceptanceOutputByResult.get(result) ?? result.finalOutput ?? "",
|
|
973
1078
|
cwd: options.cwd ?? runtimeCwd,
|
|
974
1079
|
});
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1080
|
+
const acceptanceFailure = acceptanceFailureMessage(result.acceptance);
|
|
1081
|
+
stripAcceptanceReportsFromMessages(result.messages);
|
|
1082
|
+
if (acceptanceFailure && result.acceptance.explicit && result.exitCode === 0 && !result.detached && !result.interrupted && !result.timedOut) {
|
|
978
1083
|
result.exitCode = 1;
|
|
979
1084
|
result.error = result.error ? `${result.error}\n${acceptanceFailure}` : acceptanceFailure;
|
|
980
1085
|
if (result.progress) {
|