pi-subagents 0.55.0 → 0.57.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 +81 -3
- package/agents/claude-code-writer.md +15 -0
- package/agents/claude-code.md +15 -0
- package/agents/codex-exec-writer.md +15 -0
- package/agents/codex-exec.md +15 -0
- package/agents/cursor-agent-writer.md +14 -0
- package/agents/cursor-agent.md +14 -0
- package/docs/agents.md +111 -15
- package/docs/configuration.md +37 -0
- package/docs/extension-api.md +2 -2
- package/docs/models.md +6 -0
- package/docs/observability.md +8 -7
- package/docs/tool-reference.md +11 -1
- package/docs/workflows.md +20 -0
- package/package.json +1 -1
- package/skills/pi-subagents/references/execution-controls.md +1 -1
- package/src/agents/agent-management.ts +13 -5
- package/src/agents/agent-refinements.ts +4 -4
- package/src/agents/agent-serializer.ts +2 -0
- package/src/agents/agents.ts +242 -49
- package/src/agents/builtin-names.ts +6 -0
- package/src/agents/runtime-agent-registry.ts +8 -2
- package/src/api/preflight.ts +22 -3
- package/src/extension/config.ts +70 -0
- package/src/extension/doctor.ts +3 -3
- package/src/extension/index.ts +18 -4
- package/src/extension/public-execution.ts +29 -13
- package/src/extension/rpc.ts +20 -5
- package/src/extension/schemas.ts +9 -3
- package/src/extension/tool-description.ts +11 -9
- package/src/inspectors/herdr/actions.ts +2 -1
- package/src/inspectors/herdr/inspector-runner.ts +2 -10
- package/src/inspectors/herdr/session-roots-codec.ts +42 -0
- package/src/integrations/herdr-status.ts +46 -3
- package/src/runs/background/active-async-capacity.ts +77 -10
- package/src/runs/background/async-execution.ts +148 -27
- package/src/runs/background/async-job-tracker.ts +5 -0
- package/src/runs/background/async-resume.ts +3 -0
- package/src/runs/background/async-retention.ts +20 -3
- package/src/runs/background/async-status.ts +5 -0
- package/src/runs/background/chain-root-attachment.ts +15 -1
- package/src/runs/background/fleet-view.ts +16 -10
- package/src/runs/background/inspect-rpc.ts +8 -8
- package/src/runs/background/result-files.ts +27 -14
- package/src/runs/background/result-watcher.ts +9 -5
- package/src/runs/background/run-status.ts +33 -6
- package/src/runs/background/scheduled-runs.ts +7 -1
- package/src/runs/background/subagent-runner.ts +254 -49
- package/src/runs/background/wait-completions.ts +4 -0
- package/src/runs/foreground/execution.ts +107 -16
- package/src/runs/foreground/foreground-control.ts +6 -0
- package/src/runs/foreground/foreground-history.ts +25 -3
- package/src/runs/foreground/subagent-executor.ts +324 -84
- package/src/runs/foreground/workflow-detach-reconcile.ts +31 -7
- package/src/runs/shared/acceptance.ts +10 -5
- package/src/runs/shared/agent-contract.ts +1 -1
- package/src/runs/shared/child-protocol.ts +21 -7
- package/src/runs/shared/claude-code-adapter.ts +129 -0
- package/src/runs/shared/codex-exec-adapter.ts +129 -0
- package/src/runs/shared/completion-guard.ts +3 -2
- package/src/runs/shared/cursor-agent-adapter.ts +114 -0
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/extension-bindings.ts +78 -0
- package/src/runs/shared/external-cli-contract.ts +167 -0
- package/src/runs/shared/external-cli-preflight.ts +122 -0
- package/src/runs/shared/external-cli-runner.ts +349 -54
- package/src/runs/shared/fast-mode-extension.ts +10 -0
- package/src/runs/shared/model-exclusions.ts +59 -8
- package/src/runs/shared/model-fallback.ts +25 -8
- package/src/runs/shared/mutation-evidence.ts +150 -0
- package/src/runs/shared/nested-events.ts +3 -1
- package/src/runs/shared/nested-render.ts +2 -2
- package/src/runs/shared/parallel-utils.ts +3 -0
- package/src/runs/shared/pi-args.ts +47 -0
- package/src/runs/shared/process-signal.ts +13 -0
- package/src/runs/shared/run-history.ts +21 -1
- package/src/runs/shared/structured-output.ts +18 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +9 -5
- package/src/shared/fork-context.ts +21 -0
- package/src/shared/formatters.ts +7 -1
- package/src/shared/launch-contract.ts +6 -0
- package/src/shared/pruned-fork.ts +450 -0
- package/src/shared/session-file-trust.ts +19 -0
- package/src/shared/session-tokens.ts +14 -3
- package/src/shared/settings.ts +16 -3
- package/src/shared/shortcuts.ts +17 -0
- package/src/shared/types.ts +166 -9
- package/src/shared/workflow-child-permit.ts +116 -0
- package/src/slash/delegation-adapters.ts +0 -1
- package/src/slash/slash-commands.ts +8 -6
- package/src/tui/fleet-status.ts +27 -10
- package/src/tui/fleet-transcript.ts +11 -5
- package/src/tui/fleet.ts +28 -13
- package/src/tui/render.ts +47 -21
- package/src/workflows/scripted-workflow.ts +298 -30
- package/src/workflows/workflow-child-summary.ts +117 -0
- package/src/workflows/workflow-receipt.ts +119 -4
|
@@ -80,13 +80,14 @@ import {
|
|
|
80
80
|
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
|
|
81
81
|
import { readRuntimeAcknowledgedExtensions } from "../shared/runtime-acknowledged-extensions.ts";
|
|
82
82
|
import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.ts";
|
|
83
|
-
import { createStructuredOutputRuntime, MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput } from "../shared/structured-output.ts";
|
|
84
|
-
import { formatProcessSignalError, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
83
|
+
import { createStructuredOutputRuntime, MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput, readStructuredOutputAcceptanceReport } from "../shared/structured-output.ts";
|
|
84
|
+
import { formatMidToolExitError, formatProcessSignalError, isOrdinaryToolForMidToolExit, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
85
85
|
import { readChildToolDiagnosticError } from "../shared/tool-availability.ts";
|
|
86
|
+
import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.ts";
|
|
86
87
|
import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection } from "../shared/dynamic-fanout.ts";
|
|
87
88
|
import { claimRunFanoutBatch, getRunFanoutBudgetSnapshot } from "../shared/run-fanout-budget.ts";
|
|
88
89
|
import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent } from "../shared/nested-events.ts";
|
|
89
|
-
import { formatModelAttemptNote, formatSubagentModelVerificationError, isContextOverflow,
|
|
90
|
+
import { formatModelAttemptNote, formatSubagentModelVerificationError, isContextOverflow, isRetryableModelFailureAttempt, recordRetryableModelFailure } from "../shared/model-fallback.ts";
|
|
90
91
|
import {
|
|
91
92
|
SUBAGENT_STARTUP_RETRY_DELAYS_MS,
|
|
92
93
|
formatSubagentExtensionConflictError,
|
|
@@ -131,6 +132,7 @@ import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts
|
|
|
131
132
|
import { acceptanceFailureMessage, aggregateAcceptanceReport, buildSkippedAcceptanceLedger, evaluateAcceptance, formatAcceptancePrompt, resolveEffectiveAcceptance, stripAcceptanceReport } from "../shared/acceptance.ts";
|
|
132
133
|
import { attachContractProjections, isAgentContractV1 } from "../shared/agent-contract.ts";
|
|
133
134
|
import { waitForImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
135
|
+
import { normalizeExtensionBindings } from "../shared/extension-bindings.ts";
|
|
134
136
|
import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests, statusStepDescription } from "./chain-append.ts";
|
|
135
137
|
import { asyncStatusChildIdentity } from "../shared/child-identity.ts";
|
|
136
138
|
import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, turnBudgetDecision, turnBudgetDeferredNote, turnBudgetDeferredState, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.ts";
|
|
@@ -139,9 +141,13 @@ import { effectiveToolTimeoutMs, formatToolTimeoutMessage, toolTimeoutCallKey }
|
|
|
139
141
|
import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.ts";
|
|
140
142
|
import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup, writePendingParallelHandoff } from "../shared/parallel-handoff.ts";
|
|
141
143
|
import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
|
|
142
|
-
import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, PI_AGGREGATE_EVENT_PROJECTOR, projectChildLifecycle, type ChildLifecycleAction, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
|
|
144
|
+
import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, PI_AGGREGATE_EVENT_PROJECTOR, projectChildLifecycle, type ChildLifecycleAction, type ChildLifecycleState, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
|
|
143
145
|
import { acquireSessionLease, type SessionLeaseRequest } from "../shared/session-lease.ts";
|
|
144
146
|
import { buildExternalCliPrompt, runExternalCli } from "../shared/external-cli-runner.ts";
|
|
147
|
+
import { resolveClaudeCodeLaunch } from "../shared/claude-code-adapter.ts";
|
|
148
|
+
import { resolveCodexExecLaunch } from "../shared/codex-exec-adapter.ts";
|
|
149
|
+
import { resolveCursorAgentLaunch } from "../shared/cursor-agent-adapter.ts";
|
|
150
|
+
import { resolveExternalCliRunnerStatus } from "../shared/external-cli-contract.ts";
|
|
145
151
|
import { runExternalJob } from "../shared/external-job-runner.ts";
|
|
146
152
|
import { createOrcaProgressTab, type OrcaProgressTab } from "../shared/orca-progress-tabs.ts";
|
|
147
153
|
import { decodeSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
@@ -204,6 +210,7 @@ interface SubagentRunConfig {
|
|
|
204
210
|
launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
|
|
205
211
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
|
|
206
212
|
runnerProcessInstanceId?: string;
|
|
213
|
+
launchBarrierToken?: string;
|
|
207
214
|
parentWorkflowRunId?: string;
|
|
208
215
|
workflowKey?: string;
|
|
209
216
|
}
|
|
@@ -229,6 +236,7 @@ interface StepResult {
|
|
|
229
236
|
timedOut?: boolean;
|
|
230
237
|
stopped?: boolean;
|
|
231
238
|
processSignal?: string | null;
|
|
239
|
+
timeoutRecovery?: import("../../shared/types.ts").TimeoutRecoverySummary;
|
|
232
240
|
turnBudget?: TurnBudgetState;
|
|
233
241
|
turnBudgetExceeded?: boolean;
|
|
234
242
|
wrapUpRequested?: boolean;
|
|
@@ -493,6 +501,7 @@ interface ChildUsage {
|
|
|
493
501
|
output?: number;
|
|
494
502
|
outputTokens?: number;
|
|
495
503
|
cacheRead?: number;
|
|
504
|
+
cacheReadTokens?: number;
|
|
496
505
|
cacheWrite?: number;
|
|
497
506
|
cost?: { total?: number };
|
|
498
507
|
}
|
|
@@ -540,6 +549,28 @@ interface RunPiStreamingResult {
|
|
|
540
549
|
processCloseObservedAt?: number;
|
|
541
550
|
processSignal?: string | null;
|
|
542
551
|
processTree: ProcessTreeTerminalV1;
|
|
552
|
+
currentTool?: string;
|
|
553
|
+
currentToolArgs?: string;
|
|
554
|
+
currentPath?: string;
|
|
555
|
+
afterCompactionSettlement?: boolean;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const MAX_CHILD_FAILURE_DIAGNOSTIC_CHARS = 8_192;
|
|
559
|
+
|
|
560
|
+
function formatChildFailureDiagnostic(input: {
|
|
561
|
+
error: string | undefined;
|
|
562
|
+
afterCompactionSettlement?: boolean;
|
|
563
|
+
missingFileOnlyOutput?: string;
|
|
564
|
+
}): string | undefined {
|
|
565
|
+
if (!input.error) return undefined;
|
|
566
|
+
const notes = [
|
|
567
|
+
input.afterCompactionSettlement ? "Child failure followed session compaction and agent settlement." : undefined,
|
|
568
|
+
input.missingFileOnlyOutput ? `Required file-only output was not produced: ${input.missingFileOnlyOutput.slice(0, 2_048)}` : undefined,
|
|
569
|
+
].filter((note): note is string => Boolean(note));
|
|
570
|
+
if (notes.length === 0) return input.error;
|
|
571
|
+
const context = notes.join("\n");
|
|
572
|
+
const errorLimit = MAX_CHILD_FAILURE_DIAGNOSTIC_CHARS - (context ? context.length + 1 : 0);
|
|
573
|
+
return `${input.error.slice(0, Math.max(0, errorLimit))}${context ? `\n${context}` : ""}`;
|
|
543
574
|
}
|
|
544
575
|
|
|
545
576
|
function runPiStreaming(
|
|
@@ -610,9 +641,54 @@ function runPiStreaming(
|
|
|
610
641
|
let observedMutationAttempt = false;
|
|
611
642
|
let structuredOutputToolInvoked = false;
|
|
612
643
|
let structuredOutputMessageStartIndex: number | undefined;
|
|
644
|
+
let currentTool: string | undefined;
|
|
645
|
+
let currentToolArgs: string | undefined;
|
|
646
|
+
let currentPath: string | undefined;
|
|
613
647
|
let toolCount = 0;
|
|
648
|
+
type ActiveToolCall = { key: string; tool: string; args?: string; path?: string };
|
|
649
|
+
let activeToolSequence = 0;
|
|
650
|
+
const activeToolCalls = new Map<string, ActiveToolCall>();
|
|
651
|
+
const activeToolKeysByName = new Map<string, string[]>();
|
|
652
|
+
const refreshCurrentTool = (): void => {
|
|
653
|
+
const active = [...activeToolCalls.values()].at(-1);
|
|
654
|
+
currentTool = active?.tool;
|
|
655
|
+
currentToolArgs = active?.args;
|
|
656
|
+
currentPath = active?.path;
|
|
657
|
+
};
|
|
658
|
+
const recordActiveToolCall = (event: { toolCallId?: unknown; toolName: string; args?: Record<string, unknown> }): void => {
|
|
659
|
+
const key = toolTimeoutCallKey(event, ++activeToolSequence);
|
|
660
|
+
const active = omitUndefinedProperties({
|
|
661
|
+
key,
|
|
662
|
+
tool: event.toolName,
|
|
663
|
+
args: extractToolArgsPreview(event.args ?? {}),
|
|
664
|
+
path: resolveCurrentPath(event.toolName, event.args),
|
|
665
|
+
});
|
|
666
|
+
activeToolCalls.set(key, active);
|
|
667
|
+
const keys = activeToolKeysByName.get(active.tool) ?? [];
|
|
668
|
+
keys.push(key);
|
|
669
|
+
activeToolKeysByName.set(active.tool, keys);
|
|
670
|
+
refreshCurrentTool();
|
|
671
|
+
};
|
|
672
|
+
const removeActiveToolCall = (event: { toolCallId?: unknown; toolName?: unknown }): void => {
|
|
673
|
+
const key = typeof event.toolCallId === "string" && event.toolCallId.length > 0
|
|
674
|
+
? `id:${event.toolCallId}`
|
|
675
|
+
: typeof event.toolName === "string"
|
|
676
|
+
? activeToolKeysByName.get(event.toolName)?.[0]
|
|
677
|
+
: activeToolCalls.size === 1
|
|
678
|
+
? [...activeToolCalls.keys()][0]
|
|
679
|
+
: undefined;
|
|
680
|
+
if (!key) return;
|
|
681
|
+
const active = activeToolCalls.get(key);
|
|
682
|
+
if (!active) return;
|
|
683
|
+
activeToolCalls.delete(key);
|
|
684
|
+
const keys = activeToolKeysByName.get(active.tool)?.filter((candidate) => candidate !== key) ?? [];
|
|
685
|
+
if (keys.length > 0) activeToolKeysByName.set(active.tool, keys);
|
|
686
|
+
else activeToolKeysByName.delete(active.tool);
|
|
687
|
+
refreshCurrentTool();
|
|
688
|
+
};
|
|
614
689
|
const childWatchdogConfig = decodeChildWatchdogConfig(env?.[CHILD_WATCHDOG_CONFIG_ENV]);
|
|
615
690
|
let childWatchdogState: ChildWatchdogStateSnapshot | undefined;
|
|
691
|
+
const childLifecycleState: ChildLifecycleState = { compactionRetryActive: false };
|
|
616
692
|
let applyChildLifecycle = (_action: ChildLifecycleAction): void => {};
|
|
617
693
|
const updateChildWatchdogState = (snapshot: ChildWatchdogStateSnapshot): void => {
|
|
618
694
|
childWatchdogState = snapshot;
|
|
@@ -663,8 +739,10 @@ function runPiStreaming(
|
|
|
663
739
|
|
|
664
740
|
appendChildEvent(event as unknown as Record<string, unknown>);
|
|
665
741
|
transcriptWriter?.writeChildEvent(event);
|
|
666
|
-
if (event.type === "
|
|
667
|
-
|
|
742
|
+
if (event.type === "compaction_start") compactionStartedReceived = true;
|
|
743
|
+
const lifecycleAction = projectChildLifecycle(event, false, childLifecycleState);
|
|
744
|
+
if (event.type === "agent_settled" && lifecycleAction === "start-drain") agentSettledReceived = true;
|
|
745
|
+
applyChildLifecycle(lifecycleAction);
|
|
668
746
|
|
|
669
747
|
if (isChildWatchdogStatusEvent(event)) {
|
|
670
748
|
if (!childWatchdogConfig) return;
|
|
@@ -701,12 +779,14 @@ function runPiStreaming(
|
|
|
701
779
|
|
|
702
780
|
if (event.type === "tool_execution_end") {
|
|
703
781
|
clearActiveToolTimeout(event);
|
|
782
|
+
removeActiveToolCall(event);
|
|
704
783
|
return;
|
|
705
784
|
}
|
|
706
785
|
|
|
707
786
|
if (event.type === "tool_execution_start" && event.toolName) {
|
|
708
787
|
toolCount += 1;
|
|
709
788
|
armToolTimeout({ toolCallId: (event as { toolCallId?: unknown }).toolCallId, toolName: event.toolName });
|
|
789
|
+
recordActiveToolCall({ toolCallId: (event as { toolCallId?: unknown }).toolCallId, toolName: event.toolName, args: event.args });
|
|
710
790
|
if (event.toolName === "structured_output") {
|
|
711
791
|
structuredOutputToolInvoked = true;
|
|
712
792
|
structuredOutputMessageStartIndex = messages.length;
|
|
@@ -718,6 +798,13 @@ function runPiStreaming(
|
|
|
718
798
|
}
|
|
719
799
|
|
|
720
800
|
if ((event.type === "message_end" || event.type === "tool_result_end") && event.message) {
|
|
801
|
+
if (event.type === "tool_result_end") {
|
|
802
|
+
clearActiveToolTimeout(event);
|
|
803
|
+
removeActiveToolCall({
|
|
804
|
+
toolCallId: (event.message as { toolCallId?: unknown }).toolCallId ?? (event as { toolCallId?: unknown }).toolCallId,
|
|
805
|
+
toolName: (event.message as { toolName?: unknown }).toolName ?? event.toolName,
|
|
806
|
+
});
|
|
807
|
+
}
|
|
721
808
|
messages.push(event.message);
|
|
722
809
|
const text = extractTextFromContent(event.message.content);
|
|
723
810
|
if (text) writeOutputText(text);
|
|
@@ -744,7 +831,11 @@ function runPiStreaming(
|
|
|
744
831
|
if (isTerminalAssistantStop(event.message)) {
|
|
745
832
|
if (!event.message.errorMessage && extractTextFromContent(event.message.content).trim()) assistantError = undefined;
|
|
746
833
|
cleanTerminalAssistantStopReceived ||= !event.message.errorMessage;
|
|
747
|
-
|
|
834
|
+
clearAllToolTimeouts();
|
|
835
|
+
activeToolCalls.clear();
|
|
836
|
+
activeToolKeysByName.clear();
|
|
837
|
+
refreshCurrentTool();
|
|
838
|
+
applyChildLifecycle(projectChildLifecycle(event, true, childLifecycleState));
|
|
748
839
|
}
|
|
749
840
|
}
|
|
750
841
|
};
|
|
@@ -757,6 +848,7 @@ function runPiStreaming(
|
|
|
757
848
|
let forcedTerminationSignal = false;
|
|
758
849
|
let cleanTerminalAssistantStopReceived = false;
|
|
759
850
|
let agentSettledReceived = false;
|
|
851
|
+
let compactionStartedReceived = false;
|
|
760
852
|
let finalDrainTimer: NodeJS.Timeout | undefined;
|
|
761
853
|
let finalHardKillTimer: NodeJS.Timeout | undefined;
|
|
762
854
|
let watchdogTailTimer: NodeJS.Timeout | undefined;
|
|
@@ -1029,6 +1121,10 @@ function runPiStreaming(
|
|
|
1029
1121
|
processCloseObservedAt,
|
|
1030
1122
|
processSignal: signal,
|
|
1031
1123
|
processTree,
|
|
1124
|
+
currentTool,
|
|
1125
|
+
currentToolArgs,
|
|
1126
|
+
currentPath,
|
|
1127
|
+
afterCompactionSettlement: (compactionStartedReceived && agentSettledReceived) || undefined,
|
|
1032
1128
|
}));
|
|
1033
1129
|
});
|
|
1034
1130
|
|
|
@@ -1207,6 +1303,8 @@ interface SingleStepContext {
|
|
|
1207
1303
|
onExternalProcess?: (process: ExternalProcessStatus) => void;
|
|
1208
1304
|
onExternalJob?: (status: ExternalJobStatus) => void;
|
|
1209
1305
|
skipAcceptance?: () => boolean;
|
|
1306
|
+
/** False when sibling work in the same Git worktree could have caused the tracked diff. */
|
|
1307
|
+
trackedMutationEvidenceForCompletionGuard?: boolean;
|
|
1210
1308
|
orcaProgressTab?: OrcaProgressTab;
|
|
1211
1309
|
}
|
|
1212
1310
|
|
|
@@ -1297,6 +1395,9 @@ async function runSingleStepInner(
|
|
|
1297
1395
|
tools: step.tools,
|
|
1298
1396
|
extensions: step.extensions,
|
|
1299
1397
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
1398
|
+
fast: step.fast,
|
|
1399
|
+
model: step.model,
|
|
1400
|
+
modelCandidates: step.modelCandidates,
|
|
1300
1401
|
mcpDirectTools: step.mcpDirectTools,
|
|
1301
1402
|
cwd: step.cwd ?? ctx.cwd,
|
|
1302
1403
|
requireReadTool: Boolean(step.skills?.length),
|
|
@@ -1329,7 +1430,7 @@ async function runSingleStepInner(
|
|
|
1329
1430
|
}
|
|
1330
1431
|
}
|
|
1331
1432
|
if (step.effectiveAcceptance) {
|
|
1332
|
-
const acceptancePrompt = formatAcceptancePrompt(step.effectiveAcceptance, { reportOptional: isAgentContractV1(step.agentContract) });
|
|
1433
|
+
const acceptancePrompt = formatAcceptancePrompt(step.effectiveAcceptance, { reportOptional: isAgentContractV1(step.agentContract), structuredOutput: Boolean(step.structuredOutput?.acceptanceReportPath) });
|
|
1333
1434
|
if (acceptancePrompt) task = `${task}\n${acceptancePrompt}`;
|
|
1334
1435
|
}
|
|
1335
1436
|
const sessionEnabled = Boolean(step.sessionFile) || ctx.sessionEnabled;
|
|
@@ -1358,21 +1459,29 @@ async function runSingleStepInner(
|
|
|
1358
1459
|
transcriptWriter?.writeInitialUserMessage(`${PROMPT_REDACTED}; live Prompt Audit only.`);
|
|
1359
1460
|
|
|
1360
1461
|
if (step.runner?.type === "external-cli") {
|
|
1361
|
-
const
|
|
1362
|
-
|
|
1363
|
-
command: step.runner.command,
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1462
|
+
const externalCwd = step.cwd ?? ctx.cwd;
|
|
1463
|
+
const adapterLaunch = step.runner.adapter === "codex-exec" || step.runner.adapter === "codex-exec-writer"
|
|
1464
|
+
? resolveCodexExecLaunch({ adapter: step.runner.adapter, command: step.runner.command, asyncDir: path.dirname(ctx.outputFile), stepIndex: ctx.flatIndex })
|
|
1465
|
+
: step.runner.adapter === "claude-code" || step.runner.adapter === "claude-code-writer"
|
|
1466
|
+
? resolveClaudeCodeLaunch({ adapter: step.runner.adapter, command: step.runner.command })
|
|
1467
|
+
: step.runner.adapter === "cursor-agent" || step.runner.adapter === "cursor-agent-writer"
|
|
1468
|
+
? resolveCursorAgentLaunch({ adapter: step.runner.adapter, command: step.runner.command, cwd: externalCwd, asyncDir: path.dirname(ctx.outputFile), stepIndex: ctx.flatIndex })
|
|
1469
|
+
: undefined;
|
|
1470
|
+
const runner = resolveExternalCliRunnerStatus({ ...step.runner, ...(adapterLaunch ? { args: adapterLaunch.args } : {}) });
|
|
1368
1471
|
const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
|
|
1369
1472
|
const external = await runExternalCli(omitUndefinedProperties({
|
|
1370
|
-
command: runner.command,
|
|
1371
|
-
args: runner.args,
|
|
1372
|
-
cwd:
|
|
1473
|
+
command: adapterLaunch?.command ?? runner.command,
|
|
1474
|
+
args: adapterLaunch?.args ?? runner.args,
|
|
1475
|
+
cwd: externalCwd,
|
|
1373
1476
|
prompt: buildExternalCliPrompt(step.systemPrompt ?? "", task),
|
|
1374
1477
|
asyncDir: path.dirname(ctx.outputFile),
|
|
1375
1478
|
stepIndex: ctx.flatIndex,
|
|
1479
|
+
environment: adapterLaunch?.environment,
|
|
1480
|
+
preflight: adapterLaunch?.preflight,
|
|
1481
|
+
parser: adapterLaunch?.parser,
|
|
1482
|
+
finalOutputPath: adapterLaunch?.finalOutputPath,
|
|
1483
|
+
promptFilePath: adapterLaunch?.promptFilePath,
|
|
1484
|
+
temporaryDirectories: adapterLaunch?.temporaryDirectories,
|
|
1376
1485
|
registerTimeout: ctx.registerTimeout,
|
|
1377
1486
|
registerStop: ctx.registerStop,
|
|
1378
1487
|
timeoutMessage: ctx.timeoutMessage,
|
|
@@ -1500,11 +1609,15 @@ async function runSingleStepInner(
|
|
|
1500
1609
|
const eventsPath = path.join(path.dirname(ctx.outputFile), "events.jsonl");
|
|
1501
1610
|
let finalResult: RunPiStreamingResult | undefined;
|
|
1502
1611
|
let finalOutputSnapshot: SingleOutputSnapshot | undefined;
|
|
1612
|
+
let structuredAcceptanceReport: unknown;
|
|
1613
|
+
let structuredAcceptanceReportError: string | undefined;
|
|
1503
1614
|
let completionGuardTriggeredFinal = false;
|
|
1504
1615
|
let turnBudget = ctx.turnBudget ? initialTurnBudgetState(ctx.turnBudget) : undefined;
|
|
1505
1616
|
let toolBudget = step.toolBudget ? initialToolBudgetState(step.toolBudget) : undefined;
|
|
1506
1617
|
let toolBudgetBlocked = false;
|
|
1507
1618
|
let actualLaunchContractDigest = step.launchContractDigest;
|
|
1619
|
+
const mutationSnapshot = snapshotTrackedMutations(step.cwd ?? ctx.cwd);
|
|
1620
|
+
let finalMutationEvidence = collectTrackedMutationEvidence(mutationSnapshot, step.cwd ?? ctx.cwd);
|
|
1508
1621
|
|
|
1509
1622
|
let modelIndex = 0;
|
|
1510
1623
|
let startupAttemptIndex = 0;
|
|
@@ -1533,6 +1646,7 @@ async function runSingleStepInner(
|
|
|
1533
1646
|
}
|
|
1534
1647
|
}
|
|
1535
1648
|
const watchdogConfig = resolveWatchdogConfig(step.cwd ?? ctx.cwd);
|
|
1649
|
+
const extensionBindings = normalizeExtensionBindings(step.extensionBindings)?.value;
|
|
1536
1650
|
const childWatchdog = watchdogConfig.ok
|
|
1537
1651
|
? resolveChildWatchdogConfig({
|
|
1538
1652
|
config: watchdogConfig.config,
|
|
@@ -1556,6 +1670,8 @@ async function runSingleStepInner(
|
|
|
1556
1670
|
tools: step.tools,
|
|
1557
1671
|
extensions: step.extensions,
|
|
1558
1672
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
1673
|
+
fast: step.fast,
|
|
1674
|
+
modelCandidates: step.modelCandidates,
|
|
1559
1675
|
systemPrompt: appendTurnBudgetSystemPrompt(step.systemPrompt ?? "", ctx.turnBudget),
|
|
1560
1676
|
systemPromptMode: step.systemPromptMode,
|
|
1561
1677
|
mcpDirectTools: step.mcpDirectTools,
|
|
@@ -1587,6 +1703,7 @@ async function runSingleStepInner(
|
|
|
1587
1703
|
childWatchdog,
|
|
1588
1704
|
waitToolEnabled: step.waitToolEnabled,
|
|
1589
1705
|
thinkingCeiling: step.thinkingCeiling,
|
|
1706
|
+
extensionBindings,
|
|
1590
1707
|
}));
|
|
1591
1708
|
if (!launchWarningsEmitted && warnings.length > 0) {
|
|
1592
1709
|
for (const warning of warnings) console.warn(`[pi-subagents] ${warning}`);
|
|
@@ -1597,6 +1714,9 @@ async function runSingleStepInner(
|
|
|
1597
1714
|
tools: step.tools,
|
|
1598
1715
|
extensions: step.extensions,
|
|
1599
1716
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
1717
|
+
fast: step.fast,
|
|
1718
|
+
model: step.model,
|
|
1719
|
+
modelCandidates: step.modelCandidates,
|
|
1600
1720
|
mcpDirectTools: step.mcpDirectTools,
|
|
1601
1721
|
cwd: step.cwd ?? ctx.cwd,
|
|
1602
1722
|
requireReadTool: Boolean(step.skills?.length),
|
|
@@ -1611,6 +1731,7 @@ async function runSingleStepInner(
|
|
|
1611
1731
|
task: step.launchBindingTask ?? task,
|
|
1612
1732
|
...(candidate ? { model: candidate } : {}),
|
|
1613
1733
|
modelCandidates: candidates as string[],
|
|
1734
|
+
...(step.fast !== undefined ? { fast: step.fast } : {}),
|
|
1614
1735
|
...(resolveEffectiveThinking(candidate, step.thinking) ? { thinking: resolveEffectiveThinking(candidate, step.thinking) } : {}),
|
|
1615
1736
|
...(step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {}),
|
|
1616
1737
|
systemPrompt: appendTurnBudgetSystemPrompt(step.systemPrompt ?? "", ctx.turnBudget),
|
|
@@ -1624,6 +1745,7 @@ async function runSingleStepInner(
|
|
|
1624
1745
|
...(step.outputPath ? { outputPath: step.outputPath } : {}),
|
|
1625
1746
|
...(step.outputMode ? { outputMode: step.outputMode } : {}),
|
|
1626
1747
|
...(step.structuredOutputSchema ? { structuredOutputSchema: step.structuredOutputSchema } : {}),
|
|
1748
|
+
...(extensionBindings ? { extensionBindings } : {}),
|
|
1627
1749
|
}));
|
|
1628
1750
|
}
|
|
1629
1751
|
capabilityAudit = attemptCapabilityAudit;
|
|
@@ -1687,11 +1809,25 @@ async function runSingleStepInner(
|
|
|
1687
1809
|
: undefined;
|
|
1688
1810
|
const runtimeAcknowledgedExtensions = readRuntimeAcknowledgedExtensions(runtimeAcknowledgedExtensionsPath);
|
|
1689
1811
|
cleanupTempDir(tempDir);
|
|
1812
|
+
const midToolExitError = run.currentTool
|
|
1813
|
+
&& isOrdinaryToolForMidToolExit(run.currentTool)
|
|
1814
|
+
&& !run.interrupted
|
|
1815
|
+
&& !run.timedOut
|
|
1816
|
+
&& !run.stopped
|
|
1817
|
+
&& !run.turnBudgetExceeded
|
|
1818
|
+
&& !run.protocolError
|
|
1819
|
+
&& !toolAvailabilityError
|
|
1820
|
+
? formatMidToolExitError({
|
|
1821
|
+
toolName: run.currentTool,
|
|
1822
|
+
exitCode: run.exitCode,
|
|
1823
|
+
processSignal: run.processSignal,
|
|
1824
|
+
})
|
|
1825
|
+
: undefined;
|
|
1690
1826
|
|
|
1691
1827
|
let structuredOutput: unknown;
|
|
1692
1828
|
let structuredError: string | undefined;
|
|
1693
1829
|
let validatedStructuredOutput = false;
|
|
1694
|
-
if (effectiveStructuredOutput && run.exitCode === 0 && !run.error && !toolAvailabilityError) {
|
|
1830
|
+
if (effectiveStructuredOutput && run.exitCode === 0 && !run.error && !toolAvailabilityError && !midToolExitError) {
|
|
1695
1831
|
if (!run.structuredOutputToolInvoked) {
|
|
1696
1832
|
structuredError = MISSING_STRUCTURED_OUTPUT_CALL_ERROR;
|
|
1697
1833
|
} else {
|
|
@@ -1703,6 +1839,9 @@ async function runSingleStepInner(
|
|
|
1703
1839
|
if (structured.error) structuredError = structured.error;
|
|
1704
1840
|
else {
|
|
1705
1841
|
structuredOutput = structured.value;
|
|
1842
|
+
const acceptanceReport = readStructuredOutputAcceptanceReport(effectiveStructuredOutput);
|
|
1843
|
+
structuredAcceptanceReport = acceptanceReport.value;
|
|
1844
|
+
structuredAcceptanceReportError = acceptanceReport.error;
|
|
1706
1845
|
validatedStructuredOutput = true;
|
|
1707
1846
|
}
|
|
1708
1847
|
}
|
|
@@ -1710,7 +1849,7 @@ async function runSingleStepInner(
|
|
|
1710
1849
|
const errorMessages = validatedStructuredOutput
|
|
1711
1850
|
? run.messages.slice(run.structuredOutputMessageStartIndex ?? run.messages.length)
|
|
1712
1851
|
: run.messages;
|
|
1713
|
-
const hiddenError = run.exitCode === 0 && !run.error && !toolAvailabilityError && !structuredError
|
|
1852
|
+
const hiddenError = run.exitCode === 0 && !run.error && !toolAvailabilityError && !structuredError && !midToolExitError
|
|
1714
1853
|
? detectSubagentError(errorMessages)
|
|
1715
1854
|
: null;
|
|
1716
1855
|
const emptyOutputError = run.exitCode === 0
|
|
@@ -1724,7 +1863,10 @@ async function runSingleStepInner(
|
|
|
1724
1863
|
: undefined;
|
|
1725
1864
|
const completionGuardEnabled = isAgentContractV1(step.agentContract) ? step.completionGuard === true : step.completionGuard !== false;
|
|
1726
1865
|
const completionToolPlan = resolvedTaskToolPlan;
|
|
1727
|
-
const
|
|
1866
|
+
const mutationEvidence = collectTrackedMutationEvidence(mutationSnapshot, step.cwd ?? ctx.cwd);
|
|
1867
|
+
finalMutationEvidence = mutationEvidence;
|
|
1868
|
+
const completionMutationEvidence = ctx.trackedMutationEvidenceForCompletionGuard === false ? undefined : mutationEvidence;
|
|
1869
|
+
const completionGuard = run.exitCode === 0 && !run.error && !structuredError && !hiddenError?.hasError && !midToolExitError && !emptyOutputError && completionGuardEnabled
|
|
1728
1870
|
? evaluateCompletionMutationGuard(omitUndefinedProperties({
|
|
1729
1871
|
agent: step.agent,
|
|
1730
1872
|
task: taskForCompletionGuard,
|
|
@@ -1732,15 +1874,18 @@ async function runSingleStepInner(
|
|
|
1732
1874
|
tools: completionToolPlan ? (completionToolPlan.explicitToolAllowlist ? completionToolPlan.effectiveToolAllowlist : undefined) : step.tools,
|
|
1733
1875
|
mcpDirectTools: completionToolPlan?.effectiveMcpTools ?? step.mcpDirectTools,
|
|
1734
1876
|
toolAvailabilityError,
|
|
1877
|
+
mutationEvidence: completionMutationEvidence,
|
|
1735
1878
|
}))
|
|
1736
1879
|
: undefined;
|
|
1737
|
-
const
|
|
1880
|
+
const mutationAttemptObserved = run.observedMutationAttempt === true || completionMutationEvidence?.attemptedMutation === true;
|
|
1881
|
+
const completionGuardTriggered = completionGuard?.triggered === true && !mutationAttemptObserved;
|
|
1738
1882
|
const completionGuardBlocked = completionGuard?.blocked === true;
|
|
1739
1883
|
const fileMutationEffect = completionGuard
|
|
1740
1884
|
? {
|
|
1741
1885
|
status: completionGuardBlocked ? "blocked" as const : completionGuard.expectedMutation ? completionGuardTriggered ? "missing" as const : "observed" as const : "not-applicable" as const,
|
|
1742
1886
|
expected: completionGuard.expectedMutation,
|
|
1743
|
-
attempted: completionGuardBlocked ? false : completionGuard.attemptedMutation ||
|
|
1887
|
+
attempted: completionGuardBlocked ? false : completionGuard.attemptedMutation || mutationAttemptObserved,
|
|
1888
|
+
...(completionMutationEvidence ? { evidence: completionMutationEvidence } : {}),
|
|
1744
1889
|
...(completionGuardBlocked && completionGuard.message ? { message: completionGuard.message } : {}),
|
|
1745
1890
|
...(completionGuardTriggered ? { message: "Subagent completed without making edits for an implementation task." } : {}),
|
|
1746
1891
|
}
|
|
@@ -1748,7 +1893,7 @@ async function runSingleStepInner(
|
|
|
1748
1893
|
const completionGuardError = completionGuardTriggered && !isAgentContractV1(step.agentContract)
|
|
1749
1894
|
? "Subagent completed without making edits for an implementation task.\nIt appears to have returned planning or scratchpad output instead of applying changes."
|
|
1750
1895
|
: undefined;
|
|
1751
|
-
const effectiveExitCode = toolAvailabilityError || (completionGuardTriggered && !isAgentContractV1(step.agentContract)) || structuredError || emptyOutputError
|
|
1896
|
+
const effectiveExitCode = toolAvailabilityError || (completionGuardTriggered && !isAgentContractV1(step.agentContract)) || midToolExitError || structuredError || emptyOutputError
|
|
1752
1897
|
? 1
|
|
1753
1898
|
: hiddenError?.hasError
|
|
1754
1899
|
? (hiddenError.exitCode ?? 1)
|
|
@@ -1765,6 +1910,7 @@ async function runSingleStepInner(
|
|
|
1765
1910
|
const error = formatSubagentExtensionConflictError(
|
|
1766
1911
|
toolAvailabilityError
|
|
1767
1912
|
?? completionGuardError
|
|
1913
|
+
?? midToolExitError
|
|
1768
1914
|
?? structuredError
|
|
1769
1915
|
?? emptyOutputError
|
|
1770
1916
|
?? (hiddenError?.hasError
|
|
@@ -1844,7 +1990,7 @@ async function runSingleStepInner(
|
|
|
1844
1990
|
finalResult.finalOutput = startupError;
|
|
1845
1991
|
break modelAttemptsLoop;
|
|
1846
1992
|
}
|
|
1847
|
-
const retryableModelFailure =
|
|
1993
|
+
const retryableModelFailure = isRetryableModelFailureAttempt({ error, messages: run.messages, toolCount: run.toolCount });
|
|
1848
1994
|
if (retryableModelFailure) recordRetryableModelFailure(candidate ?? run.model ?? step.model, error);
|
|
1849
1995
|
if (isContextOverflow(error)) {
|
|
1850
1996
|
contextOverflow = true;
|
|
@@ -1890,6 +2036,21 @@ async function runSingleStepInner(
|
|
|
1890
2036
|
: resolvedOutput.savedPath
|
|
1891
2037
|
? "unknown"
|
|
1892
2038
|
: finalResult?.outputState ?? "unknown";
|
|
2039
|
+
const timeoutRecovery = finalResult?.timedOut === true || ctx.timeoutSignal?.aborted === true
|
|
2040
|
+
? buildTimeoutRecoverySummary({
|
|
2041
|
+
termination: "timed-out",
|
|
2042
|
+
evidence: finalMutationEvidence,
|
|
2043
|
+
currentTool: finalResult?.currentTool,
|
|
2044
|
+
currentToolArgs: finalResult?.currentToolArgs,
|
|
2045
|
+
currentPath: finalResult?.currentPath,
|
|
2046
|
+
sessionFile: step.sessionFile,
|
|
2047
|
+
transcriptPath: transcriptWriter ? artifactPaths?.transcriptPath : undefined,
|
|
2048
|
+
artifactPaths,
|
|
2049
|
+
})
|
|
2050
|
+
: undefined;
|
|
2051
|
+
if (timeoutRecovery) outputForSummary = outputForSummary.trim()
|
|
2052
|
+
? `${outputForSummary}\n\n${timeoutRecovery.message}`
|
|
2053
|
+
: timeoutRecovery.message;
|
|
1893
2054
|
const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
|
|
1894
2055
|
fullOutput: outputForSummary,
|
|
1895
2056
|
outputPath: step.outputPath,
|
|
@@ -1904,6 +2065,8 @@ async function runSingleStepInner(
|
|
|
1904
2065
|
? await evaluateAcceptance(omitUndefinedProperties({
|
|
1905
2066
|
acceptance: step.effectiveAcceptance,
|
|
1906
2067
|
output: outputForAcceptance,
|
|
2068
|
+
report: structuredAcceptanceReport as import("../../shared/types.ts").AcceptanceReport | undefined,
|
|
2069
|
+
reportError: structuredAcceptanceReportError,
|
|
1907
2070
|
fileOutput: childWrittenOutput !== undefined && step.outputPath
|
|
1908
2071
|
? { content: childWrittenOutput, path: step.outputPath, authoritative: step.outputMode === "file-only" }
|
|
1909
2072
|
: undefined,
|
|
@@ -1931,7 +2094,7 @@ async function runSingleStepInner(
|
|
|
1931
2094
|
const acceptanceCanFailRun = acceptanceFailure && effectiveAcceptance?.explicit && (finalResult?.exitCode ?? 1) === 0 && !finalResult?.interrupted && !timedOutAfterAcceptance && !stoppedAfterAcceptance && !turnBudgetExceeded && !isAgentContractV1(step.agentContract);
|
|
1932
2095
|
const effectiveFinalExitCode = timedOutAfterAcceptance || stoppedAfterAcceptance || turnBudgetExceeded ? 1 : acceptanceCanFailRun ? 1 : finalResult?.exitCode ?? 1;
|
|
1933
2096
|
const intercomDetachReceipt = finalResult?.finalOutput === INTERCOM_DETACH_RECEIPT;
|
|
1934
|
-
const
|
|
2097
|
+
const baseFinalError = stoppedAfterAcceptance
|
|
1935
2098
|
? ctx.stopMessage ?? "Subagent stopped by user."
|
|
1936
2099
|
: timedOutAfterAcceptance
|
|
1937
2100
|
? finalResult?.error ?? ctx.timeoutMessage ?? "Subagent timed out."
|
|
@@ -1940,6 +2103,17 @@ async function runSingleStepInner(
|
|
|
1940
2103
|
: acceptanceCanFailRun
|
|
1941
2104
|
? (finalResult?.error ? `${finalResult.error}\n${acceptanceFailure}` : acceptanceFailure)
|
|
1942
2105
|
: finalResult?.error ?? (intercomDetachReceipt ? INTERCOM_DETACH_RECEIPT : undefined);
|
|
2106
|
+
const effectiveFinalError = formatChildFailureDiagnostic({
|
|
2107
|
+
error: baseFinalError,
|
|
2108
|
+
afterCompactionSettlement: finalResult?.afterCompactionSettlement,
|
|
2109
|
+
missingFileOnlyOutput: effectiveFinalExitCode !== 0
|
|
2110
|
+
&& finalResult?.afterCompactionSettlement
|
|
2111
|
+
&& step.outputMode === "file-only"
|
|
2112
|
+
&& step.outputPath
|
|
2113
|
+
&& !fs.existsSync(step.outputPath)
|
|
2114
|
+
? step.outputPath
|
|
2115
|
+
: undefined,
|
|
2116
|
+
});
|
|
1943
2117
|
|
|
1944
2118
|
const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
|
|
1945
2119
|
? persistStepArtifacts({
|
|
@@ -1999,6 +2173,7 @@ async function runSingleStepInner(
|
|
|
1999
2173
|
timedOut: timedOutAfterAcceptance ? true : finalResult?.timedOut,
|
|
2000
2174
|
stopped: stoppedAfterAcceptance ? true : finalResult?.stopped,
|
|
2001
2175
|
processSignal: finalResult?.processSignal,
|
|
2176
|
+
timeoutRecovery,
|
|
2002
2177
|
turnBudget,
|
|
2003
2178
|
turnBudgetExceeded: turnBudgetExceeded || undefined,
|
|
2004
2179
|
wrapUpRequested: finalResult?.wrapUpRequested || turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined,
|
|
@@ -2035,13 +2210,7 @@ type RunnerStatusStep = NonNullable<AsyncStatus["steps"]>[number] & {
|
|
|
2035
2210
|
|
|
2036
2211
|
function externalRunnerStatus(runner: SubagentStep["runner"]): ExternalCliRunnerStatus | ExternalJobRunnerStatus | undefined {
|
|
2037
2212
|
if (runner?.type === "external-cli") {
|
|
2038
|
-
return
|
|
2039
|
-
type: "external-cli",
|
|
2040
|
-
command: runner.command,
|
|
2041
|
-
args: runner.args ?? [],
|
|
2042
|
-
promptDelivery: runner.promptDelivery ?? "stdin",
|
|
2043
|
-
capabilities: { stop: true, steer: false, resume: false, structuredOutput: false, toolEvents: false },
|
|
2044
|
-
};
|
|
2213
|
+
return resolveExternalCliRunnerStatus(runner);
|
|
2045
2214
|
}
|
|
2046
2215
|
if (runner?.type === "external-job") {
|
|
2047
2216
|
return {
|
|
@@ -3453,12 +3622,13 @@ async function runSubagent(
|
|
|
3453
3622
|
if (usage) {
|
|
3454
3623
|
const input = usage.input ?? usage.inputTokens ?? 0;
|
|
3455
3624
|
const output = usage.output ?? usage.outputTokens ?? 0;
|
|
3625
|
+
const window = input + (usage.cacheRead ?? usage.cacheReadTokens ?? 0);
|
|
3456
3626
|
const previousInput = step.tokens?.input ?? 0;
|
|
3457
3627
|
const previousOutput = step.tokens?.output ?? 0;
|
|
3458
|
-
step.tokens = { input: previousInput + input, output: previousOutput + output, total: previousInput + previousOutput + input + output };
|
|
3628
|
+
step.tokens = { input: previousInput + input, output: previousOutput + output, total: previousInput + previousOutput + input + output, window, windowPeak: Math.max(step.tokens?.windowPeak ?? 0, window) };
|
|
3459
3629
|
const totalInput = statusPayload.totalTokens?.input ?? 0;
|
|
3460
3630
|
const totalOutput = statusPayload.totalTokens?.output ?? 0;
|
|
3461
|
-
statusPayload.totalTokens = { input: totalInput + input, output: totalOutput + output, total: totalInput + totalOutput + input + output };
|
|
3631
|
+
statusPayload.totalTokens = { input: totalInput + input, output: totalOutput + output, total: totalInput + totalOutput + input + output, window, windowPeak: Math.max(statusPayload.totalTokens?.windowPeak ?? 0, window) };
|
|
3462
3632
|
refreshUsageBudget();
|
|
3463
3633
|
}
|
|
3464
3634
|
statusPayload.turnCount = Math.max(statusPayload.turnCount ?? 0, step.turnCount);
|
|
@@ -4013,6 +4183,7 @@ async function runSubagent(
|
|
|
4013
4183
|
registerTurnBudgetAbort: (abort) => registerStepTurnBudgetAbort(fi, abort),
|
|
4014
4184
|
timeoutSignal: timeoutAbortController.signal,
|
|
4015
4185
|
stopSignal: stopAbortController.signal,
|
|
4186
|
+
trackedMutationEvidenceForCompletionGuard: false,
|
|
4016
4187
|
timeoutMessage,
|
|
4017
4188
|
stopMessage,
|
|
4018
4189
|
turnBudget: config.turnBudget,
|
|
@@ -4072,6 +4243,7 @@ async function runSubagent(
|
|
|
4072
4243
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
|
|
4073
4244
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
|
|
4074
4245
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
|
|
4246
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "timeoutRecovery", singleResult.timeoutRecovery);
|
|
4075
4247
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
|
|
4076
4248
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
|
|
4077
4249
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
|
|
@@ -4087,7 +4259,7 @@ async function runSubagent(
|
|
|
4087
4259
|
}));
|
|
4088
4260
|
if (stopped || childStopped) appendTerminalChildStatusEvent(fi, taskEndTime);
|
|
4089
4261
|
if (singleResult.exitCode !== 0 && failFast && !childStopped) aborted = true;
|
|
4090
|
-
return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: timeoutMessage ?? "Subagent timed out.", error: timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
|
|
4262
|
+
return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: singleResult.output || (timeoutMessage ?? "Subagent timed out."), error: singleResult.error ?? timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
|
|
4091
4263
|
}, globalSemaphore);
|
|
4092
4264
|
|
|
4093
4265
|
flatIndex += dynamicSteps.length;
|
|
@@ -4127,6 +4299,7 @@ async function runSubagent(
|
|
|
4127
4299
|
effects: pr.effects,
|
|
4128
4300
|
execution: pr.execution,
|
|
4129
4301
|
review: pr.review,
|
|
4302
|
+
timeoutRecovery: pr.timeoutRecovery,
|
|
4130
4303
|
structuredOutput: pr.structuredOutput,
|
|
4131
4304
|
structuredOutputPath: pr.structuredOutputPath,
|
|
4132
4305
|
structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
|
|
@@ -4406,6 +4579,7 @@ async function runSubagent(
|
|
|
4406
4579
|
registerTurnBudgetAbort: (abort) => registerStepTurnBudgetAbort(fi, abort),
|
|
4407
4580
|
timeoutSignal: timeoutAbortController.signal,
|
|
4408
4581
|
stopSignal: stopAbortController.signal,
|
|
4582
|
+
trackedMutationEvidenceForCompletionGuard: Boolean(worktreeSetup),
|
|
4409
4583
|
timeoutMessage,
|
|
4410
4584
|
stopMessage,
|
|
4411
4585
|
turnBudget: config.turnBudget,
|
|
@@ -4470,6 +4644,7 @@ async function runSubagent(
|
|
|
4470
4644
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
|
|
4471
4645
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
|
|
4472
4646
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
|
|
4647
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "timeoutRecovery", singleResult.timeoutRecovery);
|
|
4473
4648
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
|
|
4474
4649
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
|
|
4475
4650
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
|
|
@@ -4500,7 +4675,7 @@ async function runSubagent(
|
|
|
4500
4675
|
}
|
|
4501
4676
|
|
|
4502
4677
|
if (singleResult.exitCode !== 0 && failFast && !childStopped) aborted = true;
|
|
4503
|
-
return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: timeoutMessage ?? "Subagent timed out.", error: timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
|
|
4678
|
+
return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: singleResult.output || (timeoutMessage ?? "Subagent timed out."), error: singleResult.error ?? timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
|
|
4504
4679
|
},
|
|
4505
4680
|
globalSemaphore,
|
|
4506
4681
|
);
|
|
@@ -4512,13 +4687,21 @@ async function runSubagent(
|
|
|
4512
4687
|
const sessionTokens = config.sessionDir
|
|
4513
4688
|
? parseSessionTokens(path.join(config.sessionDir, `parallel-${t}`))
|
|
4514
4689
|
: null;
|
|
4515
|
-
const
|
|
4690
|
+
const fallbackTokens = tokenUsageFromAttempts(parallelResults[t]?.modelAttempts);
|
|
4691
|
+
const observedTokens = requiredStatusStep(statusPayload, fi).tokens;
|
|
4692
|
+
const taskTokens = sessionTokens ?? (fallbackTokens
|
|
4693
|
+
? { ...fallbackTokens, ...(observedTokens?.window !== undefined ? { window: observedTokens.window } : {}), ...(observedTokens?.windowPeak !== undefined ? { windowPeak: observedTokens.windowPeak } : {}) }
|
|
4694
|
+
: null);
|
|
4516
4695
|
if (!taskTokens) continue;
|
|
4517
4696
|
requiredStatusStep(statusPayload, fi).tokens = taskTokens;
|
|
4518
4697
|
previousCumulativeTokens = {
|
|
4519
4698
|
input: previousCumulativeTokens.input + taskTokens.input,
|
|
4520
4699
|
output: previousCumulativeTokens.output + taskTokens.output,
|
|
4521
4700
|
total: previousCumulativeTokens.total + taskTokens.total,
|
|
4701
|
+
...(taskTokens.window !== undefined ? { window: taskTokens.window } : {}),
|
|
4702
|
+
...(previousCumulativeTokens.windowPeak !== undefined || taskTokens.windowPeak !== undefined
|
|
4703
|
+
? { windowPeak: Math.max(previousCumulativeTokens.windowPeak ?? 0, taskTokens.windowPeak ?? 0) }
|
|
4704
|
+
: {}),
|
|
4522
4705
|
};
|
|
4523
4706
|
}
|
|
4524
4707
|
statusPayload.totalTokens = { ...previousCumulativeTokens };
|
|
@@ -4557,10 +4740,11 @@ async function runSubagent(
|
|
|
4557
4740
|
artifactPaths: pr.artifactPaths,
|
|
4558
4741
|
transcriptPath: pr.transcriptPath,
|
|
4559
4742
|
transcriptError: pr.transcriptError,
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4743
|
+
effects: pr.effects,
|
|
4744
|
+
execution: pr.execution,
|
|
4745
|
+
review: pr.review,
|
|
4746
|
+
timeoutRecovery: pr.timeoutRecovery,
|
|
4747
|
+
structuredOutput: pr.structuredOutput,
|
|
4564
4748
|
structuredOutputPath: pr.structuredOutputPath,
|
|
4565
4749
|
structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
|
|
4566
4750
|
acceptance: pr.acceptance,
|
|
@@ -4780,7 +4964,7 @@ async function runSubagent(
|
|
|
4780
4964
|
launchContractDigest: singleResult.launchContractDigest,
|
|
4781
4965
|
launchResolvedExtensions: singleResult.launchResolvedExtensions,
|
|
4782
4966
|
runtimeAcknowledgedExtensions: singleResult.runtimeAcknowledgedExtensions,
|
|
4783
|
-
output: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.output,
|
|
4967
|
+
output: stopped || childStopped ? stopMessage : timedOut ? singleResult.output || (timeoutMessage ?? "Subagent timed out.") : singleResult.output,
|
|
4784
4968
|
outputState: singleResult.outputState,
|
|
4785
4969
|
error: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error,
|
|
4786
4970
|
protocolError: singleResult.protocolError,
|
|
@@ -4799,6 +4983,7 @@ async function runSubagent(
|
|
|
4799
4983
|
effects: singleResult.effects,
|
|
4800
4984
|
execution: singleResult.execution,
|
|
4801
4985
|
review: singleResult.review,
|
|
4986
|
+
timeoutRecovery: singleResult.timeoutRecovery,
|
|
4802
4987
|
structuredOutput: singleResult.structuredOutput,
|
|
4803
4988
|
structuredOutputPath: singleResult.structuredOutputPath,
|
|
4804
4989
|
structuredOutputSchemaPath: singleResult.structuredOutputSchemaPath,
|
|
@@ -4833,17 +5018,27 @@ async function runSubagent(
|
|
|
4833
5018
|
input: cumulativeTokens.input - previousCumulativeTokens.input,
|
|
4834
5019
|
output: cumulativeTokens.output - previousCumulativeTokens.output,
|
|
4835
5020
|
total: cumulativeTokens.total - previousCumulativeTokens.total,
|
|
5021
|
+
...(cumulativeTokens.window !== undefined ? { window: cumulativeTokens.window } : {}),
|
|
5022
|
+
...(cumulativeTokens.windowPeak !== undefined ? { windowPeak: cumulativeTokens.windowPeak } : {}),
|
|
4836
5023
|
}
|
|
4837
5024
|
: null;
|
|
4838
5025
|
if (cumulativeTokens) {
|
|
4839
5026
|
previousCumulativeTokens = cumulativeTokens;
|
|
4840
5027
|
} else {
|
|
4841
|
-
|
|
5028
|
+
const fallbackTokens = tokenUsageFromAttempts(singleResult.modelAttempts);
|
|
5029
|
+
const observedTokens = requiredStatusStep(statusPayload, flatIndex).tokens;
|
|
5030
|
+
stepTokens = fallbackTokens
|
|
5031
|
+
? { ...fallbackTokens, ...(observedTokens?.window !== undefined ? { window: observedTokens.window } : {}), ...(observedTokens?.windowPeak !== undefined ? { windowPeak: observedTokens.windowPeak } : {}) }
|
|
5032
|
+
: null;
|
|
4842
5033
|
if (stepTokens) {
|
|
4843
5034
|
previousCumulativeTokens = {
|
|
4844
5035
|
input: previousCumulativeTokens.input + stepTokens.input,
|
|
4845
5036
|
output: previousCumulativeTokens.output + stepTokens.output,
|
|
4846
5037
|
total: previousCumulativeTokens.total + stepTokens.total,
|
|
5038
|
+
...(stepTokens.window !== undefined ? { window: stepTokens.window } : {}),
|
|
5039
|
+
...(previousCumulativeTokens.windowPeak !== undefined || stepTokens.windowPeak !== undefined
|
|
5040
|
+
? { windowPeak: Math.max(previousCumulativeTokens.windowPeak ?? 0, stepTokens.windowPeak ?? 0) }
|
|
5041
|
+
: {}),
|
|
4847
5042
|
};
|
|
4848
5043
|
}
|
|
4849
5044
|
}
|
|
@@ -4885,6 +5080,7 @@ async function runSubagent(
|
|
|
4885
5080
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputPath", singleResult.structuredOutputPath);
|
|
4886
5081
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
|
|
4887
5082
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "acceptance", singleResult.acceptance);
|
|
5083
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "timeoutRecovery", singleResult.timeoutRecovery);
|
|
4888
5084
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "watchdog", singleResult.watchdog);
|
|
4889
5085
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityCeiling", singleResult.capabilityCeiling);
|
|
4890
5086
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityAudit", singleResult.capabilityAudit);
|
|
@@ -4977,7 +5173,7 @@ async function runSubagent(
|
|
|
4977
5173
|
}
|
|
4978
5174
|
}
|
|
4979
5175
|
|
|
4980
|
-
let summary = results.map((r) => `${r.agent}:\n${r.output}`).join("\n\n");
|
|
5176
|
+
let summary = results.map((r) => `${r.agent}:\n${r.output || (r.exitCode !== 0 ? r.error : undefined) || "(no output)"}`).join("\n\n");
|
|
4981
5177
|
let truncated = false;
|
|
4982
5178
|
|
|
4983
5179
|
if (maxOutput) {
|
|
@@ -5169,6 +5365,7 @@ async function runSubagent(
|
|
|
5169
5365
|
structuredOutputSchemaPath: r.structuredOutputSchemaPath,
|
|
5170
5366
|
acceptance: r.acceptance,
|
|
5171
5367
|
watchdog: r.watchdog,
|
|
5368
|
+
timeoutRecovery: r.timeoutRecovery,
|
|
5172
5369
|
capabilityCeiling: r.capabilityCeiling,
|
|
5173
5370
|
capabilityAudit: r.capabilityAudit,
|
|
5174
5371
|
})),
|
|
@@ -5287,7 +5484,7 @@ async function waitForStartupControl(
|
|
|
5287
5484
|
} catch (error) {
|
|
5288
5485
|
throw new Error(`Failed to read runner startup control '${controlPath}': ${error instanceof Error ? error.message : String(error)}`);
|
|
5289
5486
|
}
|
|
5290
|
-
if (payload.token !== token) throw new Error("Runner startup control token does not match
|
|
5487
|
+
if (payload.token !== token) throw new Error("Runner startup control token does not match.");
|
|
5291
5488
|
if (payload.action === action) return;
|
|
5292
5489
|
if (payload.action !== "ack" && payload.action !== "proceed") throw new Error("Runner startup control action is invalid.");
|
|
5293
5490
|
}
|
|
@@ -5298,7 +5495,7 @@ async function waitForStartupControl(
|
|
|
5298
5495
|
|
|
5299
5496
|
async function runConfiguredSubagent(config: SubagentRunConfig): Promise<void> {
|
|
5300
5497
|
let lease: ReturnType<typeof acquireSessionLease> | undefined;
|
|
5301
|
-
let startupCommitted = config.revivalLease === undefined;
|
|
5498
|
+
let startupCommitted = config.revivalLease === undefined && config.launchBarrierToken === undefined;
|
|
5302
5499
|
const startupPath = path.join(config.asyncDir, "runner-startup.json");
|
|
5303
5500
|
const startupAckPath = path.join(config.asyncDir, "runner-startup-ack.json");
|
|
5304
5501
|
const startupProceedPath = path.join(config.asyncDir, "runner-startup-proceed.json");
|
|
@@ -5311,7 +5508,15 @@ async function runConfiguredSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
5311
5508
|
};
|
|
5312
5509
|
process.once("exit", releaseOnExit);
|
|
5313
5510
|
try {
|
|
5314
|
-
if (config.
|
|
5511
|
+
if (config.launchBarrierToken) {
|
|
5512
|
+
await waitForStartupControl(startupProceedPath, config.launchBarrierToken, "proceed");
|
|
5513
|
+
startupCommitted = true;
|
|
5514
|
+
try {
|
|
5515
|
+
fs.rmSync(startupProceedPath, { force: true });
|
|
5516
|
+
} catch {
|
|
5517
|
+
// Startup control cleanup is best effort after the parent commits the run.
|
|
5518
|
+
}
|
|
5519
|
+
} else if (config.revivalLease) {
|
|
5315
5520
|
lease = acquireSessionLease(config.revivalLease);
|
|
5316
5521
|
config.revivalLeaseToken = lease.owner.token;
|
|
5317
5522
|
writeAtomicJson(startupPath, { state: "ready", token: lease.owner.token, pid: process.pid, owner: lease.owner });
|
|
@@ -5329,7 +5534,7 @@ async function runConfiguredSubagent(config: SubagentRunConfig): Promise<void> {
|
|
|
5329
5534
|
}
|
|
5330
5535
|
await runSubagent(config, lease ? (writer) => lease!.updateWriter(writer) : undefined);
|
|
5331
5536
|
} catch (error) {
|
|
5332
|
-
if (
|
|
5537
|
+
if (!startupCommitted) {
|
|
5333
5538
|
try {
|
|
5334
5539
|
writeAtomicJson(startupPath, { state: "error", pid: process.pid, error: error instanceof Error ? error.message : String(error) });
|
|
5335
5540
|
} catch {
|