pi-subagents 0.36.0 → 0.37.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 +17 -0
- package/README.md +93 -8
- package/agents/delegate.md +2 -0
- package/agents/worker.md +2 -0
- package/package.json +4 -2
- package/skills/pi-subagents/SKILL.md +20 -4
- package/src/agents/agent-management.ts +7 -1
- package/src/agents/agents.ts +99 -12
- package/src/api/capability-ceiling.ts +17 -0
- package/src/api/delegation.ts +3 -1
- package/src/api/preflight.ts +399 -0
- package/src/extension/index.ts +2 -0
- package/src/extension/rpc.ts +4 -0
- package/src/extension/schemas.ts +8 -2
- package/src/extension/tool-description.ts +2 -0
- package/src/runs/background/async-execution.ts +125 -14
- package/src/runs/background/async-resume.ts +24 -7
- package/src/runs/background/async-status.ts +18 -0
- package/src/runs/background/process-terminal.ts +280 -0
- package/src/runs/background/run-status.ts +7 -1
- package/src/runs/background/scheduled-runs.ts +6 -1
- package/src/runs/background/stale-run-reconciler.ts +6 -0
- package/src/runs/background/subagent-runner.ts +182 -12
- package/src/runs/foreground/chain-execution.ts +5 -0
- package/src/runs/foreground/execution.ts +59 -13
- package/src/runs/foreground/subagent-executor.ts +32 -2
- package/src/runs/shared/acceptance.ts +41 -30
- package/src/runs/shared/capability-ceiling.ts +177 -0
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
- package/src/runs/shared/nested-events.ts +8 -1
- package/src/runs/shared/parallel-utils.ts +5 -0
- package/src/runs/shared/pi-args.ts +141 -58
- package/src/runs/shared/session-lease.ts +25 -5
- package/src/runs/shared/subagent-prompt-runtime.ts +14 -1
- package/src/runs/shared/tool-availability.ts +18 -2
- package/src/shared/launch-contract.ts +123 -0
- package/src/shared/types.ts +104 -7
- package/src/shared/utils.ts +17 -42
- package/src/slash/delegation-adapters.ts +1 -1
- package/src/slash/slash-commands.ts +1 -1
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
6
7
|
import * as fs from "node:fs";
|
|
7
8
|
import * as os from "node:os";
|
|
8
9
|
import * as path from "node:path";
|
|
@@ -11,7 +12,7 @@ import { createRequire } from "node:module";
|
|
|
11
12
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
12
13
|
import type { AgentConfig } from "../../agents/agents.ts";
|
|
13
14
|
import { writePrivateAtomicJson } from "../../shared/atomic-json.ts";
|
|
14
|
-
import { applyThinkingSuffix } from "../shared/pi-args.ts";
|
|
15
|
+
import { applyThinkingSuffix, resolvePiLaunchToolPlan } from "../shared/pi-args.ts";
|
|
15
16
|
import { injectOutputPathSystemPrompt, injectSingleOutputInstruction, normalizeSingleOutputOverride, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
|
|
16
17
|
import { buildChainInstructions, isDynamicParallelStep, isParallelStep, resolveStepBehavior, suppressProgressForReadOnlyTask, writeInitialProgressFile, type ChainStep, type ResolvedStepBehavior, type SequentialStep, type StepOverrides } from "../../shared/settings.ts";
|
|
17
18
|
import type { RunnerStep } from "../shared/parallel-utils.ts";
|
|
@@ -49,11 +50,15 @@ import {
|
|
|
49
50
|
getAsyncConfigPath,
|
|
50
51
|
resolveChildMaxSubagentDepth,
|
|
51
52
|
} from "../../shared/types.ts";
|
|
52
|
-
import { nestedResultsPath, resolveInheritedNestedRouteFromEnv, resolveNestedParentAddressFromEnv, writeNestedEvent } from "../shared/nested-events.ts";
|
|
53
|
-
import { initialTurnBudgetState } from "../shared/turn-budget.ts";
|
|
53
|
+
import { nestedResultsPath, nestedSummaryFromAsyncStatus, resolveInheritedNestedRouteFromEnv, resolveNestedParentAddressFromEnv, writeNestedEvent } from "../shared/nested-events.ts";
|
|
54
|
+
import { appendTurnBudgetSystemPrompt, initialTurnBudgetState } from "../shared/turn-budget.ts";
|
|
54
55
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
55
56
|
import type { ImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
56
57
|
import type { SessionLeaseRequest } from "../shared/session-lease.ts";
|
|
58
|
+
import { finalizeProcessTerminal, readProcessTerminal } from "./process-terminal.ts";
|
|
59
|
+
import { SUBAGENT_PROCESS_TERMINAL_EVENT } from "../../shared/types.ts";
|
|
60
|
+
import { decodeSubagentCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
61
|
+
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
57
62
|
|
|
58
63
|
const require = createRequire(import.meta.url);
|
|
59
64
|
const piPackageRoot = resolvePiPackageRoot();
|
|
@@ -157,6 +162,7 @@ interface AsyncChainParams {
|
|
|
157
162
|
configToolBudget?: ResolvedToolBudget;
|
|
158
163
|
/** Global cap on simultaneously-running subagent tasks within the async run. */
|
|
159
164
|
globalConcurrencyLimit?: number;
|
|
165
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
interface AsyncSingleParams {
|
|
@@ -200,6 +206,7 @@ interface AsyncSingleParams {
|
|
|
200
206
|
turnBudget?: ResolvedTurnBudget;
|
|
201
207
|
toolBudget?: ResolvedToolBudget;
|
|
202
208
|
configToolBudget?: ResolvedToolBudget;
|
|
209
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
203
210
|
}
|
|
204
211
|
|
|
205
212
|
interface AsyncExecutionResult {
|
|
@@ -232,6 +239,7 @@ export interface AsyncRunnerStepBuildParams {
|
|
|
232
239
|
validateOutputBindings?: boolean;
|
|
233
240
|
toolBudget?: ResolvedToolBudget;
|
|
234
241
|
configToolBudget?: ResolvedToolBudget;
|
|
242
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
235
243
|
}
|
|
236
244
|
|
|
237
245
|
export type AsyncRunnerStepBuildResult =
|
|
@@ -397,7 +405,7 @@ function terminateRunnerBeforeProceed(pid: number): void {
|
|
|
397
405
|
}
|
|
398
406
|
}
|
|
399
407
|
|
|
400
|
-
function spawnRunner(cfg: object, suffix: string, cwd: string): { pid?: number; error?: string } {
|
|
408
|
+
function spawnRunner(cfg: object, suffix: string, cwd: string, onProcessTerminal?: (proof: unknown) => void): { pid?: number; error?: string } {
|
|
401
409
|
if (!jitiCliPath) {
|
|
402
410
|
return { error: "upstream jiti for TypeScript execution could not be found; ensure package dependencies are installed" };
|
|
403
411
|
}
|
|
@@ -413,12 +421,14 @@ function spawnRunner(cfg: object, suffix: string, cwd: string): { pid?: number;
|
|
|
413
421
|
|
|
414
422
|
fs.mkdirSync(TEMP_ROOT_DIR, { recursive: true });
|
|
415
423
|
const cfgPath = getAsyncConfigPath(suffix);
|
|
416
|
-
|
|
424
|
+
const runnerProcessInstanceId = randomUUID();
|
|
425
|
+
const launchConfig = { ...cfg, runnerProcessInstanceId };
|
|
426
|
+
fs.writeFileSync(cfgPath, JSON.stringify(launchConfig));
|
|
417
427
|
const runner = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-runner.ts");
|
|
418
428
|
const nodeCommand = resolveAsyncRunnerNodeCommand();
|
|
419
|
-
const startupPath = typeof (
|
|
420
|
-
&& typeof (
|
|
421
|
-
? path.join((
|
|
429
|
+
const startupPath = typeof (launchConfig as { revivalLease?: unknown; asyncDir?: unknown }).revivalLease === "object"
|
|
430
|
+
&& typeof (launchConfig as { asyncDir?: unknown }).asyncDir === "string"
|
|
431
|
+
? path.join((launchConfig as { asyncDir: string }).asyncDir, "runner-startup.json")
|
|
422
432
|
: undefined;
|
|
423
433
|
const startupAckPath = startupPath ? path.join(path.dirname(startupPath), "runner-startup-ack.json") : undefined;
|
|
424
434
|
const startupProceedPath = startupPath ? path.join(path.dirname(startupPath), "runner-startup-proceed.json") : undefined;
|
|
@@ -426,7 +436,7 @@ function spawnRunner(cfg: object, suffix: string, cwd: string): { pid?: number;
|
|
|
426
436
|
if (startupAckPath) fs.rmSync(startupAckPath, { force: true });
|
|
427
437
|
if (startupProceedPath) fs.rmSync(startupProceedPath, { force: true });
|
|
428
438
|
|
|
429
|
-
const logPaths = resolveAsyncRunnerLogPaths(
|
|
439
|
+
const logPaths = resolveAsyncRunnerLogPaths(launchConfig);
|
|
430
440
|
let stdoutFd: number | undefined;
|
|
431
441
|
let stderrFd: number | undefined;
|
|
432
442
|
try {
|
|
@@ -450,6 +460,56 @@ function spawnRunner(cfg: object, suffix: string, cwd: string): { pid?: number;
|
|
|
450
460
|
proc.on("error", (error) => {
|
|
451
461
|
console.error(`[pi-subagents] async spawn failed: ${error.message}`);
|
|
452
462
|
});
|
|
463
|
+
proc.once("close", (exitCode, signal) => {
|
|
464
|
+
const launch = launchConfig as { asyncDir?: unknown; id?: unknown; nestedRoute?: NestedRouteInfo; nestedSelf?: { parentRunId: string; parentStepIndex?: number; depth: number; path?: Array<{ runId: string; stepIndex?: number; agent?: string }> } };
|
|
465
|
+
const asyncDir = launch.asyncDir;
|
|
466
|
+
const runId = launch.id;
|
|
467
|
+
if (typeof asyncDir !== "string" || typeof runId !== "string") return;
|
|
468
|
+
finalizeProcessTerminal(asyncDir, runId, {
|
|
469
|
+
processInstanceId: runnerProcessInstanceId,
|
|
470
|
+
closeObservedAt: Date.now(),
|
|
471
|
+
exitCode,
|
|
472
|
+
signal,
|
|
473
|
+
});
|
|
474
|
+
const persisted = readProcessTerminal(asyncDir, { runId, runnerProcessInstanceId });
|
|
475
|
+
if (!persisted) return;
|
|
476
|
+
if (launch.nestedRoute && launch.nestedSelf) {
|
|
477
|
+
try {
|
|
478
|
+
let status: import("../../shared/types.ts").AsyncStatus;
|
|
479
|
+
try {
|
|
480
|
+
status = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8")) as import("../../shared/types.ts").AsyncStatus;
|
|
481
|
+
status.processTerminal = persisted;
|
|
482
|
+
} catch {
|
|
483
|
+
status = {
|
|
484
|
+
runId,
|
|
485
|
+
mode: "single",
|
|
486
|
+
state: persisted.state === "observed" ? "complete" : "failed",
|
|
487
|
+
startedAt: persisted.observedAt ?? Date.now(),
|
|
488
|
+
lastUpdate: Date.now(),
|
|
489
|
+
processTerminal: persisted,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
writeNestedEvent(launch.nestedRoute, {
|
|
493
|
+
type: "subagent.nested.completed",
|
|
494
|
+
ts: Date.now(),
|
|
495
|
+
parentRunId: launch.nestedSelf.parentRunId,
|
|
496
|
+
parentStepIndex: launch.nestedSelf.parentStepIndex,
|
|
497
|
+
child: nestedSummaryFromAsyncStatus(status, asyncDir, {
|
|
498
|
+
id: runId,
|
|
499
|
+
parentRunId: launch.nestedSelf.parentRunId,
|
|
500
|
+
parentStepIndex: launch.nestedSelf.parentStepIndex,
|
|
501
|
+
depth: launch.nestedSelf.depth,
|
|
502
|
+
path: launch.nestedSelf.path,
|
|
503
|
+
mode: status.mode,
|
|
504
|
+
ts: Date.now(),
|
|
505
|
+
}),
|
|
506
|
+
});
|
|
507
|
+
} catch (error) {
|
|
508
|
+
console.error("Failed to emit final nested process-terminal status:", error);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
onProcessTerminal?.(persisted);
|
|
512
|
+
});
|
|
453
513
|
if (typeof proc.pid !== "number") {
|
|
454
514
|
return { error: `async runner did not produce a pid for cwd: ${cwd}` };
|
|
455
515
|
}
|
|
@@ -637,6 +697,7 @@ export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildPa
|
|
|
637
697
|
const agentContract = s.agentContract ?? params.agentContract;
|
|
638
698
|
return {
|
|
639
699
|
parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
|
|
700
|
+
...(params.capabilityCeiling ? { capabilityCeiling: params.capabilityCeiling } : {}),
|
|
640
701
|
agent: s.agent,
|
|
641
702
|
task,
|
|
642
703
|
...(params.contextForAgent ? { context: params.contextForAgent(s.agent) } : {}),
|
|
@@ -834,6 +895,7 @@ export function executeAsyncChain(
|
|
|
834
895
|
nestedRoute,
|
|
835
896
|
} = params;
|
|
836
897
|
const resultMode = params.resultMode ?? "chain";
|
|
898
|
+
const capabilityCeiling = params.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId);
|
|
837
899
|
const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
|
|
838
900
|
const nestedAddress = inheritedNestedRoute ? resolveNestedParentAddressFromEnv() : undefined;
|
|
839
901
|
const asyncDir = inheritedNestedRoute
|
|
@@ -873,6 +935,7 @@ export function executeAsyncChain(
|
|
|
873
935
|
asyncDir,
|
|
874
936
|
toolBudget: params.toolBudget,
|
|
875
937
|
configToolBudget: params.configToolBudget,
|
|
938
|
+
capabilityCeiling,
|
|
876
939
|
});
|
|
877
940
|
if ("error" in built) {
|
|
878
941
|
try {
|
|
@@ -917,6 +980,7 @@ export function executeAsyncChain(
|
|
|
917
980
|
sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
|
|
918
981
|
asyncDir,
|
|
919
982
|
sessionId: ctx.currentSessionId,
|
|
983
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
920
984
|
piPackageRoot,
|
|
921
985
|
piArgv1: process.argv[1],
|
|
922
986
|
worktreeSetupHook,
|
|
@@ -943,6 +1007,7 @@ export function executeAsyncChain(
|
|
|
943
1007
|
},
|
|
944
1008
|
id,
|
|
945
1009
|
runnerCwd,
|
|
1010
|
+
(proof) => ctx.pi.events.emit(SUBAGENT_PROCESS_TERMINAL_EVENT, proof),
|
|
946
1011
|
);
|
|
947
1012
|
} catch (error) {
|
|
948
1013
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1014,6 +1079,7 @@ export function executeAsyncChain(
|
|
|
1014
1079
|
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1015
1080
|
startedAt: now,
|
|
1016
1081
|
lastUpdate: now,
|
|
1082
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1017
1083
|
},
|
|
1018
1084
|
});
|
|
1019
1085
|
} catch (error) {
|
|
@@ -1040,6 +1106,7 @@ export function executeAsyncChain(
|
|
|
1040
1106
|
asyncDir,
|
|
1041
1107
|
...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}),
|
|
1042
1108
|
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1109
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1043
1110
|
nestedRoute,
|
|
1044
1111
|
});
|
|
1045
1112
|
}
|
|
@@ -1052,7 +1119,7 @@ export function executeAsyncChain(
|
|
|
1052
1119
|
|
|
1053
1120
|
return {
|
|
1054
1121
|
content: [{ type: "text", text: formatAsyncStartedMessage(`Async ${resultMode}: ${chainDesc} [${id}]`, ctx.interactive === true) }],
|
|
1055
|
-
details: { mode: resultMode, runId: id, results: [], asyncId: id, asyncDir, workflowGraph, ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}), ...(params.turnBudget ? { turnBudget: params.turnBudget } : {}), ...(params.toolBudget ? { toolBudget: params.toolBudget } : {}) },
|
|
1122
|
+
details: { mode: resultMode, runId: id, results: [], asyncId: id, asyncDir, workflowGraph, ...(capabilityCeiling ? { capabilityCeiling } : {}), ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}), ...(params.turnBudget ? { turnBudget: params.turnBudget } : {}), ...(params.toolBudget ? { toolBudget: params.toolBudget } : {}) },
|
|
1056
1123
|
};
|
|
1057
1124
|
}
|
|
1058
1125
|
|
|
@@ -1084,6 +1151,7 @@ export function executeAsyncSingle(
|
|
|
1084
1151
|
nestedRoute,
|
|
1085
1152
|
} = params;
|
|
1086
1153
|
const task = params.task ?? "";
|
|
1154
|
+
const capabilityCeiling = params.capabilityCeiling ?? resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId);
|
|
1087
1155
|
const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
|
|
1088
1156
|
const skillNames = params.skills ?? agentConfig.skills ?? [];
|
|
1089
1157
|
const availableModels = params.availableModels;
|
|
@@ -1149,6 +1217,39 @@ export function executeAsyncSingle(
|
|
|
1149
1217
|
const structuredOutput = params.structuredOutputSchema
|
|
1150
1218
|
? createStructuredOutputRuntime(params.structuredOutputSchema, path.join(asyncDir, "structured-output"))
|
|
1151
1219
|
: undefined;
|
|
1220
|
+
const modelCandidates = buildModelCandidates(primaryModel, agentConfig.fallbackModels, availableModels, ctx.currentModelProvider, { scope: ctx.modelScope }).map((candidate) =>
|
|
1221
|
+
applyThinkingSuffix(candidate, effectiveThinking, params.thinkingOverride !== undefined),
|
|
1222
|
+
);
|
|
1223
|
+
const effectiveSystemPrompt = appendTurnBudgetSystemPrompt(systemPrompt, params.turnBudget);
|
|
1224
|
+
const toolPlan = resolvePiLaunchToolPlan({
|
|
1225
|
+
tools: agentConfig.tools,
|
|
1226
|
+
extensions: agentConfig.extensions,
|
|
1227
|
+
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
1228
|
+
mcpDirectTools: agentConfig.mcpDirectTools,
|
|
1229
|
+
cwd: runnerCwd,
|
|
1230
|
+
requireReadTool: Boolean(resolvedSkills.length),
|
|
1231
|
+
structuredOutput: Boolean(params.structuredOutputSchema),
|
|
1232
|
+
capabilityCeiling,
|
|
1233
|
+
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
1234
|
+
});
|
|
1235
|
+
const launchContractDigest = launchBindingDigest({
|
|
1236
|
+
definitionDigest: agentDefinitionDigest(agentConfig),
|
|
1237
|
+
task,
|
|
1238
|
+
...(model ? { model } : {}),
|
|
1239
|
+
modelCandidates,
|
|
1240
|
+
...(resolveEffectiveThinking(model, effectiveThinking) ? { thinking: resolveEffectiveThinking(model, effectiveThinking) } : {}),
|
|
1241
|
+
systemPrompt: effectiveSystemPrompt,
|
|
1242
|
+
systemPromptMode: agentConfig.systemPromptMode,
|
|
1243
|
+
inheritProjectContext: agentConfig.inheritProjectContext,
|
|
1244
|
+
inheritSkills: agentConfig.inheritSkills,
|
|
1245
|
+
skills: resolvedSkills.map((skill) => skill.name),
|
|
1246
|
+
tools: toolPlan.effectiveToolAllowlist,
|
|
1247
|
+
extensions: toolPlan.extensionArgs,
|
|
1248
|
+
mcpDirectTools: toolPlan.effectiveMcpTools,
|
|
1249
|
+
...(outputPath ? { outputPath } : {}),
|
|
1250
|
+
outputMode,
|
|
1251
|
+
...(params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {}),
|
|
1252
|
+
});
|
|
1152
1253
|
const resolvedAcceptance = resolveEffectiveAcceptance({
|
|
1153
1254
|
explicit: params.acceptance,
|
|
1154
1255
|
agentName: agent,
|
|
@@ -1160,6 +1261,7 @@ export function executeAsyncSingle(
|
|
|
1160
1261
|
});
|
|
1161
1262
|
const recoveryDescriptor: SteeringRecoveryDescriptor = {
|
|
1162
1263
|
version: 1,
|
|
1264
|
+
launchContractDigest,
|
|
1163
1265
|
sourceRunId: id,
|
|
1164
1266
|
...(params.agentContract ? { agentContract: params.agentContract } : {}),
|
|
1165
1267
|
agent,
|
|
@@ -1195,6 +1297,7 @@ export function executeAsyncSingle(
|
|
|
1195
1297
|
...(resolvedSessionDir ? { sessionDir: resolvedSessionDir } : {}),
|
|
1196
1298
|
...(artifactsDir ? { artifactsDir } : {}),
|
|
1197
1299
|
artifactConfig,
|
|
1300
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1198
1301
|
};
|
|
1199
1302
|
try {
|
|
1200
1303
|
writePrivateAtomicJson(path.join(asyncDir, "recovery-descriptor.json"), recoveryDescriptor);
|
|
@@ -1209,15 +1312,14 @@ export function executeAsyncSingle(
|
|
|
1209
1312
|
steps: [
|
|
1210
1313
|
{
|
|
1211
1314
|
parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
|
|
1315
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1212
1316
|
agent,
|
|
1213
1317
|
task: taskWithOutputInstruction,
|
|
1214
1318
|
...(params.context ? { context: params.context } : {}),
|
|
1215
1319
|
cwd: runnerCwd,
|
|
1216
1320
|
model,
|
|
1217
1321
|
thinking: resolveEffectiveThinking(model, effectiveThinking),
|
|
1218
|
-
modelCandidates
|
|
1219
|
-
applyThinkingSuffix(candidate, effectiveThinking, params.thinkingOverride !== undefined),
|
|
1220
|
-
),
|
|
1322
|
+
modelCandidates,
|
|
1221
1323
|
tools: agentConfig.tools,
|
|
1222
1324
|
extensions: agentConfig.extensions,
|
|
1223
1325
|
subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
|
|
@@ -1234,6 +1336,9 @@ export function executeAsyncSingle(
|
|
|
1234
1336
|
maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
|
|
1235
1337
|
waitToolEnabled: params.waitToolEnabled,
|
|
1236
1338
|
...(params.agentContract ? { agentContract: params.agentContract } : {}),
|
|
1339
|
+
definitionDigest: agentDefinitionDigest(agentConfig),
|
|
1340
|
+
launchBindingTask: task,
|
|
1341
|
+
launchContractDigest,
|
|
1237
1342
|
effectiveAcceptance: resolvedAcceptance,
|
|
1238
1343
|
...(structuredOutput ? { structuredOutput } : {}),
|
|
1239
1344
|
...(params.structuredOutputSchema ? { structuredOutputSchema: params.structuredOutputSchema } : {}),
|
|
@@ -1250,6 +1355,7 @@ export function executeAsyncSingle(
|
|
|
1250
1355
|
sessionDir: resolvedSessionDir,
|
|
1251
1356
|
asyncDir,
|
|
1252
1357
|
sessionId: ctx.currentSessionId,
|
|
1358
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1253
1359
|
piPackageRoot,
|
|
1254
1360
|
piArgv1: process.argv[1],
|
|
1255
1361
|
worktreeSetupHook,
|
|
@@ -1263,6 +1369,7 @@ export function executeAsyncSingle(
|
|
|
1263
1369
|
controlIntercomTarget,
|
|
1264
1370
|
childIntercomTargets: childIntercomTarget ? [childIntercomTarget(agent, 0)] : undefined,
|
|
1265
1371
|
resultMode: "single",
|
|
1372
|
+
launchContractDigest,
|
|
1266
1373
|
...(params.revivalLease ? { revivalLease: params.revivalLease } : {}),
|
|
1267
1374
|
nestedRoute: nestedRoute ?? inheritedNestedRoute,
|
|
1268
1375
|
nestedSelf: inheritedNestedRoute && nestedAddress ? {
|
|
@@ -1274,6 +1381,7 @@ export function executeAsyncSingle(
|
|
|
1274
1381
|
},
|
|
1275
1382
|
id,
|
|
1276
1383
|
runnerCwd,
|
|
1384
|
+
(proof) => ctx.pi.events.emit(SUBAGENT_PROCESS_TERMINAL_EVENT, proof),
|
|
1277
1385
|
);
|
|
1278
1386
|
} catch (error) {
|
|
1279
1387
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1314,6 +1422,7 @@ export function executeAsyncSingle(
|
|
|
1314
1422
|
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1315
1423
|
startedAt: now,
|
|
1316
1424
|
lastUpdate: now,
|
|
1425
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1317
1426
|
},
|
|
1318
1427
|
});
|
|
1319
1428
|
} catch (error) {
|
|
@@ -1331,14 +1440,16 @@ export function executeAsyncSingle(
|
|
|
1331
1440
|
goal: (params.goal ?? task).slice(0, 120),
|
|
1332
1441
|
cwd: runnerCwd,
|
|
1333
1442
|
asyncDir,
|
|
1443
|
+
launchContractDigest,
|
|
1334
1444
|
...(timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}),
|
|
1335
1445
|
...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
|
|
1446
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
1336
1447
|
nestedRoute,
|
|
1337
1448
|
});
|
|
1338
1449
|
}
|
|
1339
1450
|
|
|
1340
1451
|
return {
|
|
1341
1452
|
content: [{ type: "text", text: formatAsyncStartedMessage(`Async: ${agent} [${id}]`, ctx.interactive === true) }],
|
|
1342
|
-
details: { mode: "single", runId: id, results: [], asyncId: id, asyncDir, ...(params.context ? { context: params.context } : {}), ...(timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}), ...(params.turnBudget ? { turnBudget: params.turnBudget } : {}), ...(params.toolBudget ? { toolBudget: params.toolBudget } : {}) },
|
|
1453
|
+
details: { mode: "single", runId: id, results: [], asyncId: id, asyncDir, launchContractDigest, ...(capabilityCeiling ? { capabilityCeiling } : {}), ...(params.context ? { context: params.context } : {}), ...(timeoutMs !== undefined ? { timeoutMs, deadlineAt } : {}), ...(params.turnBudget ? { turnBudget: params.turnBudget } : {}), ...(params.toolBudget ? { toolBudget: params.toolBudget } : {}) },
|
|
1343
1454
|
};
|
|
1344
1455
|
}
|
|
@@ -4,6 +4,7 @@ import { ASYNC_DIR, RESULTS_DIR, type AcceptanceInput, type AsyncStatus, type St
|
|
|
4
4
|
import type { AgentConfig } from "../../agents/agents.ts";
|
|
5
5
|
import { validateAcceptanceInput } from "../shared/acceptance.ts";
|
|
6
6
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
7
|
+
import { intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
7
8
|
import { resolveTurnBudgetConfig } from "../shared/turn-budget.ts";
|
|
8
9
|
import { reconcileAsyncRun } from "./stale-run-reconciler.ts";
|
|
9
10
|
|
|
@@ -38,6 +39,8 @@ export type AsyncResumeTarget = {
|
|
|
38
39
|
model?: string;
|
|
39
40
|
thinking?: string;
|
|
40
41
|
recoveryDescriptor?: SteeringRecoveryDescriptor;
|
|
42
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
43
|
+
launchContractDigest?: string;
|
|
41
44
|
};
|
|
42
45
|
|
|
43
46
|
interface AsyncResultFile {
|
|
@@ -52,7 +55,9 @@ interface AsyncResultFile {
|
|
|
52
55
|
sessionFile?: string;
|
|
53
56
|
model?: string;
|
|
54
57
|
thinking?: string;
|
|
55
|
-
|
|
58
|
+
launchContractDigest?: string;
|
|
59
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
60
|
+
results?: Array<{ agent?: string; success?: boolean; sessionFile?: string; intercomTarget?: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling }>;
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
export interface AsyncRunLocation {
|
|
@@ -92,9 +97,11 @@ function validateResultFile(value: unknown, resultPath: string): AsyncResultFile
|
|
|
92
97
|
const intercomTarget = validateOptionalString(child, "intercomTarget", resultPath, `results[${index}].intercomTarget`);
|
|
93
98
|
const model = validateOptionalString(child, "model", resultPath, `results[${index}].model`);
|
|
94
99
|
const thinking = validateOptionalString(child, "thinking", resultPath, `results[${index}].thinking`);
|
|
100
|
+
const launchContractDigest = validateOptionalString(child, "launchContractDigest", resultPath, `results[${index}].launchContractDigest`);
|
|
101
|
+
const capabilityCeiling = child.capabilityCeiling === undefined ? undefined : parseSubagentCapabilityCeiling(child.capabilityCeiling, `async result file '${resultPath}' results[${index}].capabilityCeiling`);
|
|
95
102
|
const success = child.success;
|
|
96
103
|
if (success !== undefined && typeof success !== "boolean") throw new Error(`Invalid async result file '${resultPath}': results[${index}].success must be a boolean.`);
|
|
97
|
-
return { agent, sessionFile, intercomTarget, model, thinking, ...(typeof success === "boolean" ? { success } : {}) };
|
|
104
|
+
return { agent, sessionFile, intercomTarget, model, thinking, launchContractDigest, ...(capabilityCeiling ? { capabilityCeiling } : {}), ...(typeof success === "boolean" ? { success } : {}) };
|
|
98
105
|
});
|
|
99
106
|
}
|
|
100
107
|
const success = data.success;
|
|
@@ -110,6 +117,8 @@ function validateResultFile(value: unknown, resultPath: string): AsyncResultFile
|
|
|
110
117
|
sessionFile: validateOptionalString(data, "sessionFile", resultPath),
|
|
111
118
|
model: validateOptionalString(data, "model", resultPath),
|
|
112
119
|
thinking: validateOptionalString(data, "thinking", resultPath),
|
|
120
|
+
launchContractDigest: validateOptionalString(data, "launchContractDigest", resultPath),
|
|
121
|
+
...(data.capabilityCeiling === undefined ? {} : { capabilityCeiling: parseSubagentCapabilityCeiling(data.capabilityCeiling, `async result file '${resultPath}' capabilityCeiling`) }),
|
|
113
122
|
...(typeof success === "boolean" ? { success } : {}),
|
|
114
123
|
...(results ? { results } : {}),
|
|
115
124
|
};
|
|
@@ -237,6 +246,7 @@ function validateStatusForResume(status: AsyncStatus | null, source: string): vo
|
|
|
237
246
|
if (status.sessionId !== undefined && typeof status.sessionId !== "string") throw new Error(`Invalid async status '${source}': sessionId must be a string.`);
|
|
238
247
|
if (status.cwd !== undefined && typeof status.cwd !== "string") throw new Error(`Invalid async status '${source}': cwd must be a string.`);
|
|
239
248
|
if (status.sessionFile !== undefined && typeof status.sessionFile !== "string") throw new Error(`Invalid async status '${source}': sessionFile must be a string.`);
|
|
249
|
+
if (status.capabilityCeiling !== undefined) status.capabilityCeiling = parseSubagentCapabilityCeiling(status.capabilityCeiling, `async status '${source}' capabilityCeiling`);
|
|
240
250
|
if (status.steps !== undefined) {
|
|
241
251
|
if (!Array.isArray(status.steps)) throw new Error(`Invalid async status '${source}': steps must be an array.`);
|
|
242
252
|
status.steps.forEach((step, index) => {
|
|
@@ -246,6 +256,7 @@ function validateStatusForResume(status: AsyncStatus | null, source: string): vo
|
|
|
246
256
|
if (stepRecord.sessionFile !== undefined && typeof stepRecord.sessionFile !== "string") throw new Error(`Invalid async status '${source}': steps[${index}].sessionFile must be a string.`);
|
|
247
257
|
if (stepRecord.model !== undefined && typeof stepRecord.model !== "string") throw new Error(`Invalid async status '${source}': steps[${index}].model must be a string.`);
|
|
248
258
|
if (stepRecord.thinking !== undefined && typeof stepRecord.thinking !== "string") throw new Error(`Invalid async status '${source}': steps[${index}].thinking must be a string.`);
|
|
259
|
+
if (stepRecord.capabilityCeiling !== undefined) stepRecord.capabilityCeiling = parseSubagentCapabilityCeiling(stepRecord.capabilityCeiling, `async status '${source}' steps[${index}].capabilityCeiling`);
|
|
249
260
|
});
|
|
250
261
|
}
|
|
251
262
|
}
|
|
@@ -254,10 +265,6 @@ function normalizeRecoveryAcceptance(value: unknown, descriptorPath: string): Ac
|
|
|
254
265
|
if (value && typeof value === "object" && !Array.isArray(value) && ("explicit" in value || "inferredReason" in value)) {
|
|
255
266
|
const { explicit, inferredReason: _inferredReason, ...publicAcceptance } = value as Record<string, unknown>;
|
|
256
267
|
if (explicit === false) return undefined;
|
|
257
|
-
if (publicAcceptance.level === "reviewed") {
|
|
258
|
-
publicAcceptance.level = "verified";
|
|
259
|
-
delete publicAcceptance.review;
|
|
260
|
-
}
|
|
261
268
|
value = publicAcceptance;
|
|
262
269
|
}
|
|
263
270
|
const errors = validateAcceptanceInput(value, "recoveryDescriptor.acceptance");
|
|
@@ -281,7 +288,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
281
288
|
"version", "sourceRunId", "agentContract", "agent", "sessionFile", "cwd", "model", "fallbackModels", "thinking", "tools", "extensions",
|
|
282
289
|
"subagentOnlyExtensions", "mcpDirectTools", "systemPrompt", "systemPromptMode", "inheritProjectContext", "inheritSkills", "skills",
|
|
283
290
|
"skillPath", "agentFilePath", "completionGuard", "memory", "outputPath", "outputMode", "structuredOutputSchema", "acceptance", "sessionDir", "artifactConfig",
|
|
284
|
-
"artifactsDir", "maxOutput", "controlConfig", "absoluteDeadlineAt", "initialTurnBudget", "initialToolBudget", "maxSubagentDepth", "share",
|
|
291
|
+
"artifactsDir", "maxOutput", "controlConfig", "absoluteDeadlineAt", "initialTurnBudget", "initialToolBudget", "maxSubagentDepth", "share", "capabilityCeiling",
|
|
285
292
|
]);
|
|
286
293
|
for (const field of Object.keys(parsed)) {
|
|
287
294
|
if (!allowedFields.has(field)) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': unknown field '${field}'.`);
|
|
@@ -291,6 +298,7 @@ export function readAsyncRecoveryDescriptor(asyncDir: string | undefined): Steer
|
|
|
291
298
|
if (typeof parsed[field] !== "string" || !(parsed[field] as string).trim()) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': ${field} must be a non-empty string.`);
|
|
292
299
|
}
|
|
293
300
|
if (parsed.version !== 1) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': version must be 1.`);
|
|
301
|
+
if (parsed.capabilityCeiling !== undefined) parsed.capabilityCeiling = parseSubagentCapabilityCeiling(parsed.capabilityCeiling, `async recovery descriptor '${descriptorPath}' capabilityCeiling`);
|
|
294
302
|
if (parsed.agentContract !== undefined) {
|
|
295
303
|
if (!parsed.agentContract || typeof parsed.agentContract !== "object" || Array.isArray(parsed.agentContract)) throw new Error(`Invalid async recovery descriptor '${descriptorPath}': agentContract must be an object.`);
|
|
296
304
|
const contract = parsed.agentContract as Record<string, unknown>;
|
|
@@ -407,6 +415,7 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
407
415
|
if (requestedIndex < 0 || requestedIndex >= stepCount) throw new Error(`Async run '${runId}' has ${stepCount} children. Index ${requestedIndex} is out of range.`);
|
|
408
416
|
const selectedStep = statusSteps[requestedIndex];
|
|
409
417
|
if (selectedStep?.status === "running") {
|
|
418
|
+
const capabilityCeiling = intersectSubagentCapabilityCeilings(status?.capabilityCeiling, selectedStep.capabilityCeiling);
|
|
410
419
|
return {
|
|
411
420
|
kind: "live",
|
|
412
421
|
runId,
|
|
@@ -418,6 +427,8 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
418
427
|
sessionFile: selectedStep.sessionFile ?? status?.sessionFile ?? result?.sessionFile,
|
|
419
428
|
model: selectedStep.model,
|
|
420
429
|
thinking: selectedStep.thinking,
|
|
430
|
+
launchContractDigest: selectedStep.launchContractDigest ?? result?.results?.[requestedIndex]?.launchContractDigest ?? result?.launchContractDigest,
|
|
431
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
421
432
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
422
433
|
};
|
|
423
434
|
}
|
|
@@ -431,6 +442,7 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
431
442
|
if (!selected) {
|
|
432
443
|
throw new Error(`Async run '${runId}' has ${running.length} running children. Provide index to choose one.`);
|
|
433
444
|
}
|
|
445
|
+
const capabilityCeiling = intersectSubagentCapabilityCeilings(status?.capabilityCeiling, selected.step.capabilityCeiling);
|
|
434
446
|
return {
|
|
435
447
|
kind: "live",
|
|
436
448
|
runId,
|
|
@@ -442,6 +454,8 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
442
454
|
sessionFile: selected.step.sessionFile ?? status?.sessionFile ?? result?.sessionFile,
|
|
443
455
|
model: selected.step.model,
|
|
444
456
|
thinking: selected.step.thinking,
|
|
457
|
+
launchContractDigest: selected.step.launchContractDigest ?? result?.results?.[selected.index]?.launchContractDigest ?? result?.launchContractDigest,
|
|
458
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
445
459
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
446
460
|
};
|
|
447
461
|
}
|
|
@@ -463,6 +477,7 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
463
477
|
const resolvedSessionFile = sessionFile ? validateResumeSessionFile(runId, sessionFile) : undefined;
|
|
464
478
|
const stepModel = statusSteps[index]?.model ?? resultSteps[index]?.model ?? (stepCount === 1 ? result?.model : undefined);
|
|
465
479
|
const stepThinking = statusSteps[index]?.thinking ?? resultSteps[index]?.thinking ?? (stepCount === 1 ? result?.thinking : undefined);
|
|
480
|
+
const capabilityCeiling = intersectSubagentCapabilityCeilings(status?.capabilityCeiling, statusSteps[index]?.capabilityCeiling, result?.capabilityCeiling, resultSteps[index]?.capabilityCeiling);
|
|
466
481
|
|
|
467
482
|
return {
|
|
468
483
|
kind: "revive",
|
|
@@ -475,6 +490,8 @@ export function resolveAsyncResumeTarget(params: AsyncResumeParams, deps: AsyncR
|
|
|
475
490
|
...(resolvedSessionFile ? { sessionFile: resolvedSessionFile } : {}),
|
|
476
491
|
...(stepModel ? { model: stepModel } : {}),
|
|
477
492
|
...(stepThinking ? { thinking: stepThinking } : {}),
|
|
493
|
+
launchContractDigest: statusSteps[index]?.launchContractDigest ?? resultSteps[index]?.launchContractDigest ?? result?.launchContractDigest,
|
|
494
|
+
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
478
495
|
...(recoveryDescriptor ? { recoveryDescriptor } : {}),
|
|
479
496
|
};
|
|
480
497
|
}
|
|
@@ -3,12 +3,14 @@ import * as path from "node:path";
|
|
|
3
3
|
import { formatDuration, formatModelThinking, formatTokens, shortenPath } from "../../shared/formatters.ts";
|
|
4
4
|
import { formatActivityLabel, formatParallelOutcome } from "../../shared/status-format.ts";
|
|
5
5
|
import { type ActivityState, type AsyncJobStep, type AsyncParallelGroupStatus, type AsyncStatus, type CostSummary, type NestedRunSummary, type SteeringStatus, type SubagentRunMode, type TokenUsage, type TurnBudgetState } from "../../shared/types.ts";
|
|
6
|
+
import type { ResolvedSubagentCapabilityCeiling, SubagentCapabilityAudit } from "../shared/capability-ceiling.ts";
|
|
6
7
|
import { readStatus } from "../../shared/utils.ts";
|
|
7
8
|
import { attachRootChildrenToSteps, buildNestedRouteIndex, type NestedRoute, projectNestedEvents } from "../shared/nested-events.ts";
|
|
8
9
|
import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
|
|
9
10
|
import { flatToLogicalStepIndex, normalizeParallelGroups } from "./parallel-groups.ts";
|
|
10
11
|
import { contextModeLabel, summarizeContextModes, type ContextMode, type ContextSummary } from "../shared/context-mode.ts";
|
|
11
12
|
import { reconcileAsyncRun, reconcileNestedAsyncDescendants } from "./stale-run-reconciler.ts";
|
|
13
|
+
import { readProcessTerminal, sanitizeProcessTerminal } from "./process-terminal.ts";
|
|
12
14
|
|
|
13
15
|
interface AsyncRunStepSummary {
|
|
14
16
|
index: number;
|
|
@@ -50,6 +52,9 @@ interface AsyncRunStepSummary {
|
|
|
50
52
|
execution?: AsyncJobStep["execution"];
|
|
51
53
|
review?: AsyncJobStep["review"];
|
|
52
54
|
effects?: AsyncJobStep["effects"];
|
|
55
|
+
processTerminal?: AsyncJobStep["processTerminal"];
|
|
56
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
57
|
+
capabilityAudit?: SubagentCapabilityAudit;
|
|
53
58
|
children?: NestedRunSummary[];
|
|
54
59
|
}
|
|
55
60
|
|
|
@@ -92,6 +97,9 @@ export interface AsyncRunSummary {
|
|
|
92
97
|
sessionFile?: string;
|
|
93
98
|
nestedChildren?: NestedRunSummary[];
|
|
94
99
|
nestedWarnings?: string[];
|
|
100
|
+
processTerminal?: AsyncStatus["processTerminal"];
|
|
101
|
+
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
102
|
+
capabilityAudit?: SubagentCapabilityAudit;
|
|
95
103
|
}
|
|
96
104
|
|
|
97
105
|
interface AsyncRunListOptions {
|
|
@@ -194,6 +202,8 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
194
202
|
throw new Error(`Invalid async status '${path.join(asyncDir, "status.json")}': sessionId must be a string.`);
|
|
195
203
|
}
|
|
196
204
|
const { activityState, lastActivityAt } = deriveAsyncActivityState(asyncDir, status);
|
|
205
|
+
const processTerminal = readProcessTerminal(asyncDir, { runId: status.runId, runnerProcessInstanceId: status.processTerminal?.runnerProcessInstanceId })
|
|
206
|
+
?? sanitizeProcessTerminal(status.processTerminal, { runId: status.runId, runnerProcessInstanceId: status.processTerminal?.runnerProcessInstanceId }, path.join(asyncDir, "status.json"));
|
|
197
207
|
const steps = status.steps ?? [];
|
|
198
208
|
const chainStepCount = status.chainStepCount ?? steps.length;
|
|
199
209
|
const parallelGroups = normalizeParallelGroups(status.parallelGroups, steps.length, chainStepCount);
|
|
@@ -247,9 +257,13 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
247
257
|
...(step.wrapUpRequested !== undefined ? { wrapUpRequested: step.wrapUpRequested } : {}),
|
|
248
258
|
...(step.acceptance ? { acceptance: step.acceptance } : {}),
|
|
249
259
|
...(step.agentContract ? { agentContract: step.agentContract } : {}),
|
|
260
|
+
...(step.launchContractDigest ? { launchContractDigest: step.launchContractDigest } : {}),
|
|
250
261
|
...(step.execution ? { execution: step.execution } : {}),
|
|
251
262
|
...(step.review ? { review: step.review } : {}),
|
|
252
263
|
...(step.effects ? { effects: step.effects } : {}),
|
|
264
|
+
...(step.processTerminal ? { processTerminal: sanitizeProcessTerminal(step.processTerminal, { runId: status.runId, runnerProcessInstanceId: step.processTerminal.runnerProcessInstanceId }, `${path.join(asyncDir, "status.json")} step ${index}`) } : {}),
|
|
265
|
+
...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
|
|
266
|
+
...(step.capabilityAudit ? { capabilityAudit: step.capabilityAudit } : {}),
|
|
253
267
|
...(step.children?.length ? { children: step.children } : {}),
|
|
254
268
|
};
|
|
255
269
|
});
|
|
@@ -288,6 +302,10 @@ function statusToSummary(asyncDir: string, status: AsyncStatus & { cwd?: string
|
|
|
288
302
|
steps: summarizedSteps,
|
|
289
303
|
...(nestedChildren.length ? { nestedChildren } : {}),
|
|
290
304
|
...(nestedWarnings.length ? { nestedWarnings } : {}),
|
|
305
|
+
...(processTerminal ? { processTerminal } : {}),
|
|
306
|
+
...(status.launchContractDigest ? { launchContractDigest: status.launchContractDigest } : {}),
|
|
307
|
+
...(status.capabilityCeiling ? { capabilityCeiling: status.capabilityCeiling } : {}),
|
|
308
|
+
...(status.capabilityAudit ? { capabilityAudit: status.capabilityAudit } : {}),
|
|
291
309
|
...(status.sessionDir ? { sessionDir: status.sessionDir } : {}),
|
|
292
310
|
...(status.outputFile ? { outputFile: status.outputFile } : {}),
|
|
293
311
|
...(status.totalTokens ? { totalTokens: status.totalTokens } : {}),
|