pi-subagents 0.40.0 → 0.41.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 +76 -0
- package/README.md +246 -525
- package/agents/oracle.md +1 -0
- package/package.json +12 -4
- package/prompts/parallel-context-build.md +1 -1
- package/prompts/parallel-handoff-plan.md +1 -1
- package/prompts/review-loop.md +1 -1
- package/skills/pi-subagents/SKILL.md +6 -6
- package/skills/pi-subagents/references/constraints-and-recipes.md +19 -26
- package/skills/pi-subagents/references/execution-controls.md +98 -97
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/prompting-and-roles.md +18 -27
- package/src/agents/agent-management.ts +155 -65
- package/src/agents/agent-serializer.ts +19 -0
- package/src/agents/agents.ts +154 -71
- package/src/agents/chain-serializer.ts +10 -7
- package/src/agents/frontmatter.ts +5 -3
- package/src/agents/identity.ts +1 -1
- package/src/agents/proactive-skills.ts +13 -10
- package/src/agents/skills.ts +23 -6
- package/src/api/control-channel.ts +4 -0
- package/src/api/delegation.ts +26 -194
- package/src/api/external-runs.ts +129 -0
- package/src/api/intercom-bridge.ts +3 -0
- package/src/api/pi-args.ts +5 -0
- package/src/api/preflight.ts +3 -3
- package/src/api/shared-types.ts +19 -0
- package/src/extension/config.ts +10 -0
- package/src/extension/control-notices.ts +5 -39
- package/src/extension/doctor.ts +10 -9
- package/src/extension/fanout-child.ts +7 -4
- package/src/extension/index.ts +232 -68
- package/src/extension/rpc.ts +18 -12
- package/src/extension/schemas.ts +48 -37
- package/src/extension/tool-description.ts +36 -86
- package/src/inspectors/herdr/actions.ts +229 -0
- package/src/inspectors/herdr/client.ts +130 -0
- package/src/inspectors/herdr/inspector-runner.ts +141 -0
- package/src/inspectors/herdr/project-panes.ts +154 -0
- package/src/integrations/herdr-status.ts +330 -0
- package/src/intercom/intercom-bridge.ts +3 -2
- package/src/intercom/result-intercom.ts +5 -1
- package/src/missions/actions.ts +372 -0
- package/src/missions/lifecycle.ts +314 -0
- package/src/missions/store.ts +442 -0
- package/src/missions/types.ts +135 -0
- package/src/policy/authority.ts +46 -0
- package/src/profiles/profiles.ts +29 -3
- package/src/runs/background/async-execution.ts +98 -49
- package/src/runs/background/async-job-tracker.ts +10 -2
- package/src/runs/background/async-resume.ts +6 -6
- package/src/runs/background/async-status.ts +29 -1
- package/src/runs/background/auto-drain.ts +3 -3
- package/src/runs/background/chain-append.ts +3 -2
- package/src/runs/background/control-channel.ts +9 -7
- package/src/runs/background/fleet-view.ts +3 -4
- package/src/runs/background/notify.ts +2 -1
- package/src/runs/background/process-terminal.ts +5 -5
- package/src/runs/background/result-watcher.ts +13 -5
- package/src/runs/background/run-id-resolver.ts +3 -3
- package/src/runs/background/run-status.ts +35 -8
- package/src/runs/background/scheduled-runs.ts +602 -375
- package/src/runs/background/stale-run-reconciler.ts +3 -3
- package/src/runs/background/subagent-runner.ts +608 -445
- package/src/runs/background/subagent-wait.ts +50 -9
- package/src/runs/background/wait-subscriptions.ts +253 -0
- package/src/runs/background/wait-tool.ts +12 -4
- package/src/runs/foreground/async-steering-action.ts +3 -3
- package/src/runs/foreground/chain-clarify.ts +8 -4
- package/src/runs/foreground/chain-execution.ts +56 -30
- package/src/runs/foreground/execution.ts +15 -2
- package/src/runs/foreground/subagent-executor.ts +1023 -273
- package/src/runs/shared/acceptance.ts +28 -6
- package/src/runs/shared/child-protocol.ts +302 -22
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/external-cli-runner.ts +130 -0
- package/src/runs/shared/long-running-guard.ts +42 -1
- package/src/runs/shared/nested-events.ts +59 -5
- package/src/runs/shared/nested-render.ts +9 -4
- package/src/runs/shared/parallel-handoff.ts +86 -2
- package/src/runs/shared/parallel-utils.ts +11 -2
- package/src/runs/shared/permissions.ts +95 -0
- package/src/runs/shared/pi-args.ts +11 -1
- package/src/runs/shared/pi-spawn.ts +11 -1
- package/src/runs/shared/run-history.ts +1 -1
- package/src/runs/shared/subagent-prompt-runtime.ts +36 -5
- package/src/runs/shared/subagent-startup-retry.ts +5 -2
- package/src/runs/shared/turn-budget.ts +6 -6
- package/src/runs/shared/worktree.ts +122 -12
- package/src/shared/accessible-dir.ts +29 -7
- package/src/shared/artifacts.ts +18 -1
- package/src/shared/fork-context.ts +3 -2
- package/src/shared/launch-contract.ts +1 -0
- package/src/shared/settings.ts +10 -0
- package/src/shared/types.ts +156 -14
- package/src/shared/utils.ts +8 -6
- package/src/slash/delegation-adapters.ts +32 -194
- package/src/slash/delegation-request.ts +43 -126
- package/src/slash/prompt-template-bridge.ts +158 -205
- package/src/slash/prompt-workflows.ts +21 -57
- package/src/slash/slash-bridge.ts +14 -0
- package/src/slash/slash-commands.ts +31 -632
- package/src/slash/subagents-admin.ts +18 -14
- package/src/tui/fleet-status.ts +156 -21
- package/src/tui/fleet-transcript.ts +110 -5
- package/src/tui/fleet.ts +56 -24
- package/src/tui/render.ts +291 -109
- package/src/types/pi-runtime-compat.d.ts +14 -0
- package/src/watchdog/lsp-diagnostics.ts +12 -7
- package/src/watchdog/model-selection.ts +2 -2
- package/src/watchdog/permission-arbiter.ts +145 -0
- package/src/watchdog/register-child.ts +1 -1
- package/src/watchdog/register-main.ts +1 -1
- package/src/watchdog/review.ts +4 -1
- package/src/watchdog/runtime.ts +3 -2
- package/src/workflows/chat-progress.ts +140 -0
- package/src/workflows/scripted-workflow.ts +415 -0
- package/agents/advisor.md +0 -73
- package/src/extension/chain-validation.ts +0 -181
|
@@ -7,12 +7,14 @@ import type { Message } from "@earendil-works/pi-ai";
|
|
|
7
7
|
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
8
8
|
import { createChildTranscriptWriter, type ChildTranscriptWriter } from "../../shared/child-transcript.ts";
|
|
9
9
|
import { closeSteerInbox, consumeInterruptRequest, consumeSteerRequests, deliverInterruptRequest, deliverStopRequest, deliverTimeoutRequest, enqueueStepSteer, steerAcksDir, steerCapabilityPath, stepSteerInboxDir, watchAsyncControlInbox, type SteerAck, type SteerCapability, type SteerRequest } from "./control-channel.ts";
|
|
10
|
-
import { appendJsonl as appendRawJsonl, formatOutputArtifactContent, getArtifactPaths } from "../../shared/artifacts.ts";
|
|
10
|
+
import { appendJsonl as appendRawJsonl, formatOutputArtifactContent, getArtifactPaths, writeArtifact, writeMetadata } from "../../shared/artifacts.ts";
|
|
11
11
|
import { PI_CODING_AGENT_PACKAGE, getPiSpawnCommand, resolveInstalledPiPackageRoot } from "../shared/pi-spawn.ts";
|
|
12
12
|
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, injectSingleOutputInstruction, resolveSingleOutput, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
13
13
|
import {
|
|
14
14
|
type ActivityState,
|
|
15
15
|
type ArtifactConfig,
|
|
16
|
+
type ExternalCliRunnerStatus,
|
|
17
|
+
type ExternalProcessStatus,
|
|
16
18
|
type ArtifactPaths,
|
|
17
19
|
type AsyncParallelGroupStatus,
|
|
18
20
|
type AsyncStatus,
|
|
@@ -118,10 +120,11 @@ import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChai
|
|
|
118
120
|
import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, turnBudgetDecision, turnBudgetDeferredNote, turnBudgetDeferredState, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.ts";
|
|
119
121
|
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
|
|
120
122
|
import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.ts";
|
|
121
|
-
import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup } from "../shared/parallel-handoff.ts";
|
|
123
|
+
import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup, writePendingParallelHandoff } from "../shared/parallel-handoff.ts";
|
|
122
124
|
import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
|
|
123
|
-
import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, projectChildLifecycle, type ChildLifecycleAction, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
|
|
125
|
+
import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, PI_AGGREGATE_EVENT_PROJECTOR, projectChildLifecycle, type ChildLifecycleAction, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
|
|
124
126
|
import { acquireSessionLease, type SessionLeaseRequest } from "../shared/session-lease.ts";
|
|
127
|
+
import { buildExternalCliPrompt, runExternalCli } from "../shared/external-cli-runner.ts";
|
|
125
128
|
import { decodeSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
|
|
126
129
|
import {
|
|
127
130
|
CHILD_WATCHDOG_CONFIG_ENV,
|
|
@@ -157,6 +160,7 @@ interface SubagentRunConfig {
|
|
|
157
160
|
controlIntercomTarget?: string;
|
|
158
161
|
childIntercomTargets?: Array<string | undefined>;
|
|
159
162
|
resultMode?: SubagentRunMode;
|
|
163
|
+
mode?: SubagentRunMode;
|
|
160
164
|
dynamicFanoutMaxItems?: number;
|
|
161
165
|
workflowGraph?: WorkflowGraphSnapshot;
|
|
162
166
|
nestedRoute?: NestedRouteInfo;
|
|
@@ -175,6 +179,8 @@ interface SubagentRunConfig {
|
|
|
175
179
|
launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
|
|
176
180
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
|
|
177
181
|
runnerProcessInstanceId?: string;
|
|
182
|
+
parentWorkflowRunId?: string;
|
|
183
|
+
workflowKey?: string;
|
|
178
184
|
}
|
|
179
185
|
|
|
180
186
|
interface StepResult {
|
|
@@ -188,8 +194,10 @@ interface StepResult {
|
|
|
188
194
|
outputState?: SubagentOutputState;
|
|
189
195
|
error?: string;
|
|
190
196
|
protocolError?: ProtocolOutputLimit;
|
|
191
|
-
success
|
|
192
|
-
exitCode
|
|
197
|
+
success?: boolean;
|
|
198
|
+
exitCode: number | null;
|
|
199
|
+
usage?: Usage;
|
|
200
|
+
savedOutputPath?: string;
|
|
193
201
|
skipped?: boolean;
|
|
194
202
|
interrupted?: boolean;
|
|
195
203
|
timedOut?: boolean;
|
|
@@ -207,6 +215,8 @@ interface StepResult {
|
|
|
207
215
|
modelAttempts?: ModelAttempt[];
|
|
208
216
|
totalCost?: CostSummary;
|
|
209
217
|
artifactPaths?: ArtifactPaths;
|
|
218
|
+
outputSaveError?: string;
|
|
219
|
+
metadataSaveError?: string;
|
|
210
220
|
truncated?: boolean;
|
|
211
221
|
transcriptPath?: string;
|
|
212
222
|
transcriptError?: string;
|
|
@@ -222,6 +232,32 @@ interface StepResult {
|
|
|
222
232
|
watchdog?: import("../../shared/types.ts").ChildWatchdogProgress;
|
|
223
233
|
writerProcesses?: Array<{ processInstanceId: string; kind: "pi-writer"; attempt: number; closeObservedAt: number; exitCode: number | null; signal: string | null }>;
|
|
224
234
|
writerAttemptCount?: number;
|
|
235
|
+
runner?: ExternalCliRunnerStatus;
|
|
236
|
+
externalProcess?: ExternalProcessStatus;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function persistStepArtifacts(input: {
|
|
240
|
+
artifactPaths: ArtifactPaths;
|
|
241
|
+
artifactConfig?: Partial<ArtifactConfig>;
|
|
242
|
+
output: string;
|
|
243
|
+
metadata: object;
|
|
244
|
+
}): { outputSaveError?: string; metadataSaveError?: string } {
|
|
245
|
+
const errors: { outputSaveError?: string; metadataSaveError?: string } = {};
|
|
246
|
+
if (input.artifactConfig?.includeOutput !== false) {
|
|
247
|
+
try {
|
|
248
|
+
writeArtifact(input.artifactPaths.outputPath, input.output);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
errors.outputSaveError = `Artifact output post-processing failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (input.artifactConfig?.includeMetadata !== false) {
|
|
254
|
+
try {
|
|
255
|
+
writeMetadata(input.artifactPaths.metadataPath, input.metadata);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
errors.metadataSaveError = `Artifact metadata post-processing failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return errors;
|
|
225
261
|
}
|
|
226
262
|
|
|
227
263
|
const ASYNC_INTERRUPT_SIGNAL: NodeJS.Signals = process.platform === "win32" ? "SIGBREAK" : "SIGUSR2";
|
|
@@ -373,11 +409,44 @@ function isTerminalAssistantStop(message: Message): boolean {
|
|
|
373
409
|
return (message as { stopReason?: string }).stopReason === "stop" && !assistantStartsToolCall(message);
|
|
374
410
|
}
|
|
375
411
|
|
|
412
|
+
type UndefinedOmitted<T extends object> = {
|
|
413
|
+
[K in keyof T]: Exclude<T[K], undefined>;
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
function omitUndefinedProperties<const T extends object>(value: T): UndefinedOmitted<T> {
|
|
417
|
+
for (const key in value) {
|
|
418
|
+
if (value[key] === undefined) delete value[key];
|
|
419
|
+
}
|
|
420
|
+
return value as UndefinedOmitted<T>;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
type WithUndefinedOptionals<T extends object> = {
|
|
424
|
+
[K in keyof T]: {} extends Pick<T, K> ? T[K] | undefined : T[K];
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
type RequiredKeysAllowingUndefined<T extends object> = {
|
|
428
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? never : undefined extends T[K] ? K : never;
|
|
429
|
+
}[keyof T];
|
|
430
|
+
|
|
431
|
+
function compactOptional<T extends object>(
|
|
432
|
+
value: WithUndefinedOptionals<T> & (RequiredKeysAllowingUndefined<T> extends never ? unknown : never),
|
|
433
|
+
): T {
|
|
434
|
+
for (const key of Object.keys(value) as Array<keyof T>) {
|
|
435
|
+
if (value[key] === undefined) delete value[key];
|
|
436
|
+
}
|
|
437
|
+
return value as T;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function setOptionalProperty<T extends object, K extends keyof T>(target: T, key: K, value: T[K]): void {
|
|
441
|
+
if (value === undefined) delete target[key];
|
|
442
|
+
else target[key] = value;
|
|
443
|
+
}
|
|
444
|
+
|
|
376
445
|
function resetStepLiveDetail(step: RunnerStatusStep): void {
|
|
377
|
-
step.currentTool
|
|
378
|
-
step.currentToolArgs
|
|
379
|
-
step.currentToolStartedAt
|
|
380
|
-
step.currentPath
|
|
446
|
+
delete step.currentTool;
|
|
447
|
+
delete step.currentToolArgs;
|
|
448
|
+
delete step.currentToolStartedAt;
|
|
449
|
+
delete step.currentPath;
|
|
381
450
|
step.recentTools = [];
|
|
382
451
|
step.recentOutput = [];
|
|
383
452
|
}
|
|
@@ -549,7 +618,7 @@ function runPiStreaming(
|
|
|
549
618
|
return;
|
|
550
619
|
}
|
|
551
620
|
|
|
552
|
-
appendChildEvent(event);
|
|
621
|
+
appendChildEvent(event as unknown as Record<string, unknown>);
|
|
553
622
|
transcriptWriter?.writeChildEvent(event);
|
|
554
623
|
if (event.type === "agent_settled") agentSettledReceived = true;
|
|
555
624
|
applyChildLifecycle(projectChildLifecycle(event));
|
|
@@ -559,9 +628,11 @@ function runPiStreaming(
|
|
|
559
628
|
const next = acceptChildWatchdogEvent({
|
|
560
629
|
current: childWatchdogState,
|
|
561
630
|
event,
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
631
|
+
...(childEventContext ? {
|
|
632
|
+
runId: childEventContext.runId,
|
|
633
|
+
agent: childEventContext.agent,
|
|
634
|
+
childIndex: childEventContext.stepIndex,
|
|
635
|
+
} : {}),
|
|
565
636
|
});
|
|
566
637
|
if (!next) return;
|
|
567
638
|
updateChildWatchdogState(next);
|
|
@@ -663,7 +734,11 @@ function runPiStreaming(
|
|
|
663
734
|
protocolHardKillTimer.unref?.();
|
|
664
735
|
}
|
|
665
736
|
};
|
|
666
|
-
const stdoutReader = createBoundedLineReader({
|
|
737
|
+
const stdoutReader = createBoundedLineReader({
|
|
738
|
+
oversizedLineProjector: PI_AGGREGATE_EVENT_PROJECTOR,
|
|
739
|
+
onLine: processStdoutLine,
|
|
740
|
+
onLimit: failProtocol,
|
|
741
|
+
});
|
|
667
742
|
const stderrReader = createBoundedLineReader({
|
|
668
743
|
stream: "stderr",
|
|
669
744
|
maxPendingLineBytes: MAX_CHILD_STDERR_BYTES,
|
|
@@ -829,7 +904,7 @@ function runPiStreaming(
|
|
|
829
904
|
turnBudgetExceeded,
|
|
830
905
|
forcedDrainAfterFinalSuccess,
|
|
831
906
|
}) ? formatProcessSignalError(signal!) : undefined;
|
|
832
|
-
resolve({
|
|
907
|
+
resolve(omitUndefinedProperties({
|
|
833
908
|
stderr,
|
|
834
909
|
exitCode: timedOut || stopped ? 1 : turnBudgetExceeded ? 1 : interrupted || forcedDrainAfterFinalSuccess ? 0 : forcedTerminationSignal || signal ? (exitCode ?? 1) : exitCode,
|
|
835
910
|
messages,
|
|
@@ -852,7 +927,7 @@ function runPiStreaming(
|
|
|
852
927
|
processInstanceId,
|
|
853
928
|
processCloseObservedAt,
|
|
854
929
|
processSignal: signal,
|
|
855
|
-
});
|
|
930
|
+
}));
|
|
856
931
|
});
|
|
857
932
|
|
|
858
933
|
child.on("error", (spawnError) => {
|
|
@@ -874,7 +949,7 @@ function runPiStreaming(
|
|
|
874
949
|
const stderr = stderrTail.text();
|
|
875
950
|
const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
|
|
876
951
|
const spawnErrorMessage = spawnError instanceof Error ? spawnError.message : String(spawnError);
|
|
877
|
-
resolve({ stderr, exitCode: 1, messages, usage, toolCount, durationMs: Date.now() - startedAt, model, error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : error ?? assistantError ?? spawnErrorMessage, protocolError, finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput, outputState: finalOutput.trim() ? "present" : "absent", timedOut, stopped, turnBudget, turnBudgetExceeded, wrapUpRequested: turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined, observedMutationAttempt, watchdog: childWatchdogState, processInstanceId });
|
|
952
|
+
resolve(omitUndefinedProperties({ stderr, exitCode: 1, messages, usage, toolCount, durationMs: Date.now() - startedAt, model, error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : error ?? assistantError ?? spawnErrorMessage, protocolError, finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput, outputState: finalOutput.trim() ? "present" : "absent", timedOut, stopped, turnBudget, turnBudgetExceeded, wrapUpRequested: turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined, observedMutationAttempt, watchdog: childWatchdogState, processInstanceId }));
|
|
878
953
|
});
|
|
879
954
|
});
|
|
880
955
|
}
|
|
@@ -1021,6 +1096,7 @@ interface SingleStepContext {
|
|
|
1021
1096
|
onAttemptStart?: (attempt: { model?: string; thinking?: string }) => void;
|
|
1022
1097
|
onChildEvent?: (event: ChildEvent) => void;
|
|
1023
1098
|
onWriterProcess?: (writer: { state: "none" | "spawning" } | { state: "running"; pid: number }) => void;
|
|
1099
|
+
onExternalProcess?: (process: ExternalProcessStatus) => void;
|
|
1024
1100
|
skipAcceptance?: () => boolean;
|
|
1025
1101
|
}
|
|
1026
1102
|
|
|
@@ -1028,42 +1104,7 @@ interface SingleStepContext {
|
|
|
1028
1104
|
async function runSingleStep(
|
|
1029
1105
|
step: SubagentStep,
|
|
1030
1106
|
ctx: SingleStepContext,
|
|
1031
|
-
): Promise<{
|
|
1032
|
-
agent: string;
|
|
1033
|
-
context?: "fresh" | "fork";
|
|
1034
|
-
agentContract?: import("../../shared/types.ts").AgentContract;
|
|
1035
|
-
launchContractDigest?: string;
|
|
1036
|
-
launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
|
|
1037
|
-
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
|
|
1038
|
-
output: string;
|
|
1039
|
-
exitCode: number | null;
|
|
1040
|
-
error?: string;
|
|
1041
|
-
model?: string;
|
|
1042
|
-
attemptedModels?: string[];
|
|
1043
|
-
modelAttempts?: ModelAttempt[];
|
|
1044
|
-
artifactPaths?: ArtifactPaths;
|
|
1045
|
-
transcriptPath?: string;
|
|
1046
|
-
transcriptError?: string;
|
|
1047
|
-
interrupted?: boolean;
|
|
1048
|
-
timedOut?: boolean;
|
|
1049
|
-
stopped?: boolean;
|
|
1050
|
-
turnBudget?: TurnBudgetState;
|
|
1051
|
-
turnBudgetExceeded?: boolean;
|
|
1052
|
-
wrapUpRequested?: boolean;
|
|
1053
|
-
toolBudget?: ToolBudgetState;
|
|
1054
|
-
toolBudgetBlocked?: boolean;
|
|
1055
|
-
sessionFile?: string;
|
|
1056
|
-
intercomTarget?: string;
|
|
1057
|
-
completionGuardTriggered?: boolean;
|
|
1058
|
-
effects?: import("../../shared/types.ts").EffectsProjection;
|
|
1059
|
-
execution?: import("../../shared/types.ts").ExecutionProjection;
|
|
1060
|
-
review?: import("../../shared/types.ts").ReviewProjection;
|
|
1061
|
-
structuredOutput?: unknown;
|
|
1062
|
-
structuredOutputPath?: string;
|
|
1063
|
-
structuredOutputSchemaPath?: string;
|
|
1064
|
-
acceptance?: import("../../shared/types.ts").AcceptanceLedger;
|
|
1065
|
-
writerAttemptCount?: number;
|
|
1066
|
-
}> {
|
|
1107
|
+
): Promise<StepResult & { completionGuardTriggered?: boolean }> {
|
|
1067
1108
|
if (step.importAsyncRoot) {
|
|
1068
1109
|
let importTimedOut = false;
|
|
1069
1110
|
let importStopped = false;
|
|
@@ -1076,7 +1117,7 @@ async function runSingleStep(
|
|
|
1076
1117
|
pid = undefined;
|
|
1077
1118
|
}
|
|
1078
1119
|
try {
|
|
1079
|
-
deliverTimeoutRequest({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-timeout" });
|
|
1120
|
+
deliverTimeoutRequest(omitUndefinedProperties({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-timeout" }));
|
|
1080
1121
|
} catch {
|
|
1081
1122
|
// The parent runner's own timeout result is authoritative for the attached step.
|
|
1082
1123
|
}
|
|
@@ -1090,16 +1131,16 @@ async function runSingleStep(
|
|
|
1090
1131
|
pid = undefined;
|
|
1091
1132
|
}
|
|
1092
1133
|
try {
|
|
1093
|
-
deliverStopRequest({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-stop" });
|
|
1134
|
+
deliverStopRequest(omitUndefinedProperties({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-stop" }));
|
|
1094
1135
|
} catch {
|
|
1095
1136
|
// The parent runner's own stopped result is authoritative for the attached step.
|
|
1096
1137
|
}
|
|
1097
1138
|
});
|
|
1098
1139
|
try {
|
|
1099
|
-
const imported = await waitForImportedAsyncRoot(step.importAsyncRoot, {
|
|
1140
|
+
const imported = await waitForImportedAsyncRoot(step.importAsyncRoot, omitUndefinedProperties({
|
|
1100
1141
|
shouldAbort: () => importTimedOut || importStopped || ctx.timeoutSignal?.aborted === true || ctx.stopSignal?.aborted === true || ctx.skipAcceptance?.() === true,
|
|
1101
1142
|
timeoutMessage: importStopped || ctx.stopSignal?.aborted === true ? ctx.stopMessage : ctx.timeoutMessage,
|
|
1102
|
-
});
|
|
1143
|
+
}));
|
|
1103
1144
|
try {
|
|
1104
1145
|
fs.writeFileSync(ctx.outputFile, imported.output, "utf-8");
|
|
1105
1146
|
} catch {
|
|
@@ -1108,7 +1149,7 @@ async function runSingleStep(
|
|
|
1108
1149
|
const stopped = importStopped || imported.stopped === true || ctx.stopSignal?.aborted === true;
|
|
1109
1150
|
const timedOut = !stopped && (importTimedOut || imported.timedOut === true || ctx.timeoutSignal?.aborted === true || ctx.skipAcceptance?.() === true);
|
|
1110
1151
|
const message = stopped ? ctx.stopMessage ?? "Subagent stopped by user." : ctx.timeoutMessage ?? "Subagent timed out.";
|
|
1111
|
-
return {
|
|
1152
|
+
return omitUndefinedProperties({
|
|
1112
1153
|
agent: imported.agent,
|
|
1113
1154
|
output: timedOut || stopped ? message : imported.output,
|
|
1114
1155
|
exitCode: timedOut || stopped ? 1 : imported.exitCode,
|
|
@@ -1125,7 +1166,7 @@ async function runSingleStep(
|
|
|
1125
1166
|
structuredOutputPath: timedOut || stopped ? undefined : imported.structuredOutputPath,
|
|
1126
1167
|
structuredOutputSchemaPath: timedOut || stopped ? undefined : imported.structuredOutputSchemaPath,
|
|
1127
1168
|
acceptance: timedOut || stopped ? undefined : imported.acceptance,
|
|
1128
|
-
};
|
|
1169
|
+
});
|
|
1129
1170
|
} finally {
|
|
1130
1171
|
ctx.registerTimeout?.(undefined);
|
|
1131
1172
|
ctx.registerStop?.(undefined);
|
|
@@ -1168,6 +1209,68 @@ async function runSingleStep(
|
|
|
1168
1209
|
}
|
|
1169
1210
|
transcriptWriter?.writeInitialUserMessage(task);
|
|
1170
1211
|
|
|
1212
|
+
if (step.runner?.type === "external-cli") {
|
|
1213
|
+
const runner: ExternalCliRunnerStatus = {
|
|
1214
|
+
type: "external-cli",
|
|
1215
|
+
command: step.runner.command,
|
|
1216
|
+
args: step.runner.args ?? [],
|
|
1217
|
+
promptDelivery: step.runner.promptDelivery ?? "stdin",
|
|
1218
|
+
capabilities: { stop: true, steer: false, resume: false, structuredOutput: false, toolEvents: false },
|
|
1219
|
+
};
|
|
1220
|
+
const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
|
|
1221
|
+
const external = await runExternalCli(omitUndefinedProperties({
|
|
1222
|
+
command: runner.command,
|
|
1223
|
+
args: runner.args,
|
|
1224
|
+
cwd: step.cwd ?? ctx.cwd,
|
|
1225
|
+
prompt: buildExternalCliPrompt(step.systemPrompt ?? "", task),
|
|
1226
|
+
asyncDir: path.dirname(ctx.outputFile),
|
|
1227
|
+
stepIndex: ctx.flatIndex,
|
|
1228
|
+
registerTimeout: ctx.registerTimeout,
|
|
1229
|
+
registerStop: ctx.registerStop,
|
|
1230
|
+
timeoutMessage: ctx.timeoutMessage,
|
|
1231
|
+
stopMessage: ctx.stopMessage,
|
|
1232
|
+
onProcess: ctx.onExternalProcess,
|
|
1233
|
+
}));
|
|
1234
|
+
try { fs.writeFileSync(ctx.outputFile, external.output, "utf-8"); } catch { /* Observability output is best-effort. */ }
|
|
1235
|
+
const resolvedOutput = step.outputPath && external.exitCode === 0
|
|
1236
|
+
? resolveSingleOutput(step.outputPath, external.output, outputSnapshot)
|
|
1237
|
+
: { fullOutput: external.output };
|
|
1238
|
+
const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
|
|
1239
|
+
const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
|
|
1240
|
+
fullOutput: resolvedOutput.fullOutput,
|
|
1241
|
+
outputPath: step.outputPath,
|
|
1242
|
+
outputMode: step.outputMode,
|
|
1243
|
+
exitCode: external.exitCode ?? 1,
|
|
1244
|
+
savedPath: resolvedOutput.savedPath,
|
|
1245
|
+
outputReference,
|
|
1246
|
+
saveError: resolvedOutput.saveError,
|
|
1247
|
+
}));
|
|
1248
|
+
const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
|
|
1249
|
+
? persistStepArtifacts({
|
|
1250
|
+
artifactPaths,
|
|
1251
|
+
artifactConfig: ctx.artifactConfig,
|
|
1252
|
+
output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, error: external.error, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })),
|
|
1253
|
+
metadata: { runId: ctx.id, agent: step.agent, task, runner, externalProcess: external.externalProcess, exitCode: external.exitCode, error: external.error, timestamp: Date.now() },
|
|
1254
|
+
})
|
|
1255
|
+
: {};
|
|
1256
|
+
return omitUndefinedProperties({
|
|
1257
|
+
agent: step.agent,
|
|
1258
|
+
context: step.context,
|
|
1259
|
+
output: finalizedOutput.displayOutput,
|
|
1260
|
+
outputState: external.output.trim() ? "present" : "absent",
|
|
1261
|
+
exitCode: external.exitCode,
|
|
1262
|
+
error: external.error,
|
|
1263
|
+
timedOut: external.timedOut,
|
|
1264
|
+
stopped: external.stopped,
|
|
1265
|
+
processSignal: external.processSignal,
|
|
1266
|
+
artifactPaths,
|
|
1267
|
+
outputSaveError: artifactErrors.outputSaveError,
|
|
1268
|
+
metadataSaveError: artifactErrors.metadataSaveError,
|
|
1269
|
+
runner,
|
|
1270
|
+
externalProcess: external.externalProcess,
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1171
1274
|
const candidates = step.modelCandidates && step.modelCandidates.length > 0
|
|
1172
1275
|
? step.modelCandidates
|
|
1173
1276
|
: step.model
|
|
@@ -1194,7 +1297,7 @@ async function runSingleStep(
|
|
|
1194
1297
|
modelAttemptsLoop: while (modelIndex < candidates.length) {
|
|
1195
1298
|
if (ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
|
|
1196
1299
|
const candidate = candidates[modelIndex];
|
|
1197
|
-
ctx.onAttemptStart?.({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking) });
|
|
1300
|
+
ctx.onAttemptStart?.(omitUndefinedProperties({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking) }));
|
|
1198
1301
|
const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
|
|
1199
1302
|
if (effectiveStructuredOutput) {
|
|
1200
1303
|
try {
|
|
@@ -1212,7 +1315,7 @@ async function runSingleStep(
|
|
|
1212
1315
|
childIndex: ctx.flatIndex,
|
|
1213
1316
|
})
|
|
1214
1317
|
: undefined;
|
|
1215
|
-
const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit } = buildPiArgs({
|
|
1318
|
+
const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit } = buildPiArgs(omitUndefinedProperties({
|
|
1216
1319
|
parentSessionId: step.parentSessionId,
|
|
1217
1320
|
baseArgs: ["--mode", "json", "-p"],
|
|
1218
1321
|
task,
|
|
@@ -1246,11 +1349,15 @@ async function runSingleStep(
|
|
|
1246
1349
|
steerAckDir: ctx.steerAckDir,
|
|
1247
1350
|
structuredOutput: effectiveStructuredOutput,
|
|
1248
1351
|
toolBudget: step.toolBudget,
|
|
1352
|
+
permissionRules: step.permissionRules,
|
|
1353
|
+
permissionAuditPath: step.permissionRules && ctx.artifactsDir
|
|
1354
|
+
? path.join(ctx.artifactsDir, "permission-audit", `${ctx.id}-${ctx.flatIndex}.jsonl`)
|
|
1355
|
+
: undefined,
|
|
1249
1356
|
childWatchdog,
|
|
1250
1357
|
waitToolEnabled: step.waitToolEnabled,
|
|
1251
|
-
});
|
|
1358
|
+
}));
|
|
1252
1359
|
if (step.definitionDigest) {
|
|
1253
|
-
const toolPlan = resolvePiLaunchToolPlan({
|
|
1360
|
+
const toolPlan = resolvePiLaunchToolPlan(omitUndefinedProperties({
|
|
1254
1361
|
tools: step.tools,
|
|
1255
1362
|
extensions: step.extensions,
|
|
1256
1363
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
@@ -1260,13 +1367,13 @@ async function runSingleStep(
|
|
|
1260
1367
|
structuredOutput: Boolean(effectiveStructuredOutput),
|
|
1261
1368
|
capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
|
|
1262
1369
|
inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
|
|
1263
|
-
});
|
|
1370
|
+
}));
|
|
1264
1371
|
launchResolvedExtensions = projectLaunchResolvedChildExtensions(toolPlan);
|
|
1265
|
-
actualLaunchContractDigest = launchBindingDigest({
|
|
1372
|
+
actualLaunchContractDigest = launchBindingDigest(omitUndefinedProperties({
|
|
1266
1373
|
definitionDigest: step.definitionDigest,
|
|
1267
1374
|
task: step.launchBindingTask ?? task,
|
|
1268
1375
|
...(candidate ? { model: candidate } : {}),
|
|
1269
|
-
modelCandidates: candidates,
|
|
1376
|
+
modelCandidates: candidates as string[],
|
|
1270
1377
|
...(resolveEffectiveThinking(candidate, step.thinking) ? { thinking: resolveEffectiveThinking(candidate, step.thinking) } : {}),
|
|
1271
1378
|
systemPrompt: appendTurnBudgetSystemPrompt(step.systemPrompt ?? "", ctx.turnBudget),
|
|
1272
1379
|
systemPromptMode: step.systemPromptMode,
|
|
@@ -1279,7 +1386,7 @@ async function runSingleStep(
|
|
|
1279
1386
|
...(step.outputPath ? { outputPath: step.outputPath } : {}),
|
|
1280
1387
|
...(step.outputMode ? { outputMode: step.outputMode } : {}),
|
|
1281
1388
|
...(step.structuredOutputSchema ? { structuredOutputSchema: step.structuredOutputSchema } : {}),
|
|
1282
|
-
});
|
|
1389
|
+
}));
|
|
1283
1390
|
}
|
|
1284
1391
|
capabilityAudit = attemptCapabilityAudit;
|
|
1285
1392
|
writerAttemptCount += 1;
|
|
@@ -1362,13 +1469,13 @@ async function runSingleStep(
|
|
|
1362
1469
|
}
|
|
1363
1470
|
const completionGuardEnabled = isAgentContractV1(step.agentContract) ? step.completionGuard === true : step.completionGuard !== false;
|
|
1364
1471
|
const completionGuard = run.exitCode === 0 && !run.error && !toolAvailabilityError && !hiddenError?.hasError && !emptyOutputError && completionGuardEnabled
|
|
1365
|
-
? evaluateCompletionMutationGuard({
|
|
1472
|
+
? evaluateCompletionMutationGuard(omitUndefinedProperties({
|
|
1366
1473
|
agent: step.agent,
|
|
1367
1474
|
task: taskForCompletionGuard,
|
|
1368
1475
|
messages: run.messages,
|
|
1369
1476
|
tools: step.tools,
|
|
1370
1477
|
mcpDirectTools: step.mcpDirectTools,
|
|
1371
|
-
})
|
|
1478
|
+
}))
|
|
1372
1479
|
: undefined;
|
|
1373
1480
|
const completionGuardTriggered = completionGuard?.triggered === true && !run.observedMutationAttempt;
|
|
1374
1481
|
const fileMutationEffect = completionGuard
|
|
@@ -1389,13 +1496,13 @@ async function runSingleStep(
|
|
|
1389
1496
|
: run.error && run.exitCode === 0
|
|
1390
1497
|
? 1
|
|
1391
1498
|
: run.exitCode;
|
|
1392
|
-
const signalError = run.exitCode !== 0 && isUnexplainedProcessSignal({
|
|
1499
|
+
const signalError = run.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
|
|
1393
1500
|
processSignal: run.processSignal,
|
|
1394
1501
|
interrupted: run.interrupted,
|
|
1395
1502
|
timedOut: run.timedOut,
|
|
1396
1503
|
stopped: run.stopped,
|
|
1397
1504
|
turnBudgetExceeded: run.turnBudgetExceeded,
|
|
1398
|
-
}) ? formatProcessSignalError(run.processSignal!) : undefined;
|
|
1505
|
+
})) ? formatProcessSignalError(run.processSignal!) : undefined;
|
|
1399
1506
|
const error = toolAvailabilityError
|
|
1400
1507
|
?? completionGuardError
|
|
1401
1508
|
?? structuredError
|
|
@@ -1405,13 +1512,13 @@ async function runSingleStep(
|
|
|
1405
1512
|
? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
|
|
1406
1513
|
: `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
|
|
1407
1514
|
: run.error || signalError || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined));
|
|
1408
|
-
const attempt: ModelAttempt = {
|
|
1515
|
+
const attempt: ModelAttempt = omitUndefinedProperties({
|
|
1409
1516
|
model: candidate ?? run.model ?? step.model ?? "default",
|
|
1410
1517
|
success: effectiveExitCode === 0 && !error,
|
|
1411
1518
|
exitCode: effectiveExitCode,
|
|
1412
1519
|
error,
|
|
1413
1520
|
usage: run.usage,
|
|
1414
|
-
};
|
|
1521
|
+
});
|
|
1415
1522
|
modelAttempts.push(attempt);
|
|
1416
1523
|
if (candidate && startupAttemptIndex === 0) attemptedModels.push(candidate);
|
|
1417
1524
|
completionGuardTriggeredFinal = completionGuardTriggered;
|
|
@@ -1427,7 +1534,7 @@ async function runSingleStep(
|
|
|
1427
1534
|
if (run.stopped || run.timedOut || ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break modelAttemptsLoop;
|
|
1428
1535
|
if (attempt.success || completionGuardTriggered) break modelAttemptsLoop;
|
|
1429
1536
|
|
|
1430
|
-
const startupFailure = isRetryableSubagentStartupFailure({
|
|
1537
|
+
const startupFailure = isRetryableSubagentStartupFailure(omitUndefinedProperties({
|
|
1431
1538
|
exitCode: effectiveExitCode,
|
|
1432
1539
|
error,
|
|
1433
1540
|
finalOutput: run.finalOutput,
|
|
@@ -1442,7 +1549,7 @@ async function runSingleStep(
|
|
|
1442
1549
|
timedOut: run.timedOut,
|
|
1443
1550
|
stopped: run.stopped,
|
|
1444
1551
|
turnBudgetExceeded: run.turnBudgetExceeded,
|
|
1445
|
-
});
|
|
1552
|
+
}));
|
|
1446
1553
|
const retryDelayMs = SUBAGENT_STARTUP_RETRY_DELAYS_MS[startupAttemptIndex];
|
|
1447
1554
|
if (startupFailure && retryDelayMs !== undefined) {
|
|
1448
1555
|
const retryNote = formatSubagentStartupRetryNote({
|
|
@@ -1507,7 +1614,7 @@ async function runSingleStep(
|
|
|
1507
1614
|
: resolvedOutput.savedPath
|
|
1508
1615
|
? "unknown"
|
|
1509
1616
|
: finalResult?.outputState ?? "unknown";
|
|
1510
|
-
const finalizedOutput = finalizeSingleOutput({
|
|
1617
|
+
const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
|
|
1511
1618
|
fullOutput: outputForSummary,
|
|
1512
1619
|
outputPath: step.outputPath,
|
|
1513
1620
|
outputMode: step.outputMode,
|
|
@@ -1515,10 +1622,10 @@ async function runSingleStep(
|
|
|
1515
1622
|
savedPath: resolvedOutput.savedPath,
|
|
1516
1623
|
outputReference,
|
|
1517
1624
|
saveError: resolvedOutput.saveError,
|
|
1518
|
-
});
|
|
1625
|
+
}));
|
|
1519
1626
|
outputForSummary = finalizedOutput.displayOutput;
|
|
1520
1627
|
const acceptance = step.effectiveAcceptance && !finalResult?.stopped && !finalResult?.turnBudgetExceeded && !ctx.timeoutSignal?.aborted && !ctx.stopSignal?.aborted && !ctx.skipAcceptance?.()
|
|
1521
|
-
? await evaluateAcceptance({
|
|
1628
|
+
? await evaluateAcceptance(omitUndefinedProperties({
|
|
1522
1629
|
acceptance: step.effectiveAcceptance,
|
|
1523
1630
|
output: outputForAcceptance,
|
|
1524
1631
|
fileOutput: childWrittenOutput !== undefined && step.outputPath
|
|
@@ -1528,7 +1635,7 @@ async function runSingleStep(
|
|
|
1528
1635
|
signal: combinedAbortSignal([ctx.timeoutSignal, ctx.stopSignal]),
|
|
1529
1636
|
abortMessage: ctx.stopSignal?.aborted ? ctx.stopMessage ?? "Subagent stopped by user." : ctx.timeoutMessage ?? "Subagent timed out.",
|
|
1530
1637
|
reportOptional: isAgentContractV1(step.agentContract),
|
|
1531
|
-
})
|
|
1638
|
+
}))
|
|
1532
1639
|
: undefined;
|
|
1533
1640
|
const stoppedAfterAcceptance = finalResult?.stopped === true || ctx.stopSignal?.aborted === true;
|
|
1534
1641
|
const timedOutAfterAcceptance = !stoppedAfterAcceptance && (finalResult?.timedOut === true || ctx.timeoutSignal?.aborted === true);
|
|
@@ -1555,43 +1662,39 @@ async function runSingleStep(
|
|
|
1555
1662
|
? (finalResult?.error ? `${finalResult.error}\n${acceptanceFailure}` : acceptanceFailure)
|
|
1556
1663
|
: finalResult?.error;
|
|
1557
1664
|
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1665
|
+
const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
|
|
1666
|
+
? persistStepArtifacts({
|
|
1667
|
+
artifactPaths,
|
|
1668
|
+
artifactConfig: ctx.artifactConfig,
|
|
1669
|
+
output: formatOutputArtifactContent(omitUndefinedProperties({
|
|
1561
1670
|
output,
|
|
1562
1671
|
error: effectiveFinalError,
|
|
1563
1672
|
transcriptPath: transcriptWriter ? artifactPaths.transcriptPath : undefined,
|
|
1564
1673
|
metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath,
|
|
1565
|
-
}),
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
timestamp: Date.now(),
|
|
1588
|
-
}, null, 2),
|
|
1589
|
-
"utf-8",
|
|
1590
|
-
);
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1674
|
+
})),
|
|
1675
|
+
metadata: {
|
|
1676
|
+
runId: ctx.id,
|
|
1677
|
+
agent: step.agent,
|
|
1678
|
+
task,
|
|
1679
|
+
exitCode: effectiveFinalExitCode,
|
|
1680
|
+
model: finalResult?.model,
|
|
1681
|
+
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
1682
|
+
modelAttempts,
|
|
1683
|
+
error: effectiveFinalError,
|
|
1684
|
+
acceptance: effectiveAcceptance,
|
|
1685
|
+
...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
|
|
1686
|
+
launchContractDigest: actualLaunchContractDigest,
|
|
1687
|
+
launchResolvedExtensions,
|
|
1688
|
+
...((finalResult as (RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }) | undefined)?.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: (finalResult as RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }).runtimeAcknowledgedExtensions } : {}),
|
|
1689
|
+
...(transcriptWriter ? { transcriptPath: artifactPaths.transcriptPath } : {}),
|
|
1690
|
+
transcriptError: transcriptWriter?.getError(),
|
|
1691
|
+
skills: step.skills,
|
|
1692
|
+
timestamp: Date.now(),
|
|
1693
|
+
},
|
|
1694
|
+
})
|
|
1695
|
+
: {};
|
|
1593
1696
|
|
|
1594
|
-
const result = {
|
|
1697
|
+
const result: StepResult & { completionGuardTriggered?: boolean } = omitUndefinedProperties({
|
|
1595
1698
|
agent: step.agent,
|
|
1596
1699
|
context: step.context,
|
|
1597
1700
|
...(step.agentContract ? { agentContract: step.agentContract } : {}),
|
|
@@ -1608,6 +1711,8 @@ async function runSingleStep(
|
|
|
1608
1711
|
modelAttempts,
|
|
1609
1712
|
totalCost: costSummaryFromAttempts(modelAttempts),
|
|
1610
1713
|
artifactPaths,
|
|
1714
|
+
outputSaveError: artifactErrors.outputSaveError,
|
|
1715
|
+
metadataSaveError: artifactErrors.metadataSaveError,
|
|
1611
1716
|
transcriptPath: transcriptWriter ? artifactPaths?.transcriptPath : undefined,
|
|
1612
1717
|
transcriptError: transcriptWriter?.getError(),
|
|
1613
1718
|
interrupted: timedOutAfterAcceptance || stoppedAfterAcceptance || turnBudgetExceeded ? false : finalResult?.interrupted,
|
|
@@ -1631,7 +1736,7 @@ async function runSingleStep(
|
|
|
1631
1736
|
...((finalResult as (RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }) | undefined)?.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: (finalResult as RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }).runtimeAcknowledgedExtensions } : {}),
|
|
1632
1737
|
writerProcesses,
|
|
1633
1738
|
writerAttemptCount,
|
|
1634
|
-
};
|
|
1739
|
+
});
|
|
1635
1740
|
return isAgentContractV1(step.agentContract) ? attachContractProjections(result as unknown as import("../../shared/types.ts").SingleResult) as unknown as typeof result : result;
|
|
1636
1741
|
}
|
|
1637
1742
|
|
|
@@ -1640,6 +1745,17 @@ type RunnerStatusStep = NonNullable<AsyncStatus["steps"]>[number] & {
|
|
|
1640
1745
|
description?: string;
|
|
1641
1746
|
};
|
|
1642
1747
|
|
|
1748
|
+
function externalRunnerStatus(runner: SubagentStep["runner"]): ExternalCliRunnerStatus | undefined {
|
|
1749
|
+
if (runner?.type !== "external-cli") return undefined;
|
|
1750
|
+
return {
|
|
1751
|
+
type: "external-cli",
|
|
1752
|
+
command: runner.command,
|
|
1753
|
+
args: runner.args ?? [],
|
|
1754
|
+
promptDelivery: runner.promptDelivery ?? "stdin",
|
|
1755
|
+
capabilities: { stop: true, steer: false, resume: false, structuredOutput: false, toolEvents: false },
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1643
1759
|
function appendCapabilityCeilingAppliedEvent(eventsPath: string, runId: string, stepIndex: number, agent: string, result: StepResult): void {
|
|
1644
1760
|
if (!result.capabilityCeiling) return;
|
|
1645
1761
|
appendJsonl(eventsPath, JSON.stringify({
|
|
@@ -1668,6 +1784,12 @@ type RunnerStatusPayload = Omit<AsyncStatus, "steps" | "parallelGroups" | "pid"
|
|
|
1668
1784
|
error?: string;
|
|
1669
1785
|
};
|
|
1670
1786
|
|
|
1787
|
+
function requiredStatusStep(statusPayload: RunnerStatusPayload, index: number): RunnerStatusStep {
|
|
1788
|
+
const step = statusPayload.steps[index];
|
|
1789
|
+
if (!step) throw new Error(`Missing status step at index ${index}`);
|
|
1790
|
+
return step;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1671
1793
|
function markParallelGroupSetupFailure(input: {
|
|
1672
1794
|
statusPayload: RunnerStatusPayload;
|
|
1673
1795
|
results: StepResult[];
|
|
@@ -1683,12 +1805,15 @@ function markParallelGroupSetupFailure(input: {
|
|
|
1683
1805
|
}): void {
|
|
1684
1806
|
for (let taskIndex = 0; taskIndex < input.group.parallel.length; taskIndex++) {
|
|
1685
1807
|
const flatTaskIndex = input.groupStartFlatIndex + taskIndex;
|
|
1686
|
-
input.statusPayload
|
|
1687
|
-
input.
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1808
|
+
const statusStep = requiredStatusStep(input.statusPayload, flatTaskIndex);
|
|
1809
|
+
const task = input.group.parallel[taskIndex];
|
|
1810
|
+
if (!task) throw new Error(`Missing parallel task at index ${taskIndex}`);
|
|
1811
|
+
statusStep.status = "failed";
|
|
1812
|
+
statusStep.startedAt = input.failedAt;
|
|
1813
|
+
statusStep.endedAt = input.failedAt;
|
|
1814
|
+
statusStep.durationMs = 0;
|
|
1815
|
+
statusStep.exitCode = 1;
|
|
1816
|
+
input.results.push(omitUndefinedProperties({ agent: task.agent, context: task.context, output: input.setupError, success: false, exitCode: 1, sessionFile: task.sessionFile }));
|
|
1692
1817
|
}
|
|
1693
1818
|
input.statusPayload.currentStep = input.groupStartFlatIndex;
|
|
1694
1819
|
input.statusPayload.lastUpdate = input.failedAt;
|
|
@@ -1716,16 +1841,17 @@ function markParallelGroupRunning(input: {
|
|
|
1716
1841
|
}): void {
|
|
1717
1842
|
for (let taskIndex = 0; taskIndex < input.group.parallel.length; taskIndex++) {
|
|
1718
1843
|
const flatTaskIndex = input.groupStartFlatIndex + taskIndex;
|
|
1719
|
-
input.statusPayload
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1844
|
+
const statusStep = requiredStatusStep(input.statusPayload, flatTaskIndex);
|
|
1845
|
+
statusStep.status = "pending";
|
|
1846
|
+
delete statusStep.startedAt;
|
|
1847
|
+
delete statusStep.endedAt;
|
|
1848
|
+
delete statusStep.durationMs;
|
|
1849
|
+
delete statusStep.lastActivityAt;
|
|
1850
|
+
delete statusStep.activityState;
|
|
1851
|
+
delete statusStep.error;
|
|
1726
1852
|
}
|
|
1727
1853
|
input.statusPayload.currentStep = input.groupStartFlatIndex;
|
|
1728
|
-
input.statusPayload.activityState
|
|
1854
|
+
delete input.statusPayload.activityState;
|
|
1729
1855
|
input.statusPayload.lastActivityAt = input.groupStartTime;
|
|
1730
1856
|
input.statusPayload.lastUpdate = input.groupStartTime;
|
|
1731
1857
|
input.statusPayload.outputFile = path.join(input.asyncDir, `output-${input.groupStartFlatIndex}.log`);
|
|
@@ -1747,8 +1873,9 @@ function prepareParallelTaskRun(
|
|
|
1747
1873
|
taskIndex: number,
|
|
1748
1874
|
): { taskForRun: SubagentStep; taskCwd: string } {
|
|
1749
1875
|
if (!worktreeSetup) return { taskForRun: task, taskCwd: cwd };
|
|
1876
|
+
const { cwd: _taskCwd, ...taskForRun } = task;
|
|
1750
1877
|
return {
|
|
1751
|
-
taskForRun
|
|
1878
|
+
taskForRun,
|
|
1752
1879
|
taskCwd: worktreeSetup.worktrees[taskIndex]!.agentCwd,
|
|
1753
1880
|
};
|
|
1754
1881
|
}
|
|
@@ -1854,7 +1981,7 @@ async function runSubagent(
|
|
|
1854
1981
|
for (let stepIndex = 0; stepIndex < steps.length; stepIndex++) {
|
|
1855
1982
|
const step = steps[stepIndex]!;
|
|
1856
1983
|
if (isCheckpointRunnerStep(step)) {
|
|
1857
|
-
initialStatusSteps.push({
|
|
1984
|
+
initialStatusSteps.push(omitUndefinedProperties({
|
|
1858
1985
|
agent: `checkpoint:${step.checkpoint}`,
|
|
1859
1986
|
phase: step.phase,
|
|
1860
1987
|
label: step.label ?? step.checkpoint,
|
|
@@ -1862,7 +1989,7 @@ async function runSubagent(
|
|
|
1862
1989
|
checkpoint: { name: step.checkpoint, ...(step.message ? { message: step.message } : {}), status: "pending", stepIndex },
|
|
1863
1990
|
recentTools: [],
|
|
1864
1991
|
recentOutput: [],
|
|
1865
|
-
});
|
|
1992
|
+
}));
|
|
1866
1993
|
flatStepCount++;
|
|
1867
1994
|
continue;
|
|
1868
1995
|
}
|
|
@@ -1870,9 +1997,10 @@ async function runSubagent(
|
|
|
1870
1997
|
parallelGroups.push({ start: flatStepCount, count: step.parallel.length, stepIndex });
|
|
1871
1998
|
for (const task of step.parallel) {
|
|
1872
1999
|
const taskFlatIndex = flatStepCount;
|
|
1873
|
-
const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: taskFlatIndex, flatStepCount: initialFlatStepCount });
|
|
1874
|
-
initialStatusSteps.push({
|
|
2000
|
+
const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: taskFlatIndex, flatStepCount: initialFlatStepCount }));
|
|
2001
|
+
initialStatusSteps.push(omitUndefinedProperties({
|
|
1875
2002
|
agent: task.agent,
|
|
2003
|
+
...(externalRunnerStatus(task.runner) ? { runner: externalRunnerStatus(task.runner) } : {}),
|
|
1876
2004
|
...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
|
|
1877
2005
|
...(task.context ? { context: task.context } : {}),
|
|
1878
2006
|
phase: task.phase,
|
|
@@ -1893,13 +2021,14 @@ async function runSubagent(
|
|
|
1893
2021
|
attemptedModels: task.modelCandidates && task.modelCandidates.length > 0 ? task.modelCandidates : task.model ? [task.model] : undefined,
|
|
1894
2022
|
recentTools: [],
|
|
1895
2023
|
recentOutput: [],
|
|
1896
|
-
});
|
|
2024
|
+
}));
|
|
1897
2025
|
flatStepCount++;
|
|
1898
2026
|
}
|
|
1899
2027
|
} else if (isDynamicRunnerGroup(step)) {
|
|
1900
2028
|
parallelGroups.push({ start: flatStepCount, count: 1, stepIndex });
|
|
1901
|
-
initialStatusSteps.push({
|
|
2029
|
+
initialStatusSteps.push(omitUndefinedProperties({
|
|
1902
2030
|
agent: `expand:${step.parallel.agent}`,
|
|
2031
|
+
...(externalRunnerStatus(step.parallel.runner) ? { runner: externalRunnerStatus(step.parallel.runner) } : {}),
|
|
1903
2032
|
...(step.parallel.context ? { context: step.parallel.context } : {}),
|
|
1904
2033
|
phase: step.phase ?? step.parallel.phase,
|
|
1905
2034
|
label: step.label ?? step.parallel.label ?? `Dynamic fanout (${step.collect.as})`,
|
|
@@ -1911,13 +2040,14 @@ async function runSubagent(
|
|
|
1911
2040
|
...(step.parallel.toolBudget ? { toolBudget: initialToolBudgetState(step.parallel.toolBudget) } : {}),
|
|
1912
2041
|
recentTools: [],
|
|
1913
2042
|
recentOutput: [],
|
|
1914
|
-
});
|
|
2043
|
+
}));
|
|
1915
2044
|
flatStepCount++;
|
|
1916
2045
|
} else {
|
|
1917
2046
|
const stepFlatIndex = flatStepCount;
|
|
1918
|
-
const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: step.agent, flatIndex: stepFlatIndex, flatStepCount: initialFlatStepCount });
|
|
1919
|
-
initialStatusSteps.push({
|
|
2047
|
+
const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: step.agent, flatIndex: stepFlatIndex, flatStepCount: initialFlatStepCount }));
|
|
2048
|
+
initialStatusSteps.push(omitUndefinedProperties({
|
|
1920
2049
|
agent: step.agent,
|
|
2050
|
+
...(externalRunnerStatus(step.runner) ? { runner: externalRunnerStatus(step.runner) } : {}),
|
|
1921
2051
|
...(statusStepDescription(step.task) ? { description: statusStepDescription(step.task) } : {}),
|
|
1922
2052
|
...(step.context ? { context: step.context } : {}),
|
|
1923
2053
|
phase: step.phase,
|
|
@@ -1938,7 +2068,7 @@ async function runSubagent(
|
|
|
1938
2068
|
attemptedModels: step.modelCandidates && step.modelCandidates.length > 0 ? step.modelCandidates : step.model ? [step.model] : undefined,
|
|
1939
2069
|
recentTools: [],
|
|
1940
2070
|
recentOutput: [],
|
|
1941
|
-
});
|
|
2071
|
+
}));
|
|
1942
2072
|
flatStepCount++;
|
|
1943
2073
|
}
|
|
1944
2074
|
}
|
|
@@ -1950,7 +2080,7 @@ async function runSubagent(
|
|
|
1950
2080
|
step.processTerminal = { version: 1, state: "pending", runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId };
|
|
1951
2081
|
}
|
|
1952
2082
|
}
|
|
1953
|
-
const statusPayload: RunnerStatusPayload = {
|
|
2083
|
+
const statusPayload: RunnerStatusPayload = omitUndefinedProperties({
|
|
1954
2084
|
lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
1955
2085
|
runId: id,
|
|
1956
2086
|
...(config.sessionId ? { sessionId: config.sessionId } : {}),
|
|
@@ -1975,12 +2105,14 @@ async function runSubagent(
|
|
|
1975
2105
|
...(config.launchContractDigest ? { launchContractDigest: config.launchContractDigest } : {}),
|
|
1976
2106
|
...(config.launchResolvedExtensions ? { launchResolvedExtensions: config.launchResolvedExtensions } : {}),
|
|
1977
2107
|
...(config.capabilityCeiling ? { capabilityCeiling: config.capabilityCeiling } : {}),
|
|
2108
|
+
...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
|
|
2109
|
+
...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
|
|
1978
2110
|
...(config.runnerProcessInstanceId ? { processTerminal: { version: 1 as const, state: "pending" as const, runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId } } : {}),
|
|
1979
2111
|
steps: initialStatusSteps,
|
|
1980
2112
|
artifactsDir,
|
|
1981
2113
|
sessionDir: config.sessionDir,
|
|
1982
2114
|
outputFile: path.join(asyncDir, "output-0.log"),
|
|
1983
|
-
};
|
|
2115
|
+
});
|
|
1984
2116
|
|
|
1985
2117
|
fs.mkdirSync(asyncDir, { recursive: true });
|
|
1986
2118
|
writeAtomicJson(statusPath, statusPayload);
|
|
@@ -1998,18 +2130,18 @@ async function runSubagent(
|
|
|
1998
2130
|
};
|
|
1999
2131
|
};
|
|
2000
2132
|
const refreshUsageBudget = () => {
|
|
2001
|
-
statusPayload
|
|
2133
|
+
setOptionalProperty(statusPayload, "usageBudget", usageBudgetState(config.usageBudget, currentUsageTotals()));
|
|
2002
2134
|
return statusPayload.usageBudget;
|
|
2003
2135
|
};
|
|
2004
2136
|
const emitNestedSelfEvent = (type: "subagent.nested.updated" | "subagent.nested.completed"): void => {
|
|
2005
2137
|
if (!config.nestedRoute || !config.nestedSelf) return;
|
|
2006
2138
|
try {
|
|
2007
|
-
writeNestedEvent(config.nestedRoute, {
|
|
2139
|
+
writeNestedEvent(config.nestedRoute, omitUndefinedProperties({
|
|
2008
2140
|
type,
|
|
2009
2141
|
ts: Date.now(),
|
|
2010
2142
|
parentRunId: config.nestedSelf.parentRunId,
|
|
2011
2143
|
parentStepIndex: config.nestedSelf.parentStepIndex,
|
|
2012
|
-
child: nestedSummaryFromAsyncStatus(statusPayload, asyncDir, {
|
|
2144
|
+
child: nestedSummaryFromAsyncStatus(statusPayload, asyncDir, omitUndefinedProperties({
|
|
2013
2145
|
id,
|
|
2014
2146
|
parentRunId: config.nestedSelf.parentRunId,
|
|
2015
2147
|
parentStepIndex: config.nestedSelf.parentStepIndex,
|
|
@@ -2017,8 +2149,8 @@ async function runSubagent(
|
|
|
2017
2149
|
path: config.nestedSelf.path,
|
|
2018
2150
|
mode: statusPayload.mode,
|
|
2019
2151
|
ts: Date.now(),
|
|
2020
|
-
}),
|
|
2021
|
-
});
|
|
2152
|
+
})),
|
|
2153
|
+
}));
|
|
2022
2154
|
} catch (error) {
|
|
2023
2155
|
console.error("Failed to emit nested async status event:", error);
|
|
2024
2156
|
}
|
|
@@ -2036,9 +2168,9 @@ async function runSubagent(
|
|
|
2036
2168
|
const step = statusPayload.steps[node.flatIndex];
|
|
2037
2169
|
if (step) {
|
|
2038
2170
|
node.status = normalize(step.status);
|
|
2039
|
-
node
|
|
2040
|
-
node
|
|
2041
|
-
node
|
|
2171
|
+
setOptionalProperty(node, "error", step.error);
|
|
2172
|
+
setOptionalProperty(node, "acceptanceStatus", step.acceptance?.status);
|
|
2173
|
+
setOptionalProperty(node, "checkpoint", step.checkpoint);
|
|
2042
2174
|
}
|
|
2043
2175
|
if (statusPayload.currentStep === node.flatIndex) graph.currentNodeId = node.id;
|
|
2044
2176
|
}
|
|
@@ -2061,6 +2193,11 @@ async function runSubagent(
|
|
|
2061
2193
|
writeAtomicJson(statusPath, statusPayload);
|
|
2062
2194
|
emitNestedSelfEvent(statusPayload.state === "running" || statusPayload.state === "queued" ? "subagent.nested.updated" : "subagent.nested.completed");
|
|
2063
2195
|
};
|
|
2196
|
+
const updateExternalProcess = (index: number, process: ExternalProcessStatus): void => {
|
|
2197
|
+
requiredStatusStep(statusPayload, index).externalProcess = process;
|
|
2198
|
+
statusPayload.lastUpdate = Date.now();
|
|
2199
|
+
writeStatusPayload();
|
|
2200
|
+
};
|
|
2064
2201
|
const registerStepInterrupt = (flatIndex: number, interrupt: (() => void) | undefined): void => {
|
|
2065
2202
|
if (!interrupt) {
|
|
2066
2203
|
activeChildInterrupts.delete(flatIndex);
|
|
@@ -2127,7 +2264,7 @@ async function runSubagent(
|
|
|
2127
2264
|
const nestedAsyncDir = run.asyncDir ?? resolveNestedAsyncDir(config.nestedRoute.rootRunId, run);
|
|
2128
2265
|
if (!nestedAsyncDir) continue;
|
|
2129
2266
|
try {
|
|
2130
|
-
deliverInterruptRequest({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-interrupt" });
|
|
2267
|
+
deliverInterruptRequest(omitUndefinedProperties({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-interrupt" }));
|
|
2131
2268
|
} catch (error) {
|
|
2132
2269
|
appendJsonl(eventsPath, JSON.stringify({
|
|
2133
2270
|
type: "subagent.nested.interrupt_failed",
|
|
@@ -2158,7 +2295,7 @@ async function runSubagent(
|
|
|
2158
2295
|
const nestedAsyncDir = run.asyncDir ?? resolveNestedAsyncDir(config.nestedRoute.rootRunId, run);
|
|
2159
2296
|
if (!nestedAsyncDir) continue;
|
|
2160
2297
|
try {
|
|
2161
|
-
deliverStopRequest({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-stop" });
|
|
2298
|
+
deliverStopRequest(omitUndefinedProperties({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-stop" }));
|
|
2162
2299
|
} catch (error) {
|
|
2163
2300
|
appendJsonl(eventsPath, JSON.stringify({
|
|
2164
2301
|
type: "subagent.nested.stop_failed",
|
|
@@ -2189,7 +2326,7 @@ async function runSubagent(
|
|
|
2189
2326
|
const nestedAsyncDir = run.asyncDir ?? resolveNestedAsyncDir(config.nestedRoute.rootRunId, run);
|
|
2190
2327
|
if (!nestedAsyncDir) continue;
|
|
2191
2328
|
try {
|
|
2192
|
-
deliverTimeoutRequest({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-timeout" });
|
|
2329
|
+
deliverTimeoutRequest(omitUndefinedProperties({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-timeout" }));
|
|
2193
2330
|
} catch (error) {
|
|
2194
2331
|
appendJsonl(eventsPath, JSON.stringify({
|
|
2195
2332
|
type: "subagent.nested.timeout_failed",
|
|
@@ -2201,14 +2338,14 @@ async function runSubagent(
|
|
|
2201
2338
|
}
|
|
2202
2339
|
}
|
|
2203
2340
|
};
|
|
2204
|
-
const pausedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => ({
|
|
2341
|
+
const pausedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
|
|
2205
2342
|
agent,
|
|
2206
2343
|
context,
|
|
2207
2344
|
output: "Paused after interrupt. Waiting for explicit next action.",
|
|
2208
2345
|
exitCode: 0,
|
|
2209
2346
|
interrupted: true,
|
|
2210
2347
|
});
|
|
2211
|
-
const timedOutStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => ({
|
|
2348
|
+
const timedOutStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
|
|
2212
2349
|
agent,
|
|
2213
2350
|
context,
|
|
2214
2351
|
output: timeoutMessage ?? "Subagent timed out.",
|
|
@@ -2216,7 +2353,7 @@ async function runSubagent(
|
|
|
2216
2353
|
exitCode: 1,
|
|
2217
2354
|
timedOut: true,
|
|
2218
2355
|
});
|
|
2219
|
-
const stoppedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => ({
|
|
2356
|
+
const stoppedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
|
|
2220
2357
|
agent,
|
|
2221
2358
|
context,
|
|
2222
2359
|
output: stopMessage,
|
|
@@ -2267,8 +2404,8 @@ async function runSubagent(
|
|
|
2267
2404
|
const groupNode = statusPayload.workflowGraph?.nodes.find((node) => node.id === `step-${stepIndex}`);
|
|
2268
2405
|
if (!groupNode) return;
|
|
2269
2406
|
groupNode.status = status;
|
|
2270
|
-
groupNode
|
|
2271
|
-
groupNode
|
|
2407
|
+
setOptionalProperty(groupNode, "error", error);
|
|
2408
|
+
setOptionalProperty(groupNode, "acceptanceStatus", acceptance?.status ?? groupNode.acceptanceStatus);
|
|
2272
2409
|
};
|
|
2273
2410
|
|
|
2274
2411
|
const stepOutputActivityAt = (index: number): number => {
|
|
@@ -2315,9 +2452,9 @@ async function runSubagent(
|
|
|
2315
2452
|
const activeStep = statusPayload.steps
|
|
2316
2453
|
.filter((step) => step.status === "running" && typeof step.currentTool === "string" && step.currentTool.length > 0)
|
|
2317
2454
|
.sort((left, right) => (right.currentToolStartedAt ?? 0) - (left.currentToolStartedAt ?? 0))[0];
|
|
2318
|
-
statusPayload
|
|
2319
|
-
statusPayload
|
|
2320
|
-
statusPayload
|
|
2455
|
+
setOptionalProperty(statusPayload, "currentTool", activeStep?.currentTool);
|
|
2456
|
+
setOptionalProperty(statusPayload, "currentToolStartedAt", activeStep?.currentToolStartedAt);
|
|
2457
|
+
setOptionalProperty(statusPayload, "currentPath", activeStep?.currentPath);
|
|
2321
2458
|
};
|
|
2322
2459
|
const syncAggregateActivityState = (): void => {
|
|
2323
2460
|
const nextRunState = statusPayload.steps.some((step) => step.activityState === "needs_attention")
|
|
@@ -2326,7 +2463,7 @@ async function runSubagent(
|
|
|
2326
2463
|
? "active_long_running"
|
|
2327
2464
|
: undefined;
|
|
2328
2465
|
currentActivityState = nextRunState;
|
|
2329
|
-
statusPayload
|
|
2466
|
+
setOptionalProperty(statusPayload, "activityState", nextRunState);
|
|
2330
2467
|
};
|
|
2331
2468
|
const maybeEmitActiveLongRunning = (flatIndex: number, now: number): boolean => {
|
|
2332
2469
|
if (!controlConfig.enabled || activeLongRunningSteps.has(flatIndex)) return false;
|
|
@@ -2343,7 +2480,7 @@ async function runSubagent(
|
|
|
2343
2480
|
const previous = step.activityState;
|
|
2344
2481
|
step.activityState = "active_long_running";
|
|
2345
2482
|
statusPayload.activityState = statusPayload.activityState === "needs_attention" ? "needs_attention" : "active_long_running";
|
|
2346
|
-
const event = buildControlEvent({
|
|
2483
|
+
const event = buildControlEvent(omitUndefinedProperties({
|
|
2347
2484
|
type: "active_long_running",
|
|
2348
2485
|
from: previous,
|
|
2349
2486
|
to: "active_long_running",
|
|
@@ -2360,7 +2497,7 @@ async function runSubagent(
|
|
|
2360
2497
|
currentToolDurationMs: step.currentToolStartedAt ? Math.max(0, now - step.currentToolStartedAt) : undefined,
|
|
2361
2498
|
currentPath: step.currentPath,
|
|
2362
2499
|
elapsedMs: now - (step.startedAt ?? overallStartTime),
|
|
2363
|
-
});
|
|
2500
|
+
}));
|
|
2364
2501
|
appendControlEvent(event);
|
|
2365
2502
|
return true;
|
|
2366
2503
|
};
|
|
@@ -2378,12 +2515,12 @@ async function runSubagent(
|
|
|
2378
2515
|
};
|
|
2379
2516
|
const recordSteeringLifecycle = (request: SteerRequest, targets: Array<{ index: number; state: SteeringTargetState; reason?: string }>): void => {
|
|
2380
2517
|
const lifecycle = steeringStatus(statusPayload);
|
|
2381
|
-
recordSteeringRequest(lifecycle, { id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets });
|
|
2518
|
+
recordSteeringRequest(lifecycle, omitUndefinedProperties({ id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets }));
|
|
2382
2519
|
for (const target of targets) {
|
|
2383
2520
|
const step = statusPayload.steps[target.index];
|
|
2384
2521
|
if (!step) continue;
|
|
2385
2522
|
step.steering ??= createSteeringStatus();
|
|
2386
|
-
recordSteeringRequest(step.steering, { id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets: [target] });
|
|
2523
|
+
recordSteeringRequest(step.steering, omitUndefinedProperties({ id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets: [target] }));
|
|
2387
2524
|
}
|
|
2388
2525
|
};
|
|
2389
2526
|
const updateSteeringLifecycleTarget = (
|
|
@@ -2473,7 +2610,7 @@ async function runSubagent(
|
|
|
2473
2610
|
const late = fs.existsSync(steeringMarkerPath(ack.requestId));
|
|
2474
2611
|
const now = Date.now();
|
|
2475
2612
|
if (ack.state === "delivered") {
|
|
2476
|
-
updateSteeringLifecycleTarget(ack.requestId, ack.index, late ? "late" : "delivered", now, { reason: late ? "acknowledged after recovery commit" : undefined });
|
|
2613
|
+
updateSteeringLifecycleTarget(ack.requestId, ack.index, late ? "late" : "delivered", now, omitUndefinedProperties({ reason: late ? "acknowledged after recovery commit" : undefined }));
|
|
2477
2614
|
emitSteeringEvent("subagent.steer.delivered", { type: "steer", id: ack.requestId, ts: now, message: ack.message }, ack.index, { late, message: ack.message });
|
|
2478
2615
|
} else {
|
|
2479
2616
|
markSteeringAttention(ack.index);
|
|
@@ -2496,8 +2633,8 @@ async function runSubagent(
|
|
|
2496
2633
|
const updateStepModel = (flatIndex: number, model: string | undefined, thinking: string | undefined, now = Date.now()): void => {
|
|
2497
2634
|
const step = statusPayload.steps[flatIndex];
|
|
2498
2635
|
if (!step) return;
|
|
2499
|
-
step
|
|
2500
|
-
step
|
|
2636
|
+
setOptionalProperty(step, "model", model);
|
|
2637
|
+
setOptionalProperty(step, "thinking", thinking);
|
|
2501
2638
|
statusPayload.lastUpdate = now;
|
|
2502
2639
|
writeStatusPayload();
|
|
2503
2640
|
};
|
|
@@ -2594,8 +2731,8 @@ async function runSubagent(
|
|
|
2594
2731
|
step.currentTool = event.toolName;
|
|
2595
2732
|
step.currentToolArgs = extractToolArgsPreview(event.args ?? {});
|
|
2596
2733
|
step.currentToolStartedAt = now;
|
|
2597
|
-
step
|
|
2598
|
-
pendingToolResults[flatIndex] = { tool: event.toolName, path: currentPath, mutates, startedAt: now };
|
|
2734
|
+
setOptionalProperty(step, "currentPath", currentPath);
|
|
2735
|
+
pendingToolResults[flatIndex] = omitUndefinedProperties({ tool: event.toolName, path: currentPath, mutates, startedAt: now });
|
|
2599
2736
|
statusPayload.toolCount = (statusPayload.toolCount ?? 0) + 1;
|
|
2600
2737
|
syncTopLevelCurrentTool();
|
|
2601
2738
|
if (controlConfig.enabled && isBlockingSupervisorTool(event.toolName, event.args) && step.activityState !== "needs_attention") {
|
|
@@ -2604,7 +2741,7 @@ async function runSubagent(
|
|
|
2604
2741
|
supervisorAttentionSteps.set(flatIndex, previous);
|
|
2605
2742
|
currentActivityState = "needs_attention";
|
|
2606
2743
|
statusPayload.activityState = "needs_attention";
|
|
2607
|
-
appendControlEvent(buildControlEvent({
|
|
2744
|
+
appendControlEvent(buildControlEvent(omitUndefinedProperties({
|
|
2608
2745
|
type: "needs_attention",
|
|
2609
2746
|
from: previous,
|
|
2610
2747
|
to: "needs_attention",
|
|
@@ -2620,7 +2757,7 @@ async function runSubagent(
|
|
|
2620
2757
|
currentTool: step.currentTool,
|
|
2621
2758
|
currentToolDurationMs: 0,
|
|
2622
2759
|
currentPath: step.currentPath,
|
|
2623
|
-
}));
|
|
2760
|
+
})));
|
|
2624
2761
|
}
|
|
2625
2762
|
} else if (event.type === "tool_execution_end") {
|
|
2626
2763
|
if (step.currentTool) {
|
|
@@ -2629,12 +2766,12 @@ async function runSubagent(
|
|
|
2629
2766
|
}
|
|
2630
2767
|
const supervisorPreviousActivity = supervisorAttentionSteps.get(flatIndex);
|
|
2631
2768
|
const clearedSupervisorAttention = supervisorAttentionSteps.delete(flatIndex);
|
|
2632
|
-
step.currentTool
|
|
2633
|
-
step.currentToolArgs
|
|
2634
|
-
step.currentToolStartedAt
|
|
2635
|
-
step.currentPath
|
|
2769
|
+
delete step.currentTool;
|
|
2770
|
+
delete step.currentToolArgs;
|
|
2771
|
+
delete step.currentToolStartedAt;
|
|
2772
|
+
delete step.currentPath;
|
|
2636
2773
|
if (clearedSupervisorAttention && step.activityState === "needs_attention") {
|
|
2637
|
-
step
|
|
2774
|
+
setOptionalProperty(step, "activityState", supervisorPreviousActivity);
|
|
2638
2775
|
syncAggregateActivityState();
|
|
2639
2776
|
}
|
|
2640
2777
|
syncTopLevelCurrentTool();
|
|
@@ -2654,17 +2791,17 @@ async function runSubagent(
|
|
|
2654
2791
|
appendRecentStepOutput(step, resultText.split("\n").slice(-10));
|
|
2655
2792
|
if (toolSnapshot?.mutates && didMutatingToolFail(resultText)) {
|
|
2656
2793
|
const state = mutatingFailureStates[flatIndex]!;
|
|
2657
|
-
recordMutatingFailure(state, {
|
|
2794
|
+
recordMutatingFailure(state, omitUndefinedProperties({
|
|
2658
2795
|
tool: toolSnapshot.tool,
|
|
2659
2796
|
path: toolSnapshot.path,
|
|
2660
2797
|
error: resultText.split("\n").find((line) => line.trim())?.trim().slice(0, 180) ?? "mutating tool failed",
|
|
2661
2798
|
ts: now,
|
|
2662
|
-
}, mutatingFailureWindowMs);
|
|
2799
|
+
}), mutatingFailureWindowMs);
|
|
2663
2800
|
if (controlConfig.enabled && shouldEscalateMutatingFailures(state, controlConfig.failedToolAttemptsBeforeAttention) && step.activityState !== "needs_attention") {
|
|
2664
2801
|
const previous = step.activityState;
|
|
2665
2802
|
step.activityState = "needs_attention";
|
|
2666
2803
|
statusPayload.activityState = "needs_attention";
|
|
2667
|
-
appendControlEvent(buildControlEvent({
|
|
2804
|
+
appendControlEvent(buildControlEvent(omitUndefinedProperties({
|
|
2668
2805
|
type: "needs_attention",
|
|
2669
2806
|
from: previous,
|
|
2670
2807
|
to: "needs_attention",
|
|
@@ -2681,7 +2818,7 @@ async function runSubagent(
|
|
|
2681
2818
|
currentToolDurationMs: toolSnapshot.startedAt ? Math.max(0, now - toolSnapshot.startedAt) : undefined,
|
|
2682
2819
|
currentPath: toolSnapshot.path,
|
|
2683
2820
|
recentFailureSummary: summarizeRecentMutatingFailures(state),
|
|
2684
|
-
}));
|
|
2821
|
+
})));
|
|
2685
2822
|
}
|
|
2686
2823
|
} else if (toolSnapshot?.mutates) {
|
|
2687
2824
|
resetMutatingFailureState(mutatingFailureStates[flatIndex]!);
|
|
@@ -2730,18 +2867,18 @@ async function runSubagent(
|
|
|
2730
2867
|
step.lastActivityAt = lastActivityAt;
|
|
2731
2868
|
changed = true;
|
|
2732
2869
|
}
|
|
2733
|
-
const idleState = deriveActivityState({
|
|
2870
|
+
const idleState = deriveActivityState(omitUndefinedProperties({
|
|
2734
2871
|
config: controlConfig,
|
|
2735
2872
|
startedAt: step.startedAt ?? overallStartTime,
|
|
2736
2873
|
lastActivityAt,
|
|
2737
2874
|
currentTool: step.currentTool,
|
|
2738
2875
|
now,
|
|
2739
|
-
});
|
|
2876
|
+
}));
|
|
2740
2877
|
if (idleState === "needs_attention") {
|
|
2741
2878
|
const previous = step.activityState;
|
|
2742
2879
|
step.activityState = "needs_attention";
|
|
2743
2880
|
if (previous !== "needs_attention") {
|
|
2744
|
-
appendControlEvent(buildControlEvent({
|
|
2881
|
+
appendControlEvent(buildControlEvent(omitUndefinedProperties({
|
|
2745
2882
|
from: previous,
|
|
2746
2883
|
to: "needs_attention",
|
|
2747
2884
|
runId: id,
|
|
@@ -2749,7 +2886,7 @@ async function runSubagent(
|
|
|
2749
2886
|
index,
|
|
2750
2887
|
ts: now,
|
|
2751
2888
|
lastActivityAt,
|
|
2752
|
-
}));
|
|
2889
|
+
})));
|
|
2753
2890
|
changed = true;
|
|
2754
2891
|
}
|
|
2755
2892
|
} else if (maybeEmitActiveLongRunning(index, now)) {
|
|
@@ -2767,7 +2904,7 @@ async function runSubagent(
|
|
|
2767
2904
|
: undefined;
|
|
2768
2905
|
if (nextRunState !== currentActivityState) {
|
|
2769
2906
|
currentActivityState = nextRunState;
|
|
2770
|
-
statusPayload
|
|
2907
|
+
setOptionalProperty(statusPayload, "activityState", nextRunState);
|
|
2771
2908
|
changed = true;
|
|
2772
2909
|
}
|
|
2773
2910
|
statusPayload.lastUpdate = now;
|
|
@@ -2790,14 +2927,14 @@ async function runSubagent(
|
|
|
2790
2927
|
const now = Date.now();
|
|
2791
2928
|
statusPayload.state = "paused";
|
|
2792
2929
|
currentActivityState = undefined;
|
|
2793
|
-
statusPayload.activityState
|
|
2930
|
+
delete statusPayload.activityState;
|
|
2794
2931
|
statusPayload.lastUpdate = now;
|
|
2795
2932
|
for (const step of statusPayload.steps) {
|
|
2796
2933
|
if (step.status === "running") {
|
|
2797
2934
|
step.status = "paused";
|
|
2798
|
-
step.activityState
|
|
2935
|
+
delete step.activityState;
|
|
2799
2936
|
step.endedAt = now;
|
|
2800
|
-
step
|
|
2937
|
+
setOptionalProperty(step, "durationMs", step.startedAt ? now - step.startedAt : undefined);
|
|
2801
2938
|
step.lastActivityAt = now;
|
|
2802
2939
|
}
|
|
2803
2940
|
}
|
|
@@ -2818,7 +2955,7 @@ async function runSubagent(
|
|
|
2818
2955
|
statusPayload.stopped = true;
|
|
2819
2956
|
statusPayload.error = stopMessage;
|
|
2820
2957
|
currentActivityState = undefined;
|
|
2821
|
-
statusPayload.activityState
|
|
2958
|
+
delete statusPayload.activityState;
|
|
2822
2959
|
statusPayload.lastUpdate = now;
|
|
2823
2960
|
for (const step of statusPayload.steps) {
|
|
2824
2961
|
if (step.status !== "running" && step.status !== "pending") continue;
|
|
@@ -2826,7 +2963,7 @@ async function runSubagent(
|
|
|
2826
2963
|
step.error = stopMessage;
|
|
2827
2964
|
step.exitCode = 1;
|
|
2828
2965
|
step.stopped = true;
|
|
2829
|
-
step.activityState
|
|
2966
|
+
delete step.activityState;
|
|
2830
2967
|
step.endedAt = now;
|
|
2831
2968
|
step.durationMs = step.startedAt ? now - step.startedAt : 0;
|
|
2832
2969
|
step.lastActivityAt = now;
|
|
@@ -2851,7 +2988,7 @@ async function runSubagent(
|
|
|
2851
2988
|
statusPayload.timedOut = true;
|
|
2852
2989
|
statusPayload.error = message;
|
|
2853
2990
|
currentActivityState = undefined;
|
|
2854
|
-
statusPayload.activityState
|
|
2991
|
+
delete statusPayload.activityState;
|
|
2855
2992
|
statusPayload.lastUpdate = now;
|
|
2856
2993
|
for (const step of statusPayload.steps) {
|
|
2857
2994
|
if (step.status !== "running" && step.status !== "pending") continue;
|
|
@@ -2859,7 +2996,7 @@ async function runSubagent(
|
|
|
2859
2996
|
step.error = message;
|
|
2860
2997
|
step.exitCode = 1;
|
|
2861
2998
|
step.timedOut = true;
|
|
2862
|
-
step.activityState
|
|
2999
|
+
delete step.activityState;
|
|
2863
3000
|
step.endedAt = now;
|
|
2864
3001
|
step.durationMs = step.startedAt ? now - step.startedAt : 0;
|
|
2865
3002
|
step.lastActivityAt = now;
|
|
@@ -2977,7 +3114,7 @@ async function runSubagent(
|
|
|
2977
3114
|
statusPayload.state = "paused";
|
|
2978
3115
|
statusPayload.currentStep = flatIndex;
|
|
2979
3116
|
statusPayload.checkpoint = checkpoint;
|
|
2980
|
-
statusPayload.activityState
|
|
3117
|
+
delete statusPayload.activityState;
|
|
2981
3118
|
statusPayload.lastUpdate = now;
|
|
2982
3119
|
if (statusStep) {
|
|
2983
3120
|
statusStep.status = "paused";
|
|
@@ -3032,7 +3169,7 @@ async function runSubagent(
|
|
|
3032
3169
|
const groupStartFlatIndex = flatIndex;
|
|
3033
3170
|
let materialized: ReturnType<typeof materializeDynamicParallelStep>;
|
|
3034
3171
|
try {
|
|
3035
|
-
materialized = materializeDynamicParallelStep(step as Parameters<typeof materializeDynamicParallelStep>[0], outputs, stepIndex, { maxItems: config.dynamicFanoutMaxItems, allowRunnerFields: true });
|
|
3172
|
+
materialized = materializeDynamicParallelStep(step as Parameters<typeof materializeDynamicParallelStep>[0], outputs, stepIndex, omitUndefinedProperties({ maxItems: config.dynamicFanoutMaxItems, allowRunnerFields: true }));
|
|
3036
3173
|
if (materialized.parallel.length > 1 && step.parallel.outputPath && !step.parallel.namespaceOutputPath) {
|
|
3037
3174
|
throw new DynamicFanoutError(`Dynamic chain step ${stepIndex + 1} materialized ${materialized.parallel.length} items that resolve output to the same path: ${step.parallel.outputPath}. Remove the explicit output path or use an inherited relative agent output so each item can be isolated.`);
|
|
3038
3175
|
}
|
|
@@ -3055,11 +3192,11 @@ async function runSubagent(
|
|
|
3055
3192
|
statusPayload.lastUpdate = now;
|
|
3056
3193
|
markDynamicGraphGroup(stepIndex, "failed", message);
|
|
3057
3194
|
writeStatusPayload();
|
|
3058
|
-
results.push({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1 });
|
|
3195
|
+
results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1 }));
|
|
3059
3196
|
break;
|
|
3060
3197
|
}
|
|
3061
3198
|
|
|
3062
|
-
const effectiveDynamicGroupAcceptance = resolveEffectiveAcceptance({
|
|
3199
|
+
const effectiveDynamicGroupAcceptance = resolveEffectiveAcceptance(omitUndefinedProperties({
|
|
3063
3200
|
explicit: step.acceptanceInput,
|
|
3064
3201
|
agentName: step.parallel.agent,
|
|
3065
3202
|
acceptanceRole: step.acceptanceRole,
|
|
@@ -3068,7 +3205,7 @@ async function runSubagent(
|
|
|
3068
3205
|
async: true,
|
|
3069
3206
|
dynamicGroup: true,
|
|
3070
3207
|
agentContract: step.agentContract,
|
|
3071
|
-
});
|
|
3208
|
+
}));
|
|
3072
3209
|
|
|
3073
3210
|
if (materialized.parallel.length === 0) {
|
|
3074
3211
|
const now = Date.now();
|
|
@@ -3089,7 +3226,7 @@ async function runSubagent(
|
|
|
3089
3226
|
}
|
|
3090
3227
|
previousOutput = "Dynamic fanout produced 0 results.";
|
|
3091
3228
|
const groupAcceptance = effectiveDynamicGroupAcceptance.explicit && !timedOut && !stopped
|
|
3092
|
-
? await evaluateAcceptance({
|
|
3229
|
+
? await evaluateAcceptance(omitUndefinedProperties({
|
|
3093
3230
|
acceptance: effectiveDynamicGroupAcceptance,
|
|
3094
3231
|
output: "",
|
|
3095
3232
|
report: aggregateAcceptanceReport({
|
|
@@ -3100,7 +3237,7 @@ async function runSubagent(
|
|
|
3100
3237
|
signal: combinedAbortSignal([timeoutAbortController.signal, stopAbortController.signal]),
|
|
3101
3238
|
abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? "Subagent timed out.",
|
|
3102
3239
|
reportOptional: isAgentContractV1(step.agentContract),
|
|
3103
|
-
})
|
|
3240
|
+
}))
|
|
3104
3241
|
: undefined;
|
|
3105
3242
|
const groupStopped = stopped || stopAbortController.signal.aborted;
|
|
3106
3243
|
const groupTimedOut = !groupStopped && (timedOut || timeoutAbortController.signal.aborted);
|
|
@@ -3111,18 +3248,18 @@ async function runSubagent(
|
|
|
3111
3248
|
const errorMessage = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? "Subagent timed out." : groupAcceptanceFailure!;
|
|
3112
3249
|
statusPayload.state = groupStopped ? "stopped" : "failed";
|
|
3113
3250
|
statusPayload.error = errorMessage;
|
|
3114
|
-
statusPayload
|
|
3251
|
+
setOptionalProperty(statusPayload, "stopped", groupStopped ? true : statusPayload.stopped);
|
|
3115
3252
|
if (placeholder) {
|
|
3116
3253
|
placeholder.status = groupStopped ? "stopped" : "failed";
|
|
3117
3254
|
placeholder.error = errorMessage;
|
|
3118
3255
|
placeholder.exitCode = 1;
|
|
3119
|
-
placeholder
|
|
3120
|
-
placeholder
|
|
3256
|
+
setOptionalProperty(placeholder, "timedOut", groupTimedOut ? true : undefined);
|
|
3257
|
+
setOptionalProperty(placeholder, "stopped", groupStopped ? true : undefined);
|
|
3121
3258
|
}
|
|
3122
3259
|
markDynamicGraphGroup(stepIndex, groupStopped ? "stopped" : "failed", errorMessage, effectiveGroupAcceptance);
|
|
3123
3260
|
statusPayload.lastUpdate = Date.now();
|
|
3124
3261
|
writeStatusPayload();
|
|
3125
|
-
results.push({ agent: step.parallel.agent, context: step.parallel.context, output: errorMessage, error: errorMessage, success: false, exitCode: 1, timedOut: groupTimedOut ? true : undefined, stopped: groupStopped ? true : undefined, acceptance: effectiveGroupAcceptance });
|
|
3262
|
+
results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: errorMessage, error: errorMessage, success: false, exitCode: 1, timedOut: groupTimedOut ? true : undefined, stopped: groupStopped ? true : undefined, acceptance: effectiveGroupAcceptance }));
|
|
3126
3263
|
break;
|
|
3127
3264
|
}
|
|
3128
3265
|
flatIndex++;
|
|
@@ -3141,10 +3278,10 @@ async function runSubagent(
|
|
|
3141
3278
|
: step.parallel.outputPath;
|
|
3142
3279
|
const taskText = task.task ?? step.parallel.task;
|
|
3143
3280
|
const materializedTask = step.parallel.namespaceOutputPath ? injectSingleOutputInstruction(taskText, outputPath, step.parallel) : taskText;
|
|
3144
|
-
return {
|
|
3281
|
+
return omitUndefinedProperties({
|
|
3145
3282
|
...step.parallel,
|
|
3146
3283
|
task: materializedTask,
|
|
3147
|
-
effectiveAcceptance: resolveEffectiveAcceptance({
|
|
3284
|
+
effectiveAcceptance: resolveEffectiveAcceptance(omitUndefinedProperties({
|
|
3148
3285
|
explicit: step.parallel.acceptanceInput,
|
|
3149
3286
|
agentName: step.parallel.agent,
|
|
3150
3287
|
acceptanceRole: step.parallel.acceptanceRole,
|
|
@@ -3153,7 +3290,7 @@ async function runSubagent(
|
|
|
3153
3290
|
async: true,
|
|
3154
3291
|
dynamic: step.parallel.acceptanceInput === undefined,
|
|
3155
3292
|
agentContract: step.parallel.agentContract ?? step.agentContract,
|
|
3156
|
-
}),
|
|
3293
|
+
})),
|
|
3157
3294
|
systemPrompt: step.parallel.namespaceOutputPath ? injectOutputPathSystemPrompt(step.parallel.systemPrompt ?? "", outputPath, step.parallel) : step.parallel.systemPrompt,
|
|
3158
3295
|
outputPath,
|
|
3159
3296
|
label: task.label ?? step.parallel.label,
|
|
@@ -3161,22 +3298,23 @@ async function runSubagent(
|
|
|
3161
3298
|
...(thinkingOverride ? {
|
|
3162
3299
|
...(model ? { model } : {}),
|
|
3163
3300
|
...(thinking ? { thinking } : {}),
|
|
3164
|
-
...(step.parallel.modelCandidates ? { modelCandidates: step.parallel.modelCandidates.
|
|
3301
|
+
...(step.parallel.modelCandidates ? { modelCandidates: step.parallel.modelCandidates.flatMap((candidate) => {
|
|
3302
|
+
const resolved = applyThinkingSuffix(candidate, thinkingOverride, true);
|
|
3303
|
+
return resolved ? [resolved] : [];
|
|
3304
|
+
}) } : {}),
|
|
3165
3305
|
} : {}),
|
|
3166
|
-
structuredOutput: undefined,
|
|
3167
3306
|
structuredOutputSchema: step.parallel.structuredOutputSchema ?? step.parallel.structuredOutput?.schema,
|
|
3168
|
-
};
|
|
3307
|
+
});
|
|
3169
3308
|
});
|
|
3170
3309
|
const dynamicFlatStepCount = Math.max(statusPayload.steps.length - 1 + dynamicSteps.length, 1);
|
|
3171
3310
|
const dynamicStatusSteps: RunnerStatusStep[] = dynamicSteps.map((task, itemIndex) => {
|
|
3172
|
-
const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: groupStartFlatIndex + itemIndex, flatStepCount: dynamicFlatStepCount });
|
|
3173
|
-
return {
|
|
3311
|
+
const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: groupStartFlatIndex + itemIndex, flatStepCount: dynamicFlatStepCount }));
|
|
3312
|
+
return omitUndefinedProperties({
|
|
3174
3313
|
agent: task.agent,
|
|
3175
3314
|
...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
|
|
3176
3315
|
...(task.context ? { context: task.context } : {}),
|
|
3177
|
-
phase: task.phase ?? step.phase,
|
|
3178
|
-
label: task.label,
|
|
3179
|
-
outputName: undefined,
|
|
3316
|
+
...(task.phase ?? step.phase ? { phase: task.phase ?? step.phase } : {}),
|
|
3317
|
+
...(task.label ? { label: task.label } : {}),
|
|
3180
3318
|
structured: Boolean(task.structuredOutputSchema),
|
|
3181
3319
|
...(task.agentContract ? { agentContract: task.agentContract } : {}),
|
|
3182
3320
|
...(task.launchResolvedExtensions ? { launchResolvedExtensions: task.launchResolvedExtensions } : {}),
|
|
@@ -3184,13 +3322,13 @@ async function runSubagent(
|
|
|
3184
3322
|
status: "pending",
|
|
3185
3323
|
...(task.sessionFile ? { sessionFile: task.sessionFile } : {}),
|
|
3186
3324
|
...(transcriptPath ? { transcriptPath } : {}),
|
|
3187
|
-
skills: task.skills,
|
|
3188
|
-
model: task.model,
|
|
3189
|
-
thinking: task.thinking,
|
|
3190
|
-
|
|
3325
|
+
...(task.skills ? { skills: task.skills } : {}),
|
|
3326
|
+
...(task.model ? { model: task.model } : {}),
|
|
3327
|
+
...(task.thinking ? { thinking: task.thinking } : {}),
|
|
3328
|
+
...(task.modelCandidates && task.modelCandidates.length > 0 ? { attemptedModels: task.modelCandidates } : task.model ? { attemptedModels: [task.model] } : {}),
|
|
3191
3329
|
recentTools: [],
|
|
3192
3330
|
recentOutput: [],
|
|
3193
|
-
};
|
|
3331
|
+
});
|
|
3194
3332
|
});
|
|
3195
3333
|
statusPayload.steps.splice(groupStartFlatIndex, 1, ...dynamicStatusSteps);
|
|
3196
3334
|
if (config.childIntercomTargets) {
|
|
@@ -3219,7 +3357,7 @@ async function runSubagent(
|
|
|
3219
3357
|
shiftFlatIndexes(statusPayload.workflowGraph.nodes);
|
|
3220
3358
|
const groupNode = statusPayload.workflowGraph.nodes.find((node) => node.id === `step-${stepIndex}`);
|
|
3221
3359
|
if (groupNode) {
|
|
3222
|
-
groupNode.children = materialized.items.map((item, itemIndex) => ({
|
|
3360
|
+
groupNode.children = materialized.items.map((item, itemIndex) => omitUndefinedProperties({
|
|
3223
3361
|
id: `step-${stepIndex}-item-${item.idKey}`,
|
|
3224
3362
|
kind: "agent",
|
|
3225
3363
|
agent: step.parallel.agent,
|
|
@@ -3238,54 +3376,54 @@ async function runSubagent(
|
|
|
3238
3376
|
const concurrency = step.concurrency ?? MAX_PARALLEL_CONCURRENCY;
|
|
3239
3377
|
const failFast = step.failFast ?? false;
|
|
3240
3378
|
let aborted = false;
|
|
3241
|
-
const parallelResults = await mapConcurrent(dynamicSteps, concurrency, async (task, taskIdx) => {
|
|
3379
|
+
const parallelResults = await mapConcurrent(dynamicSteps, concurrency, async (task, taskIdx): Promise<StepResult> => {
|
|
3242
3380
|
const fi = groupStartFlatIndex + taskIdx;
|
|
3243
3381
|
refreshUsageBudget();
|
|
3244
3382
|
if (statusPayload.usageBudget?.exhausted) {
|
|
3245
3383
|
const skippedAt = Date.now();
|
|
3246
3384
|
const message = usageBudgetExceededMessage(statusPayload.usageBudget);
|
|
3247
|
-
statusPayload
|
|
3248
|
-
statusPayload
|
|
3249
|
-
statusPayload
|
|
3250
|
-
statusPayload
|
|
3251
|
-
statusPayload
|
|
3252
|
-
statusPayload
|
|
3385
|
+
requiredStatusStep(statusPayload, fi).status = "failed";
|
|
3386
|
+
requiredStatusStep(statusPayload, fi).error = message;
|
|
3387
|
+
requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
|
|
3388
|
+
requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
|
|
3389
|
+
requiredStatusStep(statusPayload, fi).durationMs = 0;
|
|
3390
|
+
requiredStatusStep(statusPayload, fi).exitCode = 1;
|
|
3253
3391
|
statusPayload.lastUpdate = skippedAt;
|
|
3254
3392
|
usageBudgetExceeded = true;
|
|
3255
3393
|
writeStatusPayload();
|
|
3256
3394
|
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0 }));
|
|
3257
|
-
return { agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true };
|
|
3395
|
+
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
|
|
3258
3396
|
}
|
|
3259
3397
|
if (timedOut) return timedOutStepResult(task.agent, task.context);
|
|
3260
3398
|
if (stopped) return stoppedStepResult(task.agent, task.context);
|
|
3261
3399
|
if (interrupted) return pausedStepResult(task.agent, task.context);
|
|
3262
3400
|
if (aborted && failFast) {
|
|
3263
3401
|
const skippedAt = Date.now();
|
|
3264
|
-
statusPayload
|
|
3265
|
-
statusPayload
|
|
3266
|
-
statusPayload
|
|
3267
|
-
statusPayload
|
|
3268
|
-
statusPayload
|
|
3269
|
-
statusPayload
|
|
3402
|
+
requiredStatusStep(statusPayload, fi).status = "failed";
|
|
3403
|
+
requiredStatusStep(statusPayload, fi).error = "Skipped due to fail-fast";
|
|
3404
|
+
requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
|
|
3405
|
+
requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
|
|
3406
|
+
requiredStatusStep(statusPayload, fi).durationMs = 0;
|
|
3407
|
+
requiredStatusStep(statusPayload, fi).exitCode = -1;
|
|
3270
3408
|
statusPayload.lastUpdate = skippedAt;
|
|
3271
3409
|
writeStatusPayload();
|
|
3272
|
-
return { agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true };
|
|
3410
|
+
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
|
|
3273
3411
|
}
|
|
3274
3412
|
const taskStartTime = Date.now();
|
|
3275
3413
|
statusPayload.currentStep = fi;
|
|
3276
|
-
statusPayload
|
|
3277
|
-
statusPayload
|
|
3278
|
-
statusPayload
|
|
3279
|
-
resetStepLiveDetail(statusPayload
|
|
3280
|
-
statusPayload
|
|
3281
|
-
statusPayload
|
|
3414
|
+
requiredStatusStep(statusPayload, fi).status = "running";
|
|
3415
|
+
delete requiredStatusStep(statusPayload, fi).error;
|
|
3416
|
+
delete requiredStatusStep(statusPayload, fi).activityState;
|
|
3417
|
+
resetStepLiveDetail(requiredStatusStep(statusPayload, fi));
|
|
3418
|
+
requiredStatusStep(statusPayload, fi).startedAt = taskStartTime;
|
|
3419
|
+
requiredStatusStep(statusPayload, fi).lastActivityAt = taskStartTime;
|
|
3282
3420
|
statusPayload.outputFile = path.join(asyncDir, `output-${fi}.log`);
|
|
3283
3421
|
statusPayload.lastActivityAt = taskStartTime;
|
|
3284
3422
|
statusPayload.lastUpdate = taskStartTime;
|
|
3285
3423
|
writeStatusPayload();
|
|
3286
3424
|
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.started", ts: taskStartTime, runId: id, stepIndex: fi, agent: task.agent }));
|
|
3287
3425
|
flushPendingStepSteers(fi);
|
|
3288
|
-
const singleResult = await runSingleStep(task, {
|
|
3426
|
+
const singleResult = await runSingleStep(task, compactOptional<SingleStepContext>({
|
|
3289
3427
|
previousOutput, placeholder, cwd, sessionEnabled,
|
|
3290
3428
|
outputs,
|
|
3291
3429
|
sessionDir: config.sessionDir ? path.join(config.sessionDir, `dynamic-${stepIndex}-${taskIdx}`) : undefined,
|
|
@@ -3313,32 +3451,33 @@ async function runSubagent(
|
|
|
3313
3451
|
onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking),
|
|
3314
3452
|
onChildEvent: (event) => updateStepFromChildEvent(fi, event),
|
|
3315
3453
|
onWriterProcess,
|
|
3454
|
+
onExternalProcess: (process) => updateExternalProcess(fi, process),
|
|
3316
3455
|
skipAcceptance: () => timedOut || stopped,
|
|
3317
|
-
});
|
|
3456
|
+
}));
|
|
3318
3457
|
const taskEndTime = Date.now();
|
|
3319
3458
|
const childInterrupted = singleResult.interrupted === true;
|
|
3320
3459
|
const childStopped = singleResult.stopped === true;
|
|
3321
|
-
statusPayload
|
|
3322
|
-
statusPayload
|
|
3323
|
-
statusPayload
|
|
3324
|
-
statusPayload
|
|
3325
|
-
statusPayload
|
|
3326
|
-
statusPayload
|
|
3327
|
-
statusPayload
|
|
3328
|
-
statusPayload
|
|
3329
|
-
statusPayload
|
|
3330
|
-
statusPayload
|
|
3331
|
-
statusPayload
|
|
3460
|
+
requiredStatusStep(statusPayload, fi).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
|
|
3461
|
+
requiredStatusStep(statusPayload, fi).endedAt = taskEndTime;
|
|
3462
|
+
requiredStatusStep(statusPayload, fi).durationMs = taskEndTime - taskStartTime;
|
|
3463
|
+
requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
|
|
3464
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
|
|
3465
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
|
|
3466
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudget", singleResult.turnBudget);
|
|
3467
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
|
|
3468
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "wrapUpRequested", singleResult.wrapUpRequested);
|
|
3469
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
|
|
3470
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
|
|
3332
3471
|
if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
|
|
3333
3472
|
if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
|
|
3334
3473
|
if (singleResult.turnBudget) statusPayload.turnBudget = singleResult.turnBudget;
|
|
3335
3474
|
if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
|
|
3336
3475
|
if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
|
|
3337
|
-
statusPayload
|
|
3338
|
-
statusPayload
|
|
3339
|
-
statusPayload
|
|
3340
|
-
statusPayload
|
|
3341
|
-
statusPayload
|
|
3476
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
|
|
3477
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
|
|
3478
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
|
|
3479
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "modelAttempts", singleResult.modelAttempts);
|
|
3480
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
|
|
3342
3481
|
if (singleResult.totalCost) {
|
|
3343
3482
|
pendingParallelUsageCost = {
|
|
3344
3483
|
inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
|
|
@@ -3347,23 +3486,23 @@ async function runSubagent(
|
|
|
3347
3486
|
};
|
|
3348
3487
|
refreshUsageBudget();
|
|
3349
3488
|
}
|
|
3350
|
-
statusPayload
|
|
3351
|
-
statusPayload
|
|
3352
|
-
statusPayload
|
|
3353
|
-
statusPayload
|
|
3354
|
-
statusPayload
|
|
3355
|
-
statusPayload
|
|
3356
|
-
statusPayload
|
|
3357
|
-
statusPayload
|
|
3358
|
-
statusPayload
|
|
3359
|
-
statusPayload
|
|
3360
|
-
statusPayload
|
|
3361
|
-
statusPayload
|
|
3362
|
-
statusPayload
|
|
3363
|
-
statusPayload
|
|
3364
|
-
statusPayload
|
|
3365
|
-
statusPayload
|
|
3366
|
-
statusPayload
|
|
3489
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
|
|
3490
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, fi).transcriptPath);
|
|
3491
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptError", singleResult.transcriptError);
|
|
3492
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "agentContract", singleResult.agentContract);
|
|
3493
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchContractDigest", singleResult.launchContractDigest);
|
|
3494
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
|
|
3495
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
|
|
3496
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "effects", singleResult.effects);
|
|
3497
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "execution", singleResult.execution);
|
|
3498
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "review", singleResult.review);
|
|
3499
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutput", singleResult.structuredOutput);
|
|
3500
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
|
|
3501
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
|
|
3502
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
|
|
3503
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
|
|
3504
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
|
|
3505
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
|
|
3367
3506
|
if (singleResult.capabilityCeiling) statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
|
|
3368
3507
|
if (singleResult.capabilityAudit) statusPayload.capabilityAudit = singleResult.capabilityAudit;
|
|
3369
3508
|
statusPayload.lastUpdate = taskEndTime;
|
|
@@ -3380,7 +3519,7 @@ async function runSubagent(
|
|
|
3380
3519
|
|
|
3381
3520
|
flatIndex += dynamicSteps.length;
|
|
3382
3521
|
for (const pr of parallelResults) {
|
|
3383
|
-
results.push({
|
|
3522
|
+
results.push(omitUndefinedProperties({
|
|
3384
3523
|
agent: pr.agent,
|
|
3385
3524
|
context: pr.context,
|
|
3386
3525
|
agentContract: pr.agentContract,
|
|
@@ -3421,7 +3560,7 @@ async function runSubagent(
|
|
|
3421
3560
|
watchdog: pr.watchdog,
|
|
3422
3561
|
capabilityCeiling: pr.capabilityCeiling,
|
|
3423
3562
|
capabilityAudit: pr.capabilityAudit,
|
|
3424
|
-
});
|
|
3563
|
+
}));
|
|
3425
3564
|
}
|
|
3426
3565
|
pendingParallelUsageCost = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
|
|
3427
3566
|
refreshUsageBudget();
|
|
@@ -3432,9 +3571,9 @@ async function runSubagent(
|
|
|
3432
3571
|
.filter(({ result, task }) => isAgentContractV1(task?.agentContract ?? step.agentContract) && task?.gateOn === "acceptance" && result.acceptance?.status === "rejected");
|
|
3433
3572
|
if (acceptanceFailures.length > 0) {
|
|
3434
3573
|
const message = acceptanceFailures
|
|
3435
|
-
.map(({ result, originalIndex }) => `Dynamic item ${originalIndex + 1} (${result.agent}, key ${materialized.items[originalIndex]?.key ?? originalIndex}) acceptance rejected: ${acceptanceFailureMessage(result.acceptance) ?? "acceptance rejected"}`)
|
|
3574
|
+
.map(({ result, originalIndex }) => `Dynamic item ${originalIndex + 1} (${result.agent}, key ${materialized.items[originalIndex]?.key ?? originalIndex}) acceptance rejected: ${(result.acceptance ? acceptanceFailureMessage(result.acceptance) : undefined) ?? "acceptance rejected"}`)
|
|
3436
3575
|
.join("\n");
|
|
3437
|
-
results.push({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection });
|
|
3576
|
+
results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection }));
|
|
3438
3577
|
statusPayload.error = message;
|
|
3439
3578
|
markDynamicGraphGroup(stepIndex, "failed", message);
|
|
3440
3579
|
}
|
|
@@ -3449,7 +3588,7 @@ async function runSubagent(
|
|
|
3449
3588
|
};
|
|
3450
3589
|
statusPayload.outputs = outputs;
|
|
3451
3590
|
const groupAcceptance = !timedOut && !stopped
|
|
3452
|
-
? await evaluateAcceptance({
|
|
3591
|
+
? await evaluateAcceptance(omitUndefinedProperties({
|
|
3453
3592
|
acceptance: effectiveDynamicGroupAcceptance,
|
|
3454
3593
|
output: "",
|
|
3455
3594
|
report: aggregateAcceptanceReport({
|
|
@@ -3460,7 +3599,7 @@ async function runSubagent(
|
|
|
3460
3599
|
signal: combinedAbortSignal([timeoutAbortController.signal, stopAbortController.signal]),
|
|
3461
3600
|
abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? "Subagent timed out.",
|
|
3462
3601
|
reportOptional: isAgentContractV1(step.agentContract),
|
|
3463
|
-
})
|
|
3602
|
+
}))
|
|
3464
3603
|
: undefined;
|
|
3465
3604
|
const groupStopped = stopped || stopAbortController.signal.aborted;
|
|
3466
3605
|
const groupTimedOut = !groupStopped && (timedOut || timeoutAbortController.signal.aborted);
|
|
@@ -3469,7 +3608,7 @@ async function runSubagent(
|
|
|
3469
3608
|
const groupError = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? "Subagent timed out." : groupAcceptanceFailure;
|
|
3470
3609
|
markDynamicGraphGroup(stepIndex, groupError ? groupStopped ? "stopped" : "failed" : "completed", groupError, effectiveGroupAcceptance);
|
|
3471
3610
|
if (groupError) {
|
|
3472
|
-
results.push({
|
|
3611
|
+
results.push(omitUndefinedProperties({
|
|
3473
3612
|
agent: step.parallel.agent,
|
|
3474
3613
|
output: groupError,
|
|
3475
3614
|
error: groupError,
|
|
@@ -3479,19 +3618,19 @@ async function runSubagent(
|
|
|
3479
3618
|
stopped: groupStopped ? true : undefined,
|
|
3480
3619
|
structuredOutput: collection,
|
|
3481
3620
|
acceptance: effectiveGroupAcceptance,
|
|
3482
|
-
});
|
|
3621
|
+
}));
|
|
3483
3622
|
statusPayload.error = groupError;
|
|
3484
|
-
statusPayload
|
|
3623
|
+
setOptionalProperty(statusPayload, "stopped", groupStopped ? true : statusPayload.stopped);
|
|
3485
3624
|
}
|
|
3486
3625
|
} catch (error) {
|
|
3487
3626
|
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
3488
|
-
results.push({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection });
|
|
3627
|
+
results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection }));
|
|
3489
3628
|
statusPayload.error = message;
|
|
3490
3629
|
markDynamicGraphGroup(stepIndex, "failed", message);
|
|
3491
3630
|
}
|
|
3492
3631
|
}
|
|
3493
3632
|
previousOutput = aggregateParallelOutputs(
|
|
3494
|
-
parallelResults.map((r, i) => ({
|
|
3633
|
+
parallelResults.map((r, i) => omitUndefinedProperties({
|
|
3495
3634
|
agent: r.agent,
|
|
3496
3635
|
taskIndex: i,
|
|
3497
3636
|
output: r.output,
|
|
@@ -3543,13 +3682,13 @@ async function runSubagent(
|
|
|
3543
3682
|
break;
|
|
3544
3683
|
}
|
|
3545
3684
|
try {
|
|
3546
|
-
worktreeSetup = createWorktrees(cwd, `${id}-s${stepIndex}`, group.parallel.length, {
|
|
3685
|
+
worktreeSetup = createWorktrees(cwd, `${id}-s${stepIndex}`, group.parallel.length, omitUndefinedProperties({
|
|
3547
3686
|
agents: group.parallel.map((task) => task.agent),
|
|
3548
3687
|
setupHook: config.worktreeSetupHook
|
|
3549
|
-
? { hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs }
|
|
3688
|
+
? omitUndefinedProperties({ hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs })
|
|
3550
3689
|
: undefined,
|
|
3551
3690
|
baseDir: config.worktreeBaseDir,
|
|
3552
|
-
});
|
|
3691
|
+
}));
|
|
3553
3692
|
} catch (error) {
|
|
3554
3693
|
const setupError = error instanceof Error ? error.message : String(error);
|
|
3555
3694
|
const failedAt = Date.now();
|
|
@@ -3572,6 +3711,18 @@ async function runSubagent(
|
|
|
3572
3711
|
}
|
|
3573
3712
|
|
|
3574
3713
|
try {
|
|
3714
|
+
if (worktreeSetup) {
|
|
3715
|
+
writePendingParallelHandoff({
|
|
3716
|
+
manifestPath: parallelHandoffPath(asyncDir),
|
|
3717
|
+
runId: id,
|
|
3718
|
+
mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" : "chain",
|
|
3719
|
+
source: "async",
|
|
3720
|
+
cwd,
|
|
3721
|
+
stepIndex,
|
|
3722
|
+
flatStartIndex: groupStartFlatIndex,
|
|
3723
|
+
setup: worktreeSetup,
|
|
3724
|
+
});
|
|
3725
|
+
}
|
|
3575
3726
|
if (group.worktree) ensureParallelProgressFile(cwd, group);
|
|
3576
3727
|
const groupStartTime = Date.now();
|
|
3577
3728
|
markParallelGroupRunning({
|
|
@@ -3588,57 +3739,57 @@ async function runSubagent(
|
|
|
3588
3739
|
const parallelResults = await mapConcurrent(
|
|
3589
3740
|
group.parallel,
|
|
3590
3741
|
concurrency,
|
|
3591
|
-
async (task, taskIdx) => {
|
|
3742
|
+
async (task, taskIdx): Promise<StepResult> => {
|
|
3592
3743
|
const fi = groupStartFlatIndex + taskIdx;
|
|
3593
3744
|
refreshUsageBudget();
|
|
3594
3745
|
if (statusPayload.usageBudget?.exhausted) {
|
|
3595
3746
|
const skippedAt = Date.now();
|
|
3596
3747
|
const message = usageBudgetExceededMessage(statusPayload.usageBudget);
|
|
3597
|
-
statusPayload
|
|
3598
|
-
statusPayload
|
|
3599
|
-
statusPayload
|
|
3600
|
-
statusPayload
|
|
3601
|
-
statusPayload
|
|
3602
|
-
statusPayload
|
|
3603
|
-
statusPayload
|
|
3748
|
+
requiredStatusStep(statusPayload, fi).status = "failed";
|
|
3749
|
+
requiredStatusStep(statusPayload, fi).error = message;
|
|
3750
|
+
requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
|
|
3751
|
+
requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
|
|
3752
|
+
requiredStatusStep(statusPayload, fi).durationMs = 0;
|
|
3753
|
+
requiredStatusStep(statusPayload, fi).exitCode = 1;
|
|
3754
|
+
delete requiredStatusStep(statusPayload, fi).activityState;
|
|
3604
3755
|
statusPayload.lastUpdate = skippedAt;
|
|
3605
3756
|
usageBudgetExceeded = true;
|
|
3606
3757
|
writeStatusPayload();
|
|
3607
3758
|
appendJsonl(eventsPath, JSON.stringify({
|
|
3608
3759
|
type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0,
|
|
3609
3760
|
}));
|
|
3610
|
-
return { agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true };
|
|
3761
|
+
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
|
|
3611
3762
|
}
|
|
3612
3763
|
if (timedOut) return timedOutStepResult(task.agent, task.context);
|
|
3613
3764
|
if (stopped) return stoppedStepResult(task.agent, task.context);
|
|
3614
3765
|
if (interrupted) return pausedStepResult(task.agent, task.context);
|
|
3615
3766
|
if (aborted && failFast) {
|
|
3616
3767
|
const skippedAt = Date.now();
|
|
3617
|
-
statusPayload
|
|
3618
|
-
statusPayload
|
|
3619
|
-
statusPayload
|
|
3620
|
-
statusPayload
|
|
3621
|
-
statusPayload
|
|
3622
|
-
statusPayload
|
|
3623
|
-
statusPayload
|
|
3768
|
+
requiredStatusStep(statusPayload, fi).status = "failed";
|
|
3769
|
+
requiredStatusStep(statusPayload, fi).error = "Skipped due to fail-fast";
|
|
3770
|
+
requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
|
|
3771
|
+
requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
|
|
3772
|
+
requiredStatusStep(statusPayload, fi).durationMs = 0;
|
|
3773
|
+
requiredStatusStep(statusPayload, fi).exitCode = -1;
|
|
3774
|
+
delete requiredStatusStep(statusPayload, fi).activityState;
|
|
3624
3775
|
statusPayload.lastUpdate = skippedAt;
|
|
3625
3776
|
writeStatusPayload();
|
|
3626
3777
|
appendJsonl(eventsPath, JSON.stringify({
|
|
3627
3778
|
type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: -1, durationMs: 0,
|
|
3628
3779
|
}));
|
|
3629
|
-
return { agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true };
|
|
3780
|
+
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
|
|
3630
3781
|
}
|
|
3631
3782
|
|
|
3632
3783
|
const taskStartTime = Date.now();
|
|
3633
3784
|
statusPayload.currentStep = fi;
|
|
3634
|
-
statusPayload
|
|
3635
|
-
statusPayload
|
|
3636
|
-
statusPayload
|
|
3637
|
-
resetStepLiveDetail(statusPayload
|
|
3638
|
-
statusPayload
|
|
3639
|
-
statusPayload
|
|
3640
|
-
statusPayload
|
|
3641
|
-
statusPayload
|
|
3785
|
+
requiredStatusStep(statusPayload, fi).status = "running";
|
|
3786
|
+
delete requiredStatusStep(statusPayload, fi).error;
|
|
3787
|
+
delete requiredStatusStep(statusPayload, fi).activityState;
|
|
3788
|
+
resetStepLiveDetail(requiredStatusStep(statusPayload, fi));
|
|
3789
|
+
requiredStatusStep(statusPayload, fi).startedAt = taskStartTime;
|
|
3790
|
+
delete requiredStatusStep(statusPayload, fi).endedAt;
|
|
3791
|
+
delete requiredStatusStep(statusPayload, fi).durationMs;
|
|
3792
|
+
requiredStatusStep(statusPayload, fi).lastActivityAt = taskStartTime;
|
|
3642
3793
|
statusPayload.outputFile = path.join(asyncDir, `output-${fi}.log`);
|
|
3643
3794
|
statusPayload.lastActivityAt = taskStartTime;
|
|
3644
3795
|
statusPayload.lastUpdate = taskStartTime;
|
|
@@ -3654,7 +3805,7 @@ async function runSubagent(
|
|
|
3654
3805
|
const { taskForRun, taskCwd } = prepareParallelTaskRun(task, cwd, worktreeSetup, taskIdx);
|
|
3655
3806
|
flushPendingStepSteers(fi);
|
|
3656
3807
|
|
|
3657
|
-
const singleResult = await runSingleStep(taskForRun, {
|
|
3808
|
+
const singleResult = await runSingleStep(taskForRun, compactOptional<SingleStepContext>({
|
|
3658
3809
|
previousOutput, placeholder, cwd: taskCwd, sessionEnabled,
|
|
3659
3810
|
outputs,
|
|
3660
3811
|
sessionDir: taskSessionDir,
|
|
@@ -3682,8 +3833,9 @@ async function runSubagent(
|
|
|
3682
3833
|
onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking),
|
|
3683
3834
|
onChildEvent: (event) => updateStepFromChildEvent(fi, event),
|
|
3684
3835
|
onWriterProcess,
|
|
3836
|
+
onExternalProcess: (process) => updateExternalProcess(fi, process),
|
|
3685
3837
|
skipAcceptance: () => timedOut || stopped,
|
|
3686
|
-
});
|
|
3838
|
+
}));
|
|
3687
3839
|
if (task.sessionFile) {
|
|
3688
3840
|
latestSessionFile = task.sessionFile;
|
|
3689
3841
|
}
|
|
@@ -3693,27 +3845,27 @@ async function runSubagent(
|
|
|
3693
3845
|
const childInterrupted = singleResult.interrupted === true;
|
|
3694
3846
|
const childStopped = singleResult.stopped === true;
|
|
3695
3847
|
|
|
3696
|
-
statusPayload
|
|
3697
|
-
statusPayload
|
|
3698
|
-
statusPayload
|
|
3699
|
-
statusPayload
|
|
3700
|
-
statusPayload
|
|
3701
|
-
statusPayload
|
|
3702
|
-
statusPayload
|
|
3703
|
-
statusPayload
|
|
3704
|
-
statusPayload
|
|
3705
|
-
statusPayload
|
|
3706
|
-
statusPayload
|
|
3848
|
+
requiredStatusStep(statusPayload, fi).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
|
|
3849
|
+
requiredStatusStep(statusPayload, fi).endedAt = taskEndTime;
|
|
3850
|
+
requiredStatusStep(statusPayload, fi).durationMs = taskDuration;
|
|
3851
|
+
requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
|
|
3852
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
|
|
3853
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
|
|
3854
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudget", singleResult.turnBudget);
|
|
3855
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
|
|
3856
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "wrapUpRequested", singleResult.wrapUpRequested);
|
|
3857
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
|
|
3858
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
|
|
3707
3859
|
if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
|
|
3708
3860
|
if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
|
|
3709
3861
|
if (singleResult.turnBudget) statusPayload.turnBudget = singleResult.turnBudget;
|
|
3710
3862
|
if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
|
|
3711
3863
|
if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
|
|
3712
|
-
statusPayload
|
|
3713
|
-
statusPayload
|
|
3714
|
-
statusPayload
|
|
3715
|
-
statusPayload
|
|
3716
|
-
statusPayload
|
|
3864
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
|
|
3865
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
|
|
3866
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
|
|
3867
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "modelAttempts", singleResult.modelAttempts);
|
|
3868
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
|
|
3717
3869
|
if (singleResult.totalCost) {
|
|
3718
3870
|
pendingParallelUsageCost = {
|
|
3719
3871
|
inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
|
|
@@ -3722,22 +3874,22 @@ async function runSubagent(
|
|
|
3722
3874
|
};
|
|
3723
3875
|
refreshUsageBudget();
|
|
3724
3876
|
}
|
|
3725
|
-
statusPayload
|
|
3726
|
-
statusPayload
|
|
3727
|
-
statusPayload
|
|
3728
|
-
statusPayload
|
|
3729
|
-
statusPayload
|
|
3730
|
-
statusPayload
|
|
3731
|
-
statusPayload
|
|
3732
|
-
statusPayload
|
|
3733
|
-
statusPayload
|
|
3734
|
-
statusPayload
|
|
3735
|
-
statusPayload
|
|
3736
|
-
statusPayload
|
|
3737
|
-
statusPayload
|
|
3738
|
-
statusPayload
|
|
3739
|
-
statusPayload
|
|
3740
|
-
statusPayload
|
|
3877
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
|
|
3878
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, fi).transcriptPath);
|
|
3879
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptError", singleResult.transcriptError);
|
|
3880
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "agentContract", singleResult.agentContract);
|
|
3881
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
|
|
3882
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
|
|
3883
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "effects", singleResult.effects);
|
|
3884
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "execution", singleResult.execution);
|
|
3885
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "review", singleResult.review);
|
|
3886
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutput", singleResult.structuredOutput);
|
|
3887
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
|
|
3888
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
|
|
3889
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
|
|
3890
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
|
|
3891
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
|
|
3892
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
|
|
3741
3893
|
if (singleResult.capabilityCeiling) statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
|
|
3742
3894
|
if (singleResult.capabilityAudit) statusPayload.capabilityAudit = singleResult.capabilityAudit;
|
|
3743
3895
|
statusPayload.lastUpdate = taskEndTime;
|
|
@@ -3750,8 +3902,8 @@ async function runSubagent(
|
|
|
3750
3902
|
exitCode: stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode, durationMs: taskDuration,
|
|
3751
3903
|
}));
|
|
3752
3904
|
if (singleResult.completionGuardTriggered) {
|
|
3753
|
-
const event = buildControlEvent({
|
|
3754
|
-
from: statusPayload
|
|
3905
|
+
const event = buildControlEvent(omitUndefinedProperties({
|
|
3906
|
+
from: requiredStatusStep(statusPayload, fi).activityState,
|
|
3755
3907
|
to: "needs_attention",
|
|
3756
3908
|
runId: id,
|
|
3757
3909
|
agent: task.agent,
|
|
@@ -3759,7 +3911,7 @@ async function runSubagent(
|
|
|
3759
3911
|
ts: taskEndTime,
|
|
3760
3912
|
message: `${task.agent} completed without making edits for an implementation task`,
|
|
3761
3913
|
reason: "completion_guard",
|
|
3762
|
-
});
|
|
3914
|
+
}));
|
|
3763
3915
|
appendControlEvent(event);
|
|
3764
3916
|
}
|
|
3765
3917
|
|
|
@@ -3778,7 +3930,7 @@ async function runSubagent(
|
|
|
3778
3930
|
: null;
|
|
3779
3931
|
const taskTokens = sessionTokens ?? tokenUsageFromAttempts(parallelResults[t]?.modelAttempts);
|
|
3780
3932
|
if (!taskTokens) continue;
|
|
3781
|
-
statusPayload
|
|
3933
|
+
requiredStatusStep(statusPayload, fi).tokens = taskTokens;
|
|
3782
3934
|
previousCumulativeTokens = {
|
|
3783
3935
|
input: previousCumulativeTokens.input + taskTokens.input,
|
|
3784
3936
|
output: previousCumulativeTokens.output + taskTokens.output,
|
|
@@ -3790,7 +3942,7 @@ async function runSubagent(
|
|
|
3790
3942
|
writeStatusPayload();
|
|
3791
3943
|
|
|
3792
3944
|
for (const pr of parallelResults) {
|
|
3793
|
-
results.push({
|
|
3945
|
+
results.push(omitUndefinedProperties({
|
|
3794
3946
|
agent: pr.agent,
|
|
3795
3947
|
context: pr.context,
|
|
3796
3948
|
agentContract: pr.agentContract,
|
|
@@ -3828,7 +3980,7 @@ async function runSubagent(
|
|
|
3828
3980
|
structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
|
|
3829
3981
|
acceptance: pr.acceptance,
|
|
3830
3982
|
watchdog: pr.watchdog,
|
|
3831
|
-
});
|
|
3983
|
+
}));
|
|
3832
3984
|
}
|
|
3833
3985
|
pendingParallelUsageCost = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
|
|
3834
3986
|
refreshUsageBudget();
|
|
@@ -3843,7 +3995,7 @@ async function runSubagent(
|
|
|
3843
3995
|
statusPayload.outputs = outputs;
|
|
3844
3996
|
|
|
3845
3997
|
previousOutput = aggregateParallelOutputs(
|
|
3846
|
-
parallelResults.map((r) => ({
|
|
3998
|
+
parallelResults.map((r) => omitUndefinedProperties({
|
|
3847
3999
|
agent: r.agent,
|
|
3848
4000
|
output: r.output,
|
|
3849
4001
|
exitCode: r.exitCode,
|
|
@@ -3856,35 +4008,37 @@ async function runSubagent(
|
|
|
3856
4008
|
const captured = captureParallelWorktreeDiffs(worktreeSetup, asyncDir, stepIndex, group);
|
|
3857
4009
|
if (captured.summary) previousOutput = `${previousOutput}\n\n${captured.summary}`;
|
|
3858
4010
|
worktreeFinalized = true;
|
|
3859
|
-
const
|
|
4011
|
+
const manifestPath = parallelHandoffPath(asyncDir);
|
|
4012
|
+
const handoff = {
|
|
4013
|
+
manifestPath,
|
|
4014
|
+
runId: id,
|
|
4015
|
+
mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" as const : "chain" as const,
|
|
4016
|
+
source: "async" as const,
|
|
4017
|
+
cwd,
|
|
4018
|
+
stepIndex,
|
|
4019
|
+
flatStartIndex: groupStartFlatIndex,
|
|
4020
|
+
setup: worktreeSetup,
|
|
4021
|
+
diffs: captured.diffs,
|
|
4022
|
+
results: parallelResults.map((result) => ({
|
|
4023
|
+
agent: result.agent,
|
|
4024
|
+
status: result.stopped || (result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
|
|
4025
|
+
processSignal: result.processSignal,
|
|
4026
|
+
interrupted: result.interrupted,
|
|
4027
|
+
timedOut: result.timedOut,
|
|
4028
|
+
stopped: result.stopped,
|
|
4029
|
+
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
4030
|
+
}))) ? "stopped" as const : result.interrupted ? "paused" as const : result.exitCode === 0 ? "completed" as const : "failed" as const,
|
|
4031
|
+
summary: result.output || result.error || "(no output)",
|
|
4032
|
+
...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
|
|
4033
|
+
...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
|
|
4034
|
+
...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
|
|
4035
|
+
...(result.sessionFile ? { sessionPath: result.sessionFile } : {}),
|
|
4036
|
+
})),
|
|
4037
|
+
};
|
|
3860
4038
|
try {
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" : "chain",
|
|
3865
|
-
source: "async",
|
|
3866
|
-
cwd,
|
|
3867
|
-
stepIndex,
|
|
3868
|
-
flatStartIndex: groupStartFlatIndex,
|
|
3869
|
-
setup: worktreeSetup,
|
|
3870
|
-
diffs: captured.diffs,
|
|
3871
|
-
cleanup,
|
|
3872
|
-
results: parallelResults.map((result) => ({
|
|
3873
|
-
agent: result.agent,
|
|
3874
|
-
status: result.stopped || (result.exitCode !== 0 && isUnexplainedProcessSignal({
|
|
3875
|
-
processSignal: result.processSignal,
|
|
3876
|
-
interrupted: result.interrupted,
|
|
3877
|
-
timedOut: result.timedOut,
|
|
3878
|
-
stopped: result.stopped,
|
|
3879
|
-
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
3880
|
-
})) ? "stopped" : result.interrupted ? "paused" : result.exitCode === 0 ? "completed" : "failed",
|
|
3881
|
-
summary: result.output || result.error || "(no output)",
|
|
3882
|
-
...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
|
|
3883
|
-
...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
|
|
3884
|
-
...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
|
|
3885
|
-
...(result.sessionFile ? { sessionPath: result.sessionFile } : {}),
|
|
3886
|
-
})),
|
|
3887
|
-
});
|
|
4039
|
+
writeParallelHandoffGroup(handoff);
|
|
4040
|
+
const cleanup = cleanupWorktrees(worktreeSetup, { kind: "preserve", capturedDiffs: captured.diffs, handoffManifestPath: manifestPath });
|
|
4041
|
+
statusPayload.parallelHandoff = writeParallelHandoffGroup({ ...handoff, cleanup });
|
|
3888
4042
|
previousOutput = `${previousOutput}\n\n${formatParallelHandoffReference(statusPayload.parallelHandoff)}`;
|
|
3889
4043
|
} catch (error) {
|
|
3890
4044
|
previousOutput = `${previousOutput}\n\n${formatParallelHandoffError(error)}`;
|
|
@@ -3905,7 +4059,7 @@ async function runSubagent(
|
|
|
3905
4059
|
.map((result, index) => ({ result, index, task: group.parallel[index] }))
|
|
3906
4060
|
.find(({ result, task }) => isAgentContractV1(task?.agentContract) && task?.gateOn === "acceptance" && result.acceptance?.status === "rejected");
|
|
3907
4061
|
if (acceptanceGateFailure) {
|
|
3908
|
-
statusPayload.error = acceptanceFailureMessage(acceptanceGateFailure.result.acceptance) ?? "Parallel acceptance gate rejected the step.";
|
|
4062
|
+
statusPayload.error = (acceptanceGateFailure.result.acceptance ? acceptanceFailureMessage(acceptanceGateFailure.result.acceptance) : undefined) ?? "Parallel acceptance gate rejected the step.";
|
|
3909
4063
|
writeStatusPayload();
|
|
3910
4064
|
break;
|
|
3911
4065
|
}
|
|
@@ -3919,13 +4073,13 @@ async function runSubagent(
|
|
|
3919
4073
|
const seqStep = step as SubagentStep;
|
|
3920
4074
|
const stepStartTime = Date.now();
|
|
3921
4075
|
statusPayload.currentStep = flatIndex;
|
|
3922
|
-
statusPayload
|
|
3923
|
-
statusPayload
|
|
3924
|
-
statusPayload.activityState
|
|
3925
|
-
resetStepLiveDetail(statusPayload
|
|
3926
|
-
statusPayload
|
|
3927
|
-
statusPayload
|
|
3928
|
-
statusPayload
|
|
4076
|
+
requiredStatusStep(statusPayload, flatIndex).status = "running";
|
|
4077
|
+
delete requiredStatusStep(statusPayload, flatIndex).activityState;
|
|
4078
|
+
delete statusPayload.activityState;
|
|
4079
|
+
resetStepLiveDetail(requiredStatusStep(statusPayload, flatIndex));
|
|
4080
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "skills", seqStep.skills);
|
|
4081
|
+
requiredStatusStep(statusPayload, flatIndex).startedAt = stepStartTime;
|
|
4082
|
+
requiredStatusStep(statusPayload, flatIndex).lastActivityAt = stepStartTime;
|
|
3929
4083
|
statusPayload.lastActivityAt = stepStartTime;
|
|
3930
4084
|
statusPayload.lastUpdate = stepStartTime;
|
|
3931
4085
|
statusPayload.outputFile = path.join(asyncDir, `output-${flatIndex}.log`);
|
|
@@ -3940,7 +4094,7 @@ async function runSubagent(
|
|
|
3940
4094
|
}));
|
|
3941
4095
|
|
|
3942
4096
|
flushPendingStepSteers(flatIndex);
|
|
3943
|
-
const singleResult = await runSingleStep(seqStep, {
|
|
4097
|
+
const singleResult = await runSingleStep(seqStep, compactOptional<SingleStepContext>({
|
|
3944
4098
|
previousOutput, placeholder, cwd, sessionEnabled,
|
|
3945
4099
|
outputs: statusPayload.mode === "single" ? undefined : outputs,
|
|
3946
4100
|
sessionDir: config.sessionDir,
|
|
@@ -3968,15 +4122,16 @@ async function runSubagent(
|
|
|
3968
4122
|
onAttemptStart: (attempt) => updateStepModel(flatIndex, attempt.model, attempt.thinking),
|
|
3969
4123
|
onChildEvent: (event) => updateStepFromChildEvent(flatIndex, event),
|
|
3970
4124
|
onWriterProcess,
|
|
4125
|
+
onExternalProcess: (process) => updateExternalProcess(flatIndex, process),
|
|
3971
4126
|
skipAcceptance: () => timedOut || stopped,
|
|
3972
|
-
});
|
|
4127
|
+
}));
|
|
3973
4128
|
if (seqStep.sessionFile) {
|
|
3974
4129
|
latestSessionFile = seqStep.sessionFile;
|
|
3975
4130
|
}
|
|
3976
4131
|
|
|
3977
4132
|
previousOutput = singleResult.output;
|
|
3978
4133
|
const childStopped = singleResult.stopped === true;
|
|
3979
|
-
results.push({
|
|
4134
|
+
results.push(omitUndefinedProperties({
|
|
3980
4135
|
agent: singleResult.agent,
|
|
3981
4136
|
context: singleResult.context,
|
|
3982
4137
|
agentContract: singleResult.agentContract,
|
|
@@ -4016,7 +4171,9 @@ async function runSubagent(
|
|
|
4016
4171
|
wrapUpRequested: singleResult.wrapUpRequested,
|
|
4017
4172
|
toolBudget: singleResult.toolBudget,
|
|
4018
4173
|
toolBudgetBlocked: singleResult.toolBudgetBlocked,
|
|
4019
|
-
|
|
4174
|
+
runner: singleResult.runner,
|
|
4175
|
+
externalProcess: singleResult.externalProcess,
|
|
4176
|
+
}));
|
|
4020
4177
|
if (seqStep.outputName) {
|
|
4021
4178
|
outputs[seqStep.outputName] = outputEntryFromAsyncResult({
|
|
4022
4179
|
agent: singleResult.agent,
|
|
@@ -4049,47 +4206,47 @@ async function runSubagent(
|
|
|
4049
4206
|
|
|
4050
4207
|
const stepEndTime = Date.now();
|
|
4051
4208
|
const childInterrupted = singleResult.interrupted === true;
|
|
4052
|
-
statusPayload
|
|
4053
|
-
statusPayload
|
|
4054
|
-
statusPayload
|
|
4055
|
-
statusPayload
|
|
4056
|
-
statusPayload
|
|
4057
|
-
statusPayload
|
|
4058
|
-
statusPayload
|
|
4059
|
-
statusPayload
|
|
4060
|
-
statusPayload
|
|
4061
|
-
statusPayload
|
|
4062
|
-
statusPayload
|
|
4209
|
+
requiredStatusStep(statusPayload, flatIndex).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
|
|
4210
|
+
requiredStatusStep(statusPayload, flatIndex).endedAt = stepEndTime;
|
|
4211
|
+
requiredStatusStep(statusPayload, flatIndex).durationMs = stepEndTime - stepStartTime;
|
|
4212
|
+
requiredStatusStep(statusPayload, flatIndex).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
|
|
4213
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
|
|
4214
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "stopped", stopped || childStopped ? true : undefined);
|
|
4215
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "turnBudget", singleResult.turnBudget);
|
|
4216
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
|
|
4217
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "wrapUpRequested", singleResult.wrapUpRequested);
|
|
4218
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudget", singleResult.toolBudget);
|
|
4219
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
|
|
4063
4220
|
if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
|
|
4064
4221
|
if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
|
|
4065
4222
|
if (singleResult.turnBudget) statusPayload.turnBudget = singleResult.turnBudget;
|
|
4066
4223
|
if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
|
|
4067
4224
|
if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
|
|
4068
|
-
statusPayload
|
|
4069
|
-
statusPayload
|
|
4070
|
-
statusPayload
|
|
4071
|
-
statusPayload
|
|
4072
|
-
statusPayload
|
|
4073
|
-
statusPayload
|
|
4074
|
-
statusPayload
|
|
4075
|
-
statusPayload
|
|
4076
|
-
statusPayload
|
|
4077
|
-
statusPayload
|
|
4078
|
-
statusPayload
|
|
4079
|
-
statusPayload
|
|
4080
|
-
statusPayload
|
|
4081
|
-
statusPayload
|
|
4082
|
-
statusPayload
|
|
4083
|
-
statusPayload
|
|
4084
|
-
statusPayload
|
|
4085
|
-
statusPayload
|
|
4086
|
-
statusPayload
|
|
4087
|
-
statusPayload
|
|
4088
|
-
statusPayload
|
|
4225
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "model", singleResult.model);
|
|
4226
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, flatIndex).thinking));
|
|
4227
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "attemptedModels", singleResult.attemptedModels);
|
|
4228
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "modelAttempts", singleResult.modelAttempts);
|
|
4229
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "totalCost", singleResult.totalCost);
|
|
4230
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
|
|
4231
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, flatIndex).transcriptPath);
|
|
4232
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "transcriptError", singleResult.transcriptError);
|
|
4233
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "agentContract", singleResult.agentContract);
|
|
4234
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
|
|
4235
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
|
|
4236
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "effects", singleResult.effects);
|
|
4237
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "execution", singleResult.execution);
|
|
4238
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "review", singleResult.review);
|
|
4239
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutput", singleResult.structuredOutput);
|
|
4240
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputPath", singleResult.structuredOutputPath);
|
|
4241
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
|
|
4242
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "acceptance", singleResult.acceptance);
|
|
4243
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "watchdog", singleResult.watchdog);
|
|
4244
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityCeiling", singleResult.capabilityCeiling);
|
|
4245
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityAudit", singleResult.capabilityAudit);
|
|
4089
4246
|
if (singleResult.capabilityCeiling) statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
|
|
4090
4247
|
if (singleResult.capabilityAudit) statusPayload.capabilityAudit = singleResult.capabilityAudit;
|
|
4091
4248
|
if (stepTokens) {
|
|
4092
|
-
statusPayload
|
|
4249
|
+
requiredStatusStep(statusPayload, flatIndex).tokens = stepTokens;
|
|
4093
4250
|
statusPayload.totalTokens = { ...previousCumulativeTokens };
|
|
4094
4251
|
}
|
|
4095
4252
|
statusPayload.lastUpdate = stepEndTime;
|
|
@@ -4107,8 +4264,8 @@ async function runSubagent(
|
|
|
4107
4264
|
tokens: stepTokens,
|
|
4108
4265
|
}));
|
|
4109
4266
|
if (singleResult.completionGuardTriggered) {
|
|
4110
|
-
const event = buildControlEvent({
|
|
4111
|
-
from: statusPayload
|
|
4267
|
+
const event = buildControlEvent(omitUndefinedProperties({
|
|
4268
|
+
from: requiredStatusStep(statusPayload, flatIndex).activityState,
|
|
4112
4269
|
to: "needs_attention",
|
|
4113
4270
|
runId: id,
|
|
4114
4271
|
agent: seqStep.agent,
|
|
@@ -4116,7 +4273,7 @@ async function runSubagent(
|
|
|
4116
4273
|
ts: stepEndTime,
|
|
4117
4274
|
message: `${seqStep.agent} completed without making edits for an implementation task`,
|
|
4118
4275
|
reason: "completion_guard",
|
|
4119
|
-
});
|
|
4276
|
+
}));
|
|
4120
4277
|
appendControlEvent(event);
|
|
4121
4278
|
}
|
|
4122
4279
|
|
|
@@ -4197,13 +4354,13 @@ async function runSubagent(
|
|
|
4197
4354
|
clearTimeout(timeoutTimer);
|
|
4198
4355
|
timeoutTimer = undefined;
|
|
4199
4356
|
}
|
|
4200
|
-
const signalTerminated = !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal({
|
|
4357
|
+
const signalTerminated = !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
|
|
4201
4358
|
processSignal: result.processSignal,
|
|
4202
4359
|
interrupted: result.interrupted,
|
|
4203
4360
|
timedOut: result.timedOut,
|
|
4204
4361
|
stopped: result.stopped,
|
|
4205
4362
|
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
4206
|
-
}));
|
|
4363
|
+
})));
|
|
4207
4364
|
statusPayload.state = checkpointRejected ? "rejected" : stopped || signalTerminated ? "stopped" : timedOut || turnBudgetExceeded || usageBudgetExceeded || statusPayload.error ? "failed" : interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed";
|
|
4208
4365
|
closeSteerInbox(asyncDir, statusPayload.state);
|
|
4209
4366
|
disposeControlInbox();
|
|
@@ -4222,12 +4379,12 @@ async function runSubagent(
|
|
|
4222
4379
|
if (changed) emitTerminalSteeringNotice(request.id, `Steering failed for run ${id}: child terminated before delivery.`);
|
|
4223
4380
|
}
|
|
4224
4381
|
const runEndedAt = Date.now();
|
|
4225
|
-
statusPayload.activityState
|
|
4382
|
+
delete statusPayload.activityState;
|
|
4226
4383
|
if (stopped) {
|
|
4227
4384
|
statusPayload.stopped = true;
|
|
4228
4385
|
statusPayload.error = stopMessage;
|
|
4229
4386
|
} else if (signalTerminated && !statusPayload.error) {
|
|
4230
|
-
statusPayload
|
|
4387
|
+
setOptionalProperty(statusPayload, "error", results.find((result) => result.processSignal)?.error);
|
|
4231
4388
|
}
|
|
4232
4389
|
if (timedOut) {
|
|
4233
4390
|
statusPayload.timedOut = true;
|
|
@@ -4242,13 +4399,13 @@ async function runSubagent(
|
|
|
4242
4399
|
}
|
|
4243
4400
|
statusPayload.endedAt = runEndedAt;
|
|
4244
4401
|
statusPayload.lastUpdate = runEndedAt;
|
|
4245
|
-
statusPayload
|
|
4402
|
+
setOptionalProperty(statusPayload, "sessionFile", effectiveSessionFile);
|
|
4246
4403
|
if (singleRuntimeAcknowledgedExtensions) statusPayload.runtimeAcknowledgedExtensions = singleRuntimeAcknowledgedExtensions;
|
|
4247
|
-
statusPayload
|
|
4248
|
-
statusPayload
|
|
4249
|
-
statusPayload
|
|
4250
|
-
statusPayload
|
|
4251
|
-
statusPayload
|
|
4404
|
+
setOptionalProperty(statusPayload, "totalCost", finalTotalCost);
|
|
4405
|
+
setOptionalProperty(statusPayload, "usageBudget", usageBudgetState(config.usageBudget, currentUsageTotals()));
|
|
4406
|
+
setOptionalProperty(statusPayload, "shareUrl", shareUrl);
|
|
4407
|
+
setOptionalProperty(statusPayload, "gistUrl", gistUrl);
|
|
4408
|
+
setOptionalProperty(statusPayload, "shareError", shareError);
|
|
4252
4409
|
if (statusPayload.state === "failed" && !statusPayload.error) {
|
|
4253
4410
|
const failedStep = statusPayload.steps.find((s) => s.status === "failed");
|
|
4254
4411
|
if (failedStep?.agent) {
|
|
@@ -4270,13 +4427,13 @@ async function runSubagent(
|
|
|
4270
4427
|
usageBudget: statusPayload.usageBudget,
|
|
4271
4428
|
}),
|
|
4272
4429
|
);
|
|
4273
|
-
writeRunLog(logPath, {
|
|
4430
|
+
writeRunLog(logPath, omitUndefinedProperties({
|
|
4274
4431
|
id,
|
|
4275
4432
|
mode: statusPayload.mode,
|
|
4276
4433
|
cwd,
|
|
4277
4434
|
startedAt: overallStartTime,
|
|
4278
4435
|
endedAt: runEndedAt,
|
|
4279
|
-
steps: statusPayload.steps.map((step) => ({
|
|
4436
|
+
steps: statusPayload.steps.map((step) => omitUndefinedProperties({
|
|
4280
4437
|
agent: step.agent,
|
|
4281
4438
|
status: step.status,
|
|
4282
4439
|
durationMs: step.durationMs,
|
|
@@ -4287,7 +4444,7 @@ async function runSubagent(
|
|
|
4287
4444
|
sessionFile: effectiveSessionFile,
|
|
4288
4445
|
shareUrl,
|
|
4289
4446
|
shareError,
|
|
4290
|
-
});
|
|
4447
|
+
}));
|
|
4291
4448
|
|
|
4292
4449
|
try {
|
|
4293
4450
|
writeAtomicJson(resultPath, {
|
|
@@ -4308,7 +4465,7 @@ async function runSubagent(
|
|
|
4308
4465
|
...(statusPayload.usageBudget ? { usageBudget: statusPayload.usageBudget } : {}),
|
|
4309
4466
|
...(statusPayload.checkpoint ? { checkpoint: statusPayload.checkpoint } : {}),
|
|
4310
4467
|
...(stopped ? { stopped: true, error: stopMessage } : timedOut ? { timedOut: true, error: timeoutMessage ?? "Subagent timed out." } : turnBudgetExceeded ? { error: statusPayload.error ?? "Subagent exceeded turn budget." } : usageBudgetExceeded ? { error: statusPayload.error ?? "Usage budget exhausted." } : {}),
|
|
4311
|
-
results: results.map((r) => ({
|
|
4468
|
+
results: results.map((r) => omitUndefinedProperties({
|
|
4312
4469
|
agent: r.agent,
|
|
4313
4470
|
context: r.context,
|
|
4314
4471
|
output: r.output,
|
|
@@ -4333,6 +4490,8 @@ async function runSubagent(
|
|
|
4333
4490
|
modelAttempts: r.modelAttempts,
|
|
4334
4491
|
totalCost: r.totalCost,
|
|
4335
4492
|
artifactPaths: r.artifactPaths,
|
|
4493
|
+
outputSaveError: r.outputSaveError,
|
|
4494
|
+
metadataSaveError: r.metadataSaveError,
|
|
4336
4495
|
truncated: r.truncated,
|
|
4337
4496
|
transcriptPath: r.transcriptPath,
|
|
4338
4497
|
transcriptError: r.transcriptError,
|
|
@@ -4340,6 +4499,8 @@ async function runSubagent(
|
|
|
4340
4499
|
launchContractDigest: r.launchContractDigest,
|
|
4341
4500
|
launchResolvedExtensions: r.launchResolvedExtensions,
|
|
4342
4501
|
runtimeAcknowledgedExtensions: r.runtimeAcknowledgedExtensions,
|
|
4502
|
+
runner: r.runner,
|
|
4503
|
+
externalProcess: r.externalProcess,
|
|
4343
4504
|
execution: r.execution,
|
|
4344
4505
|
review: r.review,
|
|
4345
4506
|
effects: r.effects,
|
|
@@ -4356,6 +4517,8 @@ async function runSubagent(
|
|
|
4356
4517
|
parallelHandoff: statusPayload.parallelHandoff,
|
|
4357
4518
|
capabilityCeiling: statusPayload.capabilityCeiling,
|
|
4358
4519
|
capabilityAudit: statusPayload.capabilityAudit,
|
|
4520
|
+
...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
|
|
4521
|
+
...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
|
|
4359
4522
|
exitCode: checkpointRejected || stopped || timedOut || turnBudgetExceeded || usageBudgetExceeded ? 1 : interrupted || results.every((r) => r.success) ? 0 : 1,
|
|
4360
4523
|
timestamp: runEndedAt,
|
|
4361
4524
|
durationMs: runEndedAt - overallStartTime,
|