pi-subagents 0.62.0 → 0.64.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 +52 -1
- package/docs/agents.md +5 -4
- package/docs/configuration.md +28 -2
- package/docs/models.md +5 -5
- package/docs/observability.md +4 -1
- package/docs/tool-reference.md +2 -2
- package/docs/watchdog.md +92 -114
- package/package.json +1 -1
- package/skills/pi-subagents/references/execution-controls.md +4 -3
- package/skills/pi-subagents/references/management-authoring-rpc.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +3 -3
- package/src/agents/agent-management.ts +22 -4
- package/src/agents/agents.ts +107 -125
- package/src/api/shared-types.ts +3 -0
- package/src/extension/config.ts +20 -0
- package/src/inspectors/herdr/inspector-runner.ts +19 -13
- package/src/runs/background/active-async-capacity.ts +0 -1
- package/src/runs/background/async-execution.ts +56 -7
- package/src/runs/background/async-resume.ts +3 -0
- package/src/runs/background/async-status.ts +18 -2
- package/src/runs/background/notify.ts +54 -3
- package/src/runs/background/run-status.ts +22 -2
- package/src/runs/background/subagent-runner.ts +53 -3
- package/src/runs/background/wait-completions.ts +13 -0
- package/src/runs/foreground/execution.ts +7 -1
- package/src/runs/foreground/subagent-executor.ts +56 -4
- package/src/runs/shared/acceptance.ts +25 -9
- package/src/runs/shared/async-status-projection.ts +11 -43
- package/src/runs/shared/lane-metadata.ts +24 -3
- package/src/runs/shared/parallel-handoff.ts +4 -0
- package/src/runs/shared/pi-args.ts +9 -6
- package/src/runs/shared/subagent-control.ts +4 -2
- package/src/runs/shared/task-intent.ts +5 -2
- package/src/runs/shared/worktree.ts +467 -63
- package/src/shared/types.ts +38 -2
- package/src/shared/utils.ts +18 -7
- package/src/slash/subagents-admin.ts +24 -12
- package/src/tui/fleet-status.ts +61 -2
- package/src/tui/fleet.ts +12 -7
- package/src/tui/render.ts +227 -14
- package/src/watchdog/child-status.ts +54 -33
- package/src/watchdog/diff-tool.ts +77 -0
- package/src/watchdog/emission-guard.ts +5 -3
- package/src/watchdog/guidance.ts +20 -0
- package/src/watchdog/register-child.ts +16 -13
- package/src/watchdog/register-main.ts +10 -9
- package/src/watchdog/render.ts +4 -5
- package/src/watchdog/review.ts +15 -4
- package/src/watchdog/rules.ts +70 -0
- package/src/watchdog/runtime.ts +75 -92
- package/src/watchdog/scope.ts +0 -11
- package/src/watchdog/settings.ts +48 -104
- package/src/watchdog/types.ts +18 -32
- package/src/watchdog/warning-format.ts +0 -1
- package/src/workflows/chat-progress.ts +3 -2
- package/src/workflows/workflow-checklist.ts +439 -0
- package/src/workflows/workflow-preflight.ts +28 -1
|
@@ -124,6 +124,7 @@ import {
|
|
|
124
124
|
findWorktreeTaskCwdConflict,
|
|
125
125
|
formatWorktreeDiffSummary,
|
|
126
126
|
formatWorktreeTaskCwdConflict,
|
|
127
|
+
WORKTREE_AGENT_CWD_PLACEHOLDER,
|
|
127
128
|
type WorktreeSetup,
|
|
128
129
|
} from "../shared/worktree.ts";
|
|
129
130
|
import { findModelInfo, resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
@@ -155,6 +156,7 @@ import { decodeSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, type
|
|
|
155
156
|
import {
|
|
156
157
|
CHILD_WATCHDOG_CONFIG_ENV,
|
|
157
158
|
acceptChildWatchdogEvent,
|
|
159
|
+
applyChildWatchdogMessage,
|
|
158
160
|
childWatchdogIsActive,
|
|
159
161
|
decodeChildWatchdogConfig,
|
|
160
162
|
isChildWatchdogStatusEvent,
|
|
@@ -185,6 +187,8 @@ interface SubagentRunConfig {
|
|
|
185
187
|
worktreeSetupHook?: string;
|
|
186
188
|
worktreeSetupHookTimeoutMs?: number;
|
|
187
189
|
worktreeBaseDir?: string;
|
|
190
|
+
worktreeProvider?: import("../../shared/types.ts").WorktreeProvider;
|
|
191
|
+
worktreeBranchPrefix?: string;
|
|
188
192
|
controlConfig?: ResolvedControlConfig;
|
|
189
193
|
controlIntercomTarget?: string;
|
|
190
194
|
childIntercomTargets?: Array<string | undefined>;
|
|
@@ -245,6 +249,7 @@ interface StepResult {
|
|
|
245
249
|
sessionFile?: string;
|
|
246
250
|
intercomTarget?: string;
|
|
247
251
|
model?: string;
|
|
252
|
+
thinking?: string;
|
|
248
253
|
attemptedModels?: string[];
|
|
249
254
|
modelAttempts?: ModelAttempt[];
|
|
250
255
|
/** True when the dispatch failed because the input exceeded the model's context window. */
|
|
@@ -850,6 +855,10 @@ function runPiStreaming(
|
|
|
850
855
|
const text = extractTextFromContent(event.message.content);
|
|
851
856
|
if (text) writeOutputText(text);
|
|
852
857
|
|
|
858
|
+
if (childWatchdogConfig && event.type === "message_end") {
|
|
859
|
+
const next = applyChildWatchdogMessage(childWatchdogState, event.message);
|
|
860
|
+
if (next) updateChildWatchdogState(next);
|
|
861
|
+
}
|
|
853
862
|
if (event.type !== "message_end" || event.message.role !== "assistant") return;
|
|
854
863
|
const hasToolCall = assistantStartsToolCall(event.message);
|
|
855
864
|
if (event.message.model) {
|
|
@@ -1066,7 +1075,6 @@ function runPiStreaming(
|
|
|
1066
1075
|
phase: "stale",
|
|
1067
1076
|
seq: (childWatchdogState?.seq ?? 0) + 1,
|
|
1068
1077
|
lastUpdate: Date.now(),
|
|
1069
|
-
followUpPending: false,
|
|
1070
1078
|
reason: "child watchdog tail timeout",
|
|
1071
1079
|
timedOut: true,
|
|
1072
1080
|
});
|
|
@@ -2164,6 +2172,7 @@ async function runSingleStepInner(
|
|
|
2164
2172
|
reportOptional: isAgentContractV1(step.agentContract),
|
|
2165
2173
|
artifactsDir: ctx.artifactsDir,
|
|
2166
2174
|
runId: ctx.id,
|
|
2175
|
+
watchdog: finalResult?.watchdog,
|
|
2167
2176
|
}))
|
|
2168
2177
|
: undefined;
|
|
2169
2178
|
const stoppedAfterAcceptance = finalResult?.stopped === true || ctx.stopSignal?.aborted === true;
|
|
@@ -2241,6 +2250,7 @@ async function runSingleStepInner(
|
|
|
2241
2250
|
sessionFile: step.sessionFile,
|
|
2242
2251
|
intercomTarget: ctx.childIntercomTarget,
|
|
2243
2252
|
model: finalResult?.model,
|
|
2253
|
+
thinking: resolveEffectiveThinking(finalResult?.model, step.thinking),
|
|
2244
2254
|
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
2245
2255
|
modelAttempts,
|
|
2246
2256
|
contextOverflow: contextOverflow || undefined,
|
|
@@ -2339,6 +2349,8 @@ function requiredStatusStep(statusPayload: RunnerStatusPayload, index: number):
|
|
|
2339
2349
|
function setStatusWorktreeReference(statusStep: RunnerStatusStep, worktree: WorktreeSetup["worktrees"][number]): void {
|
|
2340
2350
|
statusStep.worktreePath = worktree.path;
|
|
2341
2351
|
statusStep.branch = worktree.branch;
|
|
2352
|
+
if (worktree.provider) statusStep.provider = worktree.provider;
|
|
2353
|
+
if (worktree.naming) statusStep.naming = worktree.naming;
|
|
2342
2354
|
}
|
|
2343
2355
|
|
|
2344
2356
|
function markParallelGroupSetupFailure(input: {
|
|
@@ -2419,6 +2431,18 @@ function markParallelGroupRunning(input: {
|
|
|
2419
2431
|
}));
|
|
2420
2432
|
}
|
|
2421
2433
|
|
|
2434
|
+
function bindWorktreeCwd(step: SubagentStep, worktreeCwd: string): SubagentStep {
|
|
2435
|
+
const bind = <T extends string | null | undefined>(value: T): T => value === null || value === undefined ? value : value.replaceAll(WORKTREE_AGENT_CWD_PLACEHOLDER, worktreeCwd) as T;
|
|
2436
|
+
return {
|
|
2437
|
+
...step,
|
|
2438
|
+
task: bind(step.task) ?? step.task,
|
|
2439
|
+
...(step.systemPrompt !== undefined ? { systemPrompt: bind(step.systemPrompt) } : {}),
|
|
2440
|
+
...(step.outputPath !== undefined ? { outputPath: bind(step.outputPath) } : {}),
|
|
2441
|
+
...(step.launchBindingTask !== undefined ? { launchBindingTask: bind(step.launchBindingTask) } : {}),
|
|
2442
|
+
...(step.requestedCwd !== undefined ? { requestedCwd: bind(step.requestedCwd) } : {}),
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2422
2446
|
function prepareParallelTaskRun(
|
|
2423
2447
|
task: SubagentStep,
|
|
2424
2448
|
cwd: string,
|
|
@@ -2427,8 +2451,9 @@ function prepareParallelTaskRun(
|
|
|
2427
2451
|
): { taskForRun: SubagentStep; taskCwd: string } {
|
|
2428
2452
|
if (!worktreeSetup) return { taskForRun: task, taskCwd: cwd };
|
|
2429
2453
|
const { cwd: _taskCwd, ...taskForRun } = task;
|
|
2454
|
+
const boundTask = bindWorktreeCwd(taskForRun, worktreeSetup.worktrees[taskIndex]!.agentCwd);
|
|
2430
2455
|
return {
|
|
2431
|
-
taskForRun,
|
|
2456
|
+
taskForRun: boundTask,
|
|
2432
2457
|
taskCwd: worktreeSetup.worktrees[taskIndex]!.agentCwd,
|
|
2433
2458
|
};
|
|
2434
2459
|
}
|
|
@@ -2887,6 +2912,7 @@ async function runSubagent(
|
|
|
2887
2912
|
success: statusResultSuccess(state, step),
|
|
2888
2913
|
sessionFile: step.sessionFile,
|
|
2889
2914
|
model: step.model,
|
|
2915
|
+
thinking: step.thinking,
|
|
2890
2916
|
attemptedModels: step.attemptedModels,
|
|
2891
2917
|
modelAttempts: step.modelAttempts,
|
|
2892
2918
|
usage: usageFromAttempts(step.modelAttempts),
|
|
@@ -3566,6 +3592,15 @@ async function runSubagent(
|
|
|
3566
3592
|
writeStatusPayload(false);
|
|
3567
3593
|
return;
|
|
3568
3594
|
}
|
|
3595
|
+
if (event.type === "message_end") {
|
|
3596
|
+
const next = applyChildWatchdogMessage(step.watchdog, event.message, now);
|
|
3597
|
+
if (next) step.watchdog = next;
|
|
3598
|
+
if (next && (event.message as { role?: unknown } | undefined)?.role === "custom") {
|
|
3599
|
+
statusPayload.lastUpdate = now;
|
|
3600
|
+
writeStatusPayload(false);
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3569
3604
|
if (event.type === "tool_execution_start" && event.toolName) {
|
|
3570
3605
|
const mutates = isMutatingTool(event.toolName, event.args, flatSteps[flatIndex]?.mutationTools);
|
|
3571
3606
|
const currentPath = resolveCurrentPath(event.toolName, event.args);
|
|
@@ -3710,6 +3745,7 @@ async function runSubagent(
|
|
|
3710
3745
|
config: controlConfig,
|
|
3711
3746
|
startedAt: step.startedAt ?? overallStartTime,
|
|
3712
3747
|
lastActivityAt,
|
|
3748
|
+
turnCount: step.turnCount,
|
|
3713
3749
|
currentTool: step.currentTool,
|
|
3714
3750
|
thinking: step.thinking,
|
|
3715
3751
|
now,
|
|
@@ -4331,6 +4367,7 @@ async function runSubagent(
|
|
|
4331
4367
|
sessionFile: pr.sessionFile,
|
|
4332
4368
|
intercomTarget: pr.intercomTarget,
|
|
4333
4369
|
model: pr.model,
|
|
4370
|
+
thinking: pr.thinking,
|
|
4334
4371
|
attemptedModels: pr.attemptedModels,
|
|
4335
4372
|
modelAttempts: pr.modelAttempts,
|
|
4336
4373
|
contextOverflow: pr.contextOverflow,
|
|
@@ -4475,6 +4512,10 @@ async function runSubagent(
|
|
|
4475
4512
|
try {
|
|
4476
4513
|
worktreeSetup = createWorktrees(cwd, `${id}-s${stepIndex}`, group.parallel.length, omitUndefinedProperties({
|
|
4477
4514
|
agents: group.parallel.map((task) => task.agent),
|
|
4515
|
+
labels: group.parallel.map((task) => task.lane?.key ?? config.workflowKey ?? task.outputName ?? task.label),
|
|
4516
|
+
tasks: group.parallel.map((task) => task.task),
|
|
4517
|
+
provider: config.worktreeProvider,
|
|
4518
|
+
branchPrefix: config.worktreeBranchPrefix,
|
|
4478
4519
|
setupHook: config.worktreeSetupHook
|
|
4479
4520
|
? omitUndefinedProperties({ hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs })
|
|
4480
4521
|
: undefined,
|
|
@@ -4772,6 +4813,7 @@ async function runSubagent(
|
|
|
4772
4813
|
sessionFile: pr.sessionFile,
|
|
4773
4814
|
intercomTarget: pr.intercomTarget,
|
|
4774
4815
|
model: pr.model,
|
|
4816
|
+
thinking: pr.thinking,
|
|
4775
4817
|
attemptedModels: pr.attemptedModels,
|
|
4776
4818
|
modelAttempts: pr.modelAttempts,
|
|
4777
4819
|
contextOverflow: pr.contextOverflow,
|
|
@@ -4907,6 +4949,10 @@ async function runSubagent(
|
|
|
4907
4949
|
try {
|
|
4908
4950
|
singleWorktreeSetup = createWorktrees(cwd, `${id}-s${stepIndex}`, 1, omitUndefinedProperties({
|
|
4909
4951
|
agents: [seqStep.agent],
|
|
4952
|
+
labels: [seqStep.lane?.key ?? config.workflowKey ?? seqStep.outputName ?? seqStep.label],
|
|
4953
|
+
tasks: [seqStep.task],
|
|
4954
|
+
provider: config.worktreeProvider,
|
|
4955
|
+
branchPrefix: config.worktreeBranchPrefix,
|
|
4910
4956
|
setupHook: config.worktreeSetupHook
|
|
4911
4957
|
? omitUndefinedProperties({ hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs })
|
|
4912
4958
|
: undefined,
|
|
@@ -4961,7 +5007,9 @@ async function runSubagent(
|
|
|
4961
5007
|
}));
|
|
4962
5008
|
|
|
4963
5009
|
flushPendingStepSteers(flatIndex);
|
|
4964
|
-
const executionStep = singleWorktreeSetup
|
|
5010
|
+
const executionStep = singleWorktreeSetup
|
|
5011
|
+
? bindWorktreeCwd({ ...seqStep, cwd: singleCwd }, singleCwd)
|
|
5012
|
+
: seqStep;
|
|
4965
5013
|
let singleResult: Awaited<ReturnType<typeof runSingleStepWithTimeout>>;
|
|
4966
5014
|
try {
|
|
4967
5015
|
singleResult = await runSingleStepWithTimeout(executionStep, compactOptional<SingleStepContext>({
|
|
@@ -5025,6 +5073,7 @@ async function runSubagent(
|
|
|
5025
5073
|
sessionFile: singleResult.sessionFile,
|
|
5026
5074
|
intercomTarget: singleResult.intercomTarget,
|
|
5027
5075
|
model: singleResult.model,
|
|
5076
|
+
thinking: singleResult.thinking,
|
|
5028
5077
|
attemptedModels: singleResult.attemptedModels,
|
|
5029
5078
|
modelAttempts: singleResult.modelAttempts,
|
|
5030
5079
|
contextOverflow: singleResult.contextOverflow,
|
|
@@ -5388,6 +5437,7 @@ async function runSubagent(
|
|
|
5388
5437
|
sessionFile: r.sessionFile,
|
|
5389
5438
|
intercomTarget: r.intercomTarget,
|
|
5390
5439
|
model: r.model,
|
|
5440
|
+
thinking: r.thinking,
|
|
5391
5441
|
attemptedModels: r.attemptedModels,
|
|
5392
5442
|
modelAttempts: r.modelAttempts,
|
|
5393
5443
|
contextOverflow: r.contextOverflow,
|
|
@@ -42,6 +42,15 @@ function errorMessage(error: unknown): string {
|
|
|
42
42
|
return error instanceof Error ? error.message : String(error);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
const STRUCTURED_OUTPUT_INLINE_LIMIT_BYTES = 4 * 1024;
|
|
46
|
+
|
|
47
|
+
export function projectStructuredOutput(value: unknown): unknown {
|
|
48
|
+
if (value === undefined) return undefined;
|
|
49
|
+
const serialized = JSON.stringify(value);
|
|
50
|
+
if (typeof serialized !== "string") throw new Error("Structured output must be JSON-serializable");
|
|
51
|
+
return Buffer.byteLength(serialized, "utf8") <= STRUCTURED_OUTPUT_INLINE_LIMIT_BYTES ? JSON.parse(serialized) : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
45
54
|
/**
|
|
46
55
|
* Project a terminal result payload into the slim shape that is safe to surface in
|
|
47
56
|
* tool_result details: run identity, per-child outcome, and the artifact trail.
|
|
@@ -65,6 +74,8 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
65
74
|
const sessionFile = asNonEmptyString(child.sessionFile);
|
|
66
75
|
const error = asNonEmptyString(child.error);
|
|
67
76
|
const model = asNonEmptyString(child.model);
|
|
77
|
+
const structuredOutput = projectStructuredOutput(child.structuredOutput);
|
|
78
|
+
const structuredOutputPath = asNonEmptyString(child.structuredOutputPath);
|
|
68
79
|
const contextOverflow = child.contextOverflow === true;
|
|
69
80
|
const timeoutRecovery = projectTimeoutRecovery(child.timeoutRecovery);
|
|
70
81
|
return [{
|
|
@@ -74,6 +85,8 @@ export function toWaitCompletion(data: Record<string, unknown>, runId: string):
|
|
|
74
85
|
...(sessionFile ? { sessionFile } : {}),
|
|
75
86
|
...(typeof child.success === "boolean" ? { success: child.success } : {}),
|
|
76
87
|
...(outputState ? { outputState } : {}),
|
|
88
|
+
...(structuredOutput !== undefined ? { structuredOutput } : {}),
|
|
89
|
+
...(structuredOutputPath ? { structuredOutputPath } : {}),
|
|
77
90
|
...(error ? { error } : {}),
|
|
78
91
|
...(model ? { model } : {}),
|
|
79
92
|
...(contextOverflow ? { contextOverflow: true } : {}),
|
|
@@ -115,6 +115,7 @@ import { consumeWorkflowChildPermit } from "../../shared/workflow-child-permit.t
|
|
|
115
115
|
import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, PI_AGGREGATE_EVENT_PROJECTOR, projectChildLifecycle, type ChildLifecycleAction, type ChildLifecycleState, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
|
|
116
116
|
import {
|
|
117
117
|
acceptChildWatchdogEvent,
|
|
118
|
+
applyChildWatchdogMessage,
|
|
118
119
|
childWatchdogIsActive,
|
|
119
120
|
isChildWatchdogStatusEvent,
|
|
120
121
|
resolveChildWatchdogConfig,
|
|
@@ -779,7 +780,6 @@ async function runSingleAttempt(
|
|
|
779
780
|
phase: "stale",
|
|
780
781
|
seq: (childWatchdogState?.seq ?? 0) + 1,
|
|
781
782
|
lastUpdate: Date.now(),
|
|
782
|
-
followUpPending: false,
|
|
783
783
|
reason: "child watchdog tail timeout",
|
|
784
784
|
timedOut: true,
|
|
785
785
|
});
|
|
@@ -965,6 +965,7 @@ async function runSingleAttempt(
|
|
|
965
965
|
config: controlConfig,
|
|
966
966
|
startedAt: startTime,
|
|
967
967
|
lastActivityAt: progress.lastActivityAt,
|
|
968
|
+
turnCount: progress.turnCount,
|
|
968
969
|
currentTool: progress.currentTool,
|
|
969
970
|
thinking: resolvedThinking,
|
|
970
971
|
now,
|
|
@@ -1119,6 +1120,10 @@ async function runSingleAttempt(
|
|
|
1119
1120
|
|
|
1120
1121
|
if (evt.type === "message_end" && evt.message) {
|
|
1121
1122
|
result.messages!.push(evt.message);
|
|
1123
|
+
if (childWatchdog) {
|
|
1124
|
+
const next = applyChildWatchdogMessage(childWatchdogState, evt.message);
|
|
1125
|
+
if (next) updateChildWatchdogState(next);
|
|
1126
|
+
}
|
|
1122
1127
|
if (evt.message.role === "assistant") {
|
|
1123
1128
|
result.usage.turns++;
|
|
1124
1129
|
progress.turnCount = result.usage.turns;
|
|
@@ -2231,6 +2236,7 @@ async function runSyncCompletionInner(
|
|
|
2231
2236
|
reportOptional: isAgentContractV1(options.agentContract),
|
|
2232
2237
|
artifactsDir: options.artifactsDir,
|
|
2233
2238
|
runId: options.runId,
|
|
2239
|
+
watchdog: result.watchdog,
|
|
2234
2240
|
});
|
|
2235
2241
|
}
|
|
2236
2242
|
} catch (error) {
|
|
@@ -27,6 +27,7 @@ import { normalizePublicSubagentExecution, validateWorkflowCapacityOverrides } f
|
|
|
27
27
|
import { runSync } from "./execution.ts";
|
|
28
28
|
import { handleWatchdogToolAction, WATCHDOG_TOOL_ACTIONS } from "../../watchdog/tool-actions.ts";
|
|
29
29
|
import type { MainWatchdogRuntime } from "../../watchdog/runtime.ts";
|
|
30
|
+
import { applyWatchdogLaunchRules } from "../../watchdog/rules.ts";
|
|
30
31
|
import { buildModelCandidates, normalizeParentModel, resolveEffectiveSubagentModel, resolveModelOrigin, type ModelOrigin, type ParentModel } from "../shared/model-fallback.ts";
|
|
31
32
|
import { formatRetainedChildren, listRetainedChildren } from "../background/retained-children.ts";
|
|
32
33
|
import { resolveModelScopesForAgent, type ModelScopeConfig } from "../shared/model-scope.ts";
|
|
@@ -1314,6 +1315,9 @@ function appendStepToAsyncChain(input: {
|
|
|
1314
1315
|
waitToolEnabled: input.deps.waitToolEnabled,
|
|
1315
1316
|
waitToolDefaultTimeoutMs: input.deps.waitToolDefaultTimeoutMs,
|
|
1316
1317
|
contextForAgent: contextPolicy.contextForAgent,
|
|
1318
|
+
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1319
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
1320
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1317
1321
|
asyncDir: resolved.location.asyncDir,
|
|
1318
1322
|
validateOutputBindings: false,
|
|
1319
1323
|
capabilityCeiling: intersectSubagentCapabilityCeilings(status.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(asyncCtx.currentSessionId)),
|
|
@@ -1687,6 +1691,8 @@ async function resumeExternalJobFollowUp(input: {
|
|
|
1687
1691
|
worktreeSetupHook: input.deps.config.worktreeSetupHook,
|
|
1688
1692
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
1689
1693
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1694
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
1695
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1690
1696
|
controlConfig: resolveControlConfig(input.deps.config.control, undefined),
|
|
1691
1697
|
controlIntercomTarget: input.intercomBridge.active ? input.intercomBridge.orchestratorTarget : undefined,
|
|
1692
1698
|
childIntercomTarget: input.intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
@@ -1943,6 +1949,8 @@ async function resumeAsyncRun(input: {
|
|
|
1943
1949
|
worktreeSetupHook: input.deps.config.worktreeSetupHook,
|
|
1944
1950
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
1945
1951
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
1952
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
1953
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
1946
1954
|
controlConfig: resolveControlConfig(input.deps.config.control, input.params.control),
|
|
1947
1955
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
1948
1956
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
@@ -2056,9 +2064,13 @@ async function resumeAsyncRun(input: {
|
|
|
2056
2064
|
worktreeSetupHook: input.deps.config.worktreeSetupHook,
|
|
2057
2065
|
worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
|
|
2058
2066
|
worktreeBaseDir: input.deps.config.worktreeBaseDir,
|
|
2059
|
-
|
|
2067
|
+
worktreeProvider: input.deps.config.worktreeProvider,
|
|
2068
|
+
worktreeBranchPrefix: input.deps.config.worktreeBranchPrefix,
|
|
2069
|
+
// A retained async child already owns the recorded worktree. Resume it in
|
|
2070
|
+
// place rather than allocating a second provider worktree around it.
|
|
2071
|
+
worktree: input.params.worktree === true && !("managedWorktree" in target && target.managedWorktree === true),
|
|
2060
2072
|
lane: input.params.lane ?? recoveryDescriptor?.lane,
|
|
2061
|
-
controlConfig:
|
|
2073
|
+
controlConfig: resolveRevivalControlConfig({ globalConfig: input.deps.config.control, requestedControl: input.params.control, recoveryControlConfig: recoveryDescriptor?.controlConfig }),
|
|
2062
2074
|
intercomBridge: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
|
|
2063
2075
|
controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
|
|
2064
2076
|
childIntercomTarget: intercomBridge.active ? (agent, index) => resolveSubagentIntercomTarget(runId, agent, index) : undefined,
|
|
@@ -3218,6 +3230,8 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3218
3230
|
source: modelOrigin === "explicit" ? "explicit" : "inherited",
|
|
3219
3231
|
});
|
|
3220
3232
|
const modelOverrideFromParent = modelOrigin === "inherited";
|
|
3233
|
+
const launchRuleError = applyWatchdogLaunchRules({ cwd: effectiveCwd, agent: a.name, model: modelOverride ?? (parentModel && `${parentModel.provider}/${parentModel.id}`), warn: (violation) => deps.watchdog?.displayRuleWarning(violation) });
|
|
3234
|
+
if (launchRuleError) return toExecutionErrorResult(params, new Error(launchRuleError), data.contextPolicy.contextSummary);
|
|
3221
3235
|
const asyncResult = executeAsyncSingle(id, compactOptional<Parameters<typeof executeAsyncSingle>[1]>({
|
|
3222
3236
|
agent: params.agent!,
|
|
3223
3237
|
task: shouldForkAgent(contextPolicy, params.agent!) ? wrapForkTask(params.task ?? "") : (params.task ?? ""),
|
|
@@ -3255,6 +3269,8 @@ async function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): Pro
|
|
|
3255
3269
|
worktreeSetupHook: deps.config.worktreeSetupHook,
|
|
3256
3270
|
worktreeSetupHookTimeoutMs: deps.config.worktreeSetupHookTimeoutMs,
|
|
3257
3271
|
worktreeBaseDir: deps.config.worktreeBaseDir,
|
|
3272
|
+
worktreeProvider: deps.config.worktreeProvider,
|
|
3273
|
+
worktreeBranchPrefix: deps.config.worktreeBranchPrefix,
|
|
3258
3274
|
controlConfig,
|
|
3259
3275
|
intercomBridge: params.intercomBridge,
|
|
3260
3276
|
controlIntercomTarget,
|
|
@@ -3291,6 +3307,10 @@ function createSingleWorktreeSetup(
|
|
|
3291
3307
|
setupHook: ExtensionConfig["worktreeSetupHook"],
|
|
3292
3308
|
setupHookTimeoutMs: ExtensionConfig["worktreeSetupHookTimeoutMs"],
|
|
3293
3309
|
baseDir: ExtensionConfig["worktreeBaseDir"],
|
|
3310
|
+
provider: ExtensionConfig["worktreeProvider"],
|
|
3311
|
+
branchPrefix: ExtensionConfig["worktreeBranchPrefix"],
|
|
3312
|
+
label?: string,
|
|
3313
|
+
task?: string,
|
|
3294
3314
|
beforeCreate?: (setup: WorktreeSetup) => void,
|
|
3295
3315
|
): { setup?: WorktreeSetup; errorResult?: AgentToolResult<Details> } {
|
|
3296
3316
|
if (!enabled) return {};
|
|
@@ -3302,6 +3322,10 @@ function createSingleWorktreeSetup(
|
|
|
3302
3322
|
? { hookPath: setupHook, ...(setupHookTimeoutMs === undefined ? {} : { timeoutMs: setupHookTimeoutMs }) }
|
|
3303
3323
|
: undefined,
|
|
3304
3324
|
baseDir,
|
|
3325
|
+
provider,
|
|
3326
|
+
branchPrefix,
|
|
3327
|
+
labels: [label],
|
|
3328
|
+
tasks: [task],
|
|
3305
3329
|
beforeCreate,
|
|
3306
3330
|
})),
|
|
3307
3331
|
};
|
|
@@ -3643,6 +3667,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3643
3667
|
},
|
|
3644
3668
|
);
|
|
3645
3669
|
const modelOverrideFromParent = modelOrigin === "inherited";
|
|
3670
|
+
const launchRuleError = applyWatchdogLaunchRules({ cwd: effectiveCwd, agent: agentConfig.name, model: modelOverride ?? (parentModel && `${parentModel.provider}/${parentModel.id}`), warn: (violation) => deps.watchdog?.displayRuleWarning(violation) });
|
|
3671
|
+
if (launchRuleError) return toExecutionErrorResult(params, new Error(launchRuleError), data.contextPolicy.contextSummary);
|
|
3646
3672
|
let skillOverride: string[] | false | undefined = normalizeSkillInput(params.skill);
|
|
3647
3673
|
let readsOverride: string[] | false | undefined = params.reads;
|
|
3648
3674
|
const rawOutput = params.output !== undefined ? params.output : agentConfig.output;
|
|
@@ -3662,6 +3688,10 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
|
|
|
3662
3688
|
deps.config.worktreeSetupHook,
|
|
3663
3689
|
deps.config.worktreeSetupHookTimeoutMs,
|
|
3664
3690
|
deps.config.worktreeBaseDir,
|
|
3691
|
+
deps.config.worktreeProvider,
|
|
3692
|
+
deps.config.worktreeBranchPrefix,
|
|
3693
|
+
params.lane?.key ?? params.workflowKey,
|
|
3694
|
+
task,
|
|
3665
3695
|
(plannedSetup) => {
|
|
3666
3696
|
pendingHandoff = writePendingParallelHandoff({
|
|
3667
3697
|
manifestPath: parallelHandoffPath(artifactsDir, runId),
|
|
@@ -4164,6 +4194,10 @@ function workflowOutputPathMappingSummary(children: WorkflowScriptChildResult[])
|
|
|
4164
4194
|
return mappings.length > 0 ? ` Output path mappings: ${mappings.join("; ")}.` : "";
|
|
4165
4195
|
}
|
|
4166
4196
|
|
|
4197
|
+
function workflowDetailsResults(children: WorkflowScriptChildResult[]): SingleResult[] {
|
|
4198
|
+
return children.flatMap((child) => (child.results ?? []).map((result) => result.workflowKey ? result : { ...result, workflowKey: child.key }));
|
|
4199
|
+
}
|
|
4200
|
+
|
|
4167
4201
|
function workflowSteerReceipt(key: string, result: AgentToolResult<Details>): WorkflowSteerResult {
|
|
4168
4202
|
const steering = result.details.steering;
|
|
4169
4203
|
const error = result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n") || undefined;
|
|
@@ -4409,6 +4443,7 @@ export function prepareWorkflowLaunchParams(
|
|
|
4409
4443
|
if (output !== undefined && typeof output !== "string" && typeof output !== "boolean") throw new Error("output must be a path string or boolean.");
|
|
4410
4444
|
const outputMode = Object.hasOwn(childParams, "outputMode") ? childParams.outputMode : workflowDefaults.outputMode;
|
|
4411
4445
|
if (outputMode !== undefined && outputMode !== "inline" && outputMode !== "file-only") throw new Error("outputMode must be 'inline' or 'file-only'.");
|
|
4446
|
+
const control = mergeWorkflowControlOverrides(workflowDefaults.control, childParams.control as ControlConfig | undefined);
|
|
4412
4447
|
return {
|
|
4413
4448
|
action: "resume",
|
|
4414
4449
|
id: childParams.resume.trim(),
|
|
@@ -4427,14 +4462,17 @@ export function prepareWorkflowLaunchParams(
|
|
|
4427
4462
|
...(options.missionDetached ? { mission: false } : {}),
|
|
4428
4463
|
...(timeoutMs !== undefined ? { timeoutMs: timeoutMs as number } : {}),
|
|
4429
4464
|
...(toolBudget !== undefined ? { toolBudget: toolBudget as ToolBudgetConfig } : {}),
|
|
4465
|
+
...(control !== undefined ? { control } : {}),
|
|
4430
4466
|
...(intercomBridge !== undefined ? { intercomBridge: intercomBridge as IntercomBridgeConfig } : {}),
|
|
4431
4467
|
...(capabilityCeiling ? { capabilityCeiling } : {}),
|
|
4432
4468
|
};
|
|
4433
4469
|
}
|
|
4470
|
+
const control = mergeWorkflowControlOverrides(workflowDefaults.control, childParams.control as ControlConfig | undefined);
|
|
4434
4471
|
const launchParams = {
|
|
4435
4472
|
...workflowDefaults,
|
|
4436
4473
|
async: options.externalAsyncRequired === true && childParams.async === undefined && workflowDefaults.async === undefined ? true : false,
|
|
4437
4474
|
...childParams,
|
|
4475
|
+
...(control !== undefined ? { control } : {}),
|
|
4438
4476
|
...(options.externalAsyncRequired === true && childParams.async === undefined && workflowDefaults.async === undefined ? { workflowAwaitAsync: true } : {}),
|
|
4439
4477
|
...(options.missionDetached ? { mission: false } : {}),
|
|
4440
4478
|
workflowParentRunId: parentWorkflowRunId,
|
|
@@ -4453,6 +4491,17 @@ export function prepareWorkflowLaunchParams(
|
|
|
4453
4491
|
return normalizedGate.params;
|
|
4454
4492
|
}
|
|
4455
4493
|
|
|
4494
|
+
function mergeWorkflowControlOverrides(workflowControl: ControlConfig | undefined, childControl: ControlConfig | undefined): ControlConfig | undefined {
|
|
4495
|
+
if (childControl === undefined) return workflowControl;
|
|
4496
|
+
if (workflowControl === undefined) return childControl;
|
|
4497
|
+
return { ...workflowControl, ...childControl };
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4500
|
+
export function resolveRevivalControlConfig(input: { globalConfig?: ControlConfig; requestedControl?: ControlConfig; recoveryControlConfig?: ResolvedControlConfig }): ResolvedControlConfig {
|
|
4501
|
+
if (input.requestedControl === undefined) return input.recoveryControlConfig ?? resolveControlConfig(input.globalConfig, undefined);
|
|
4502
|
+
return resolveControlConfig(input.recoveryControlConfig ?? input.globalConfig, input.requestedControl);
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4456
4505
|
type GateParamsNormalizationResult =
|
|
4457
4506
|
| { ok: true; params: SubagentParamsLike }
|
|
4458
4507
|
| { ok: false; error: string };
|
|
@@ -5519,7 +5568,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5519
5568
|
const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
|
|
5520
5569
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5521
5570
|
content: [{ type: "text", text: displayText }],
|
|
5522
|
-
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children
|
|
5571
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflowDetailsResults(workflow.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: finalPreflightTrace, emits: workflow.emits, console: workflow.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5523
5572
|
}, workflowFanoutBudget));
|
|
5524
5573
|
} catch (error) {
|
|
5525
5574
|
const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
|
|
@@ -5546,7 +5595,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
5546
5595
|
return attachWorkflowMission(withRunFanoutBudget({
|
|
5547
5596
|
content: [{ type: "text", text: displayText }],
|
|
5548
5597
|
isError: true,
|
|
5549
|
-
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children
|
|
5598
|
+
details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflowDetailsResults(partial.children), ...(workflowPreflight ? { preflight: workflowPreflight } : {}), workflowChildren, totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: finalPreflightTrace, emits: partial.emits, console: partial.console, ...(workflowResource ? { resource: workflowResource.provenance } : {}), ...(finalPreflightWarnings.length ? { preflightWarnings: finalPreflightWarnings } : {}), receipt }, chatProgress }),
|
|
5550
5599
|
}, workflowFanoutBudget));
|
|
5551
5600
|
}
|
|
5552
5601
|
}
|
|
@@ -6245,6 +6294,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
|
|
|
6245
6294
|
const canonicalParams = canonicalizeExecutionParams(effectiveParams, discoveredAgents, discovered.agentDiagnostics, unknownAgentDiagnosticContext);
|
|
6246
6295
|
if (canonicalParams.error) return buildRequestedModeError(effectiveParams, canonicalParams.error);
|
|
6247
6296
|
effectiveParams = canonicalParams.params!;
|
|
6297
|
+
if (effectiveParams.worktree === undefined && deps.config.worktree !== undefined) {
|
|
6298
|
+
effectiveParams = { ...effectiveParams, worktree: deps.config.worktree };
|
|
6299
|
+
}
|
|
6248
6300
|
const modelScope = discovered.modelScope;
|
|
6249
6301
|
effectiveParams = applySingleAgentLaunchDefaults(effectiveParams, discoveredAgents);
|
|
6250
6302
|
// An agent-level defaultContext is a preference, unlike an explicit request.
|
|
@@ -21,7 +21,9 @@ import type {
|
|
|
21
21
|
ResolvedAcceptanceGate,
|
|
22
22
|
SingleResult,
|
|
23
23
|
SubagentRunMode,
|
|
24
|
+
ChildWatchdogProgress,
|
|
24
25
|
} from "../../shared/types.ts";
|
|
26
|
+
import { unresolvedChildWatchdogBlockers } from "../../watchdog/child-status.ts";
|
|
25
27
|
import { isAgentContractV1 } from "./agent-contract.ts";
|
|
26
28
|
import { classifyTaskMutationIntent, stripSeverityCompounds, taskMayMutate } from "./task-intent.ts";
|
|
27
29
|
|
|
@@ -100,12 +102,13 @@ function inferLevel(input: {
|
|
|
100
102
|
const writeTask = taskMayWrite
|
|
101
103
|
|| (input.acceptanceRole === "writer" && !readOnlyTask)
|
|
102
104
|
|| (input.acceptanceRole === undefined && /\bworker\b/.test(agent) && !readOnlyTask);
|
|
103
|
-
const inferredReadOnly = readOnlyTask || (input.acceptanceRole === "read-only" && !taskMayWrite);
|
|
105
|
+
const inferredReadOnly = readOnlyTask || ((readOnlyAgent || input.acceptanceRole === "read-only") && !taskMayWrite);
|
|
104
106
|
const roleResolvesReadOnly = input.acceptanceRole !== undefined && inferredReadOnly;
|
|
107
|
+
const dynamicResolvesReadOnly = inferredReadOnly && !writeTask;
|
|
105
108
|
const keywordRiskReadOnly = input.acceptanceRole === undefined ? intent.kind === "read-only" : inferredReadOnly;
|
|
106
109
|
const risky = Boolean(input.async && writeTask)
|
|
107
|
-
|| (Boolean(input.dynamic) && !roleResolvesReadOnly)
|
|
108
|
-
|| (Boolean(input.dynamicGroup) && !roleResolvesReadOnly)
|
|
110
|
+
|| (Boolean(input.dynamic) && !roleResolvesReadOnly && !dynamicResolvesReadOnly)
|
|
111
|
+
|| (Boolean(input.dynamicGroup) && !roleResolvesReadOnly && !dynamicResolvesReadOnly)
|
|
109
112
|
|| (!keywordRiskReadOnly && /\b(?:release|migration|migrate|security|data[- ]loss|destructive|post-review|fix pass)\b/.test(task));
|
|
110
113
|
|
|
111
114
|
if (risky) {
|
|
@@ -131,7 +134,7 @@ function inferLevel(input: {
|
|
|
131
134
|
if (readOnlyAgent || readOnlyTask) {
|
|
132
135
|
reasons.push(input.acceptanceRole === "read-only" && !readOnlyTask ? "declared read-only acceptance role" : readOnlyAgent ? "read-only/reviewer-style agent" : "read-only task wording");
|
|
133
136
|
return {
|
|
134
|
-
level: "
|
|
137
|
+
level: "none",
|
|
135
138
|
reasons,
|
|
136
139
|
criteria: ["Return concrete findings with file paths and severity when applicable"],
|
|
137
140
|
evidence: ["review-findings", "residual-risks"],
|
|
@@ -207,6 +210,10 @@ function explicitAcceptanceCanDisable(explicit: AcceptanceConfig): boolean {
|
|
|
207
210
|
return explicit.level === "none" && typeof explicit.reason === "string" && explicit.reason.trim().length > 0;
|
|
208
211
|
}
|
|
209
212
|
|
|
213
|
+
function explicitAcceptanceRequestsPolicy(explicit: AcceptanceConfig): boolean {
|
|
214
|
+
return (explicit.level !== undefined && explicit.level !== "auto") || Object.keys(explicit).some((key) => key !== "level");
|
|
215
|
+
}
|
|
216
|
+
|
|
210
217
|
function unsupportedEvidenceKindMessage(pathLabel: string, item: unknown): string {
|
|
211
218
|
const value = typeof item === "string" ? ` "${item}"` : "";
|
|
212
219
|
return `${pathLabel}${value} is not a supported evidence kind. ${ACCEPTANCE_EVIDENCE_HELP}`;
|
|
@@ -437,12 +444,13 @@ export function resolveEffectiveAcceptance(input: {
|
|
|
437
444
|
};
|
|
438
445
|
}
|
|
439
446
|
const inferred = inferLevel(input);
|
|
447
|
+
const inferredLevel = inferred.level === "none" && explicitAcceptanceRequestsPolicy(explicit) ? "attested" : inferred.level;
|
|
440
448
|
const level = explicitAcceptanceCanDisable(explicit)
|
|
441
449
|
? "none"
|
|
442
450
|
: explicitLevel === "auto"
|
|
443
|
-
?
|
|
444
|
-
: (LEVEL_RANK[explicitLevel] >= LEVEL_RANK[
|
|
445
|
-
const evidence = unique([...(level ===
|
|
451
|
+
? inferredLevel
|
|
452
|
+
: (LEVEL_RANK[explicitLevel] >= LEVEL_RANK[inferredLevel] ? explicitLevel : inferredLevel);
|
|
453
|
+
const evidence = unique([...(level === inferredLevel ? inferred.evidence : requiredEvidenceForLevel(level)), ...(explicit.evidence ?? [])]);
|
|
446
454
|
const criteria = normalizeCriteria(
|
|
447
455
|
(explicit.criteria?.length ? explicit.criteria : inferred.criteria) as Array<string | { id?: string; must?: string; evidence?: AcceptanceEvidenceKind[]; severity?: "required" | "recommended" }>,
|
|
448
456
|
evidence,
|
|
@@ -452,8 +460,8 @@ export function resolveEffectiveAcceptance(input: {
|
|
|
452
460
|
level,
|
|
453
461
|
explicit: input.explicit !== undefined,
|
|
454
462
|
inferredReason: inferred.reasons,
|
|
455
|
-
criteria,
|
|
456
|
-
evidence,
|
|
463
|
+
criteria: level === "none" ? [] : criteria,
|
|
464
|
+
evidence: level === "none" ? [] : evidence,
|
|
457
465
|
verify: explicit.verify ?? [],
|
|
458
466
|
review,
|
|
459
467
|
stopRules: explicit.stopRules ?? [],
|
|
@@ -1354,6 +1362,7 @@ export async function evaluateAcceptance(input: {
|
|
|
1354
1362
|
reportOptional?: boolean;
|
|
1355
1363
|
artifactsDir?: string;
|
|
1356
1364
|
runId?: string;
|
|
1365
|
+
watchdog?: ChildWatchdogProgress;
|
|
1357
1366
|
}): Promise<AcceptanceLedger> {
|
|
1358
1367
|
const acceptance = input.acceptance;
|
|
1359
1368
|
const initialStatus = acceptance.level === "none" ? "not-required" : "claimed";
|
|
@@ -1369,6 +1378,13 @@ export async function evaluateAcceptance(input: {
|
|
|
1369
1378
|
};
|
|
1370
1379
|
if (acceptance.level === "none") return ledger;
|
|
1371
1380
|
|
|
1381
|
+
if (input.watchdog) {
|
|
1382
|
+
const unresolved = unresolvedChildWatchdogBlockers(input.watchdog);
|
|
1383
|
+
ledger.runtimeChecks.push(unresolved.length
|
|
1384
|
+
? { id: "watchdog-blocker", status: "failed", message: `Unresolved watchdog blocker: ${unresolved[0]!.summary}` }
|
|
1385
|
+
: { id: "watchdog-blocker", status: "passed", message: "No unresolved watchdog blockers." });
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1372
1388
|
const parsed: AcceptanceReportParseResult = input.reportError
|
|
1373
1389
|
? { error: input.reportError }
|
|
1374
1390
|
: input.report !== undefined
|