pi-subagents 0.57.0 → 0.59.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 +104 -0
- package/docs/agents.md +18 -9
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +40 -1
- package/docs/models.md +27 -4
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +92 -6
- package/docs/workflows.md +115 -0
- package/package.json +3 -1
- package/prompts/review-loop.md +2 -2
- package/skills/council-mode/SKILL.md +1 -1
- package/skills/pi-subagents/SKILL.md +3 -1
- package/skills/pi-subagents/references/execution-controls.md +6 -2
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/prompting-and-roles.md +26 -5
- package/src/agents/agent-management.ts +28 -17
- package/src/agents/agent-serializer.ts +9 -2
- package/src/agents/agents.ts +103 -27
- package/src/agents/runtime-agent-events.ts +70 -0
- package/src/agents/runtime-agent-registry.ts +19 -18
- package/src/api/agents.ts +10 -5
- package/src/api/background-work.ts +5 -1
- package/src/api/delegation.ts +0 -7
- package/src/api/preflight.ts +32 -10
- package/src/extension/fanout-child.ts +5 -3
- package/src/extension/index.ts +66 -27
- package/src/extension/public-execution.ts +15 -2
- package/src/extension/rpc.ts +35 -14
- package/src/extension/schemas.ts +37 -12
- package/src/extension/tool-description.ts +25 -6
- package/src/integrations/herdr-status.ts +5 -0
- package/src/intercom/result-intercom.ts +2 -0
- package/src/profiles/profiles.ts +5 -6
- package/src/runs/background/active-async-capacity.ts +2 -2
- package/src/runs/background/async-execution.ts +78 -46
- package/src/runs/background/async-job-tracker.ts +14 -12
- package/src/runs/background/async-resume.ts +29 -27
- package/src/runs/background/async-status-snapshot.ts +23 -261
- package/src/runs/background/async-status.ts +68 -7
- package/src/runs/background/chain-append.ts +8 -3
- package/src/runs/background/chain-root-attachment.ts +60 -8
- package/src/runs/background/fleet-view.ts +21 -11
- package/src/runs/background/notify.ts +184 -9
- package/src/runs/background/result-delivery-ownership.ts +45 -0
- package/src/runs/background/result-files.ts +2 -1
- package/src/runs/background/result-watcher.ts +29 -10
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/retained-children.ts +1 -1
- package/src/runs/background/run-status.ts +18 -8
- package/src/runs/background/scheduled-runs.ts +86 -7
- package/src/runs/background/stale-run-reconciler.ts +10 -4
- package/src/runs/background/steering.ts +4 -14
- package/src/runs/background/subagent-runner.ts +389 -350
- package/src/runs/background/subagent-wait.ts +58 -10
- package/src/runs/background/terminal-run-index.ts +1 -1
- package/src/runs/background/wait-completions.ts +22 -1
- package/src/runs/background/wait-config.ts +23 -9
- package/src/runs/background/wait-tool.ts +9 -2
- package/src/runs/foreground/async-steering-action.ts +2 -2
- package/src/runs/foreground/execution.ts +134 -121
- package/src/runs/foreground/foreground-control.ts +3 -0
- package/src/runs/foreground/foreground-history.ts +1 -0
- package/src/runs/foreground/subagent-executor.ts +527 -257
- package/src/runs/foreground/workflow-detach-reconcile.ts +130 -120
- package/src/runs/shared/abort-recovery.ts +119 -0
- package/src/runs/shared/async-status-projection.ts +463 -0
- package/src/runs/shared/child-identity.ts +19 -4
- package/src/runs/shared/child-launch-plan.ts +151 -0
- package/src/runs/shared/completion-evidence.ts +89 -0
- package/src/runs/shared/completion-guard.ts +5 -4
- package/src/runs/shared/dynamic-fanout.ts +3 -3
- package/src/runs/shared/fast-mode-extension.ts +5 -5
- package/src/runs/shared/host-step-status.ts +230 -0
- package/src/runs/shared/lane-metadata.ts +105 -0
- package/src/runs/shared/launch-cwd.ts +16 -0
- package/src/runs/shared/long-running-guard.ts +2 -1
- package/src/runs/shared/mcp-config-sources.ts +422 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
- package/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/src/runs/shared/model-exclusions.ts +12 -0
- package/src/runs/shared/model-fallback.ts +25 -6
- package/src/runs/shared/nested-events.ts +6 -2
- package/src/runs/shared/nested-render.ts +7 -3
- package/src/runs/shared/parallel-handoff.ts +419 -7
- package/src/runs/shared/parallel-utils.ts +15 -1
- package/src/runs/shared/pi-args.ts +81 -8
- package/src/runs/shared/single-output.ts +44 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +98 -13
- package/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/src/runs/shared/worktree.ts +18 -0
- package/src/shared/child-session-name.ts +46 -0
- package/src/shared/extension-context.ts +24 -0
- package/src/shared/formatters.ts +11 -2
- package/src/shared/launch-contract.ts +5 -1
- package/src/shared/settings.ts +9 -103
- package/src/shared/types.ts +240 -30
- package/src/shared/utils.ts +41 -84
- package/src/slash/delegation-adapters.ts +1 -8
- package/src/slash/delegation-request.ts +0 -4
- package/src/slash/slash-bridge.ts +1 -2
- package/src/slash/slash-commands.ts +369 -90
- package/src/slash/slash-live-state.ts +22 -11
- package/src/slash/subagents-admin.ts +3 -0
- package/src/tui/fleet-status.ts +125 -74
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render.ts +330 -33
- package/src/watchdog/turn-delta.ts +1 -1
- package/src/workflows/chat-progress.ts +6 -3
- package/src/workflows/host-command.ts +230 -0
- package/src/workflows/scripted-workflow.ts +496 -35
- package/src/workflows/workflow-child-summary.ts +9 -5
- package/src/workflows/workflow-preflight.ts +270 -0
- package/src/workflows/workflow-receipt.ts +79 -5
- package/src/workflows/workflow-settlement.ts +246 -0
- package/src/runs/shared/turn-budget.ts +0 -98
|
@@ -14,6 +14,7 @@ import { createChildTranscriptWriter, type ChildTranscriptWriter } from "../../s
|
|
|
14
14
|
import { closeSteerInbox, consumeInterruptRequest, consumeSteerRequests, deliverInterruptRequest, deliverStopRequest, deliverTimeoutRequest, enqueueStepSteer, steerAcksDir, steerCapabilityPath, stepSteerInboxDir, watchAsyncControlInbox, type SteerAck, type SteerCapability, type SteerRequest, type StopRequest } from "./control-channel.ts";
|
|
15
15
|
import { appendJsonl as appendRawJsonl, formatOutputArtifactContent, getArtifactPaths, writeArtifact, writeMetadata } from "../../shared/artifacts.ts";
|
|
16
16
|
import { PI_CODING_AGENT_PACKAGE, getPiSpawnCommand, resolveInstalledPiPackageRoot } from "../shared/pi-spawn.ts";
|
|
17
|
+
import { preflightLaunchCwd } from "../shared/launch-cwd.ts";
|
|
17
18
|
import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, injectSingleOutputInstruction, resolveSingleOutput, type SingleOutputSnapshot } from "../shared/single-output.ts";
|
|
18
19
|
import {
|
|
19
20
|
type ActivityState,
|
|
@@ -35,24 +36,21 @@ import {
|
|
|
35
36
|
type NestedRouteInfo,
|
|
36
37
|
type NestedRunSummary,
|
|
37
38
|
type ResolvedControlConfig,
|
|
38
|
-
type ResolvedTurnBudget,
|
|
39
39
|
type ResolvedToolBudget,
|
|
40
40
|
type RunFanoutBudgetDescriptor,
|
|
41
41
|
type SubagentRunMode,
|
|
42
42
|
type SubagentOutputState,
|
|
43
43
|
type UsageBudgetConfig,
|
|
44
44
|
type ToolBudgetState,
|
|
45
|
-
type TurnBudgetState,
|
|
46
45
|
type Usage,
|
|
47
46
|
type WorkflowGraphSnapshot,
|
|
48
|
-
type SteeringStatus,
|
|
49
47
|
type SteeringTargetState,
|
|
50
48
|
type SteeringTargetStatus,
|
|
51
49
|
type SubagentChildStatusEvent,
|
|
50
|
+
type WorkflowLaneMetadata,
|
|
52
51
|
DEFAULT_MAX_OUTPUT,
|
|
53
52
|
type MaxOutputConfig,
|
|
54
53
|
SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
|
|
55
|
-
POLL_INTERVAL_MS,
|
|
56
54
|
truncateOutput,
|
|
57
55
|
getSubagentDepthEnv,
|
|
58
56
|
} from "../../shared/types.ts";
|
|
@@ -78,6 +76,7 @@ import {
|
|
|
78
76
|
Semaphore,
|
|
79
77
|
} from "../shared/parallel-utils.ts";
|
|
80
78
|
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
|
|
79
|
+
import { deriveChildSessionName } from "../../shared/child-session-name.ts";
|
|
81
80
|
import { readRuntimeAcknowledgedExtensions } from "../shared/runtime-acknowledged-extensions.ts";
|
|
82
81
|
import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.ts";
|
|
83
82
|
import { createStructuredOutputRuntime, MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput, readStructuredOutputAcceptanceReport } from "../shared/structured-output.ts";
|
|
@@ -100,8 +99,10 @@ import { markProcessTerminalCandidateLeaseRelease, writeProcessTerminalCandidate
|
|
|
100
99
|
import { createOwnedProcessTreeController, type OwnedProcessTreeController } from "./owned-process-tree.ts";
|
|
101
100
|
import { createSteeringStatus, recordSteeringRequest, steeringStatus, terminalSteeringNoticeState, updateSteeringTarget } from "./steering.ts";
|
|
102
101
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
103
|
-
import { PROMPT_REDACTED, detectSubagentError, extractTextFromContent, extractToolArgsPreview, getFinalOutput, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.ts";
|
|
104
|
-
import { evaluateCompletionMutationGuard, validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
102
|
+
import { PROMPT_REDACTED, detectSubagentError, extractTextFromContent, extractToolArgsPreview, formatEmptyTerminalAssistantResponseError, getFinalOutput, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.ts";
|
|
103
|
+
import { evaluateCompletionMutationGuard, expectsImplementationMutation, hasMutationToolCapability, validateImplementationToolContract } from "../shared/completion-guard.ts";
|
|
104
|
+
import { planCompletionEvidence, projectSettlementDiagnostic } from "../shared/completion-evidence.ts";
|
|
105
|
+
import { planAbortRecovery } from "../shared/abort-recovery.ts";
|
|
105
106
|
import {
|
|
106
107
|
createMutatingFailureState,
|
|
107
108
|
didMutatingToolFail,
|
|
@@ -124,7 +125,7 @@ import {
|
|
|
124
125
|
formatWorktreeTaskCwdConflict,
|
|
125
126
|
type WorktreeSetup,
|
|
126
127
|
} from "../shared/worktree.ts";
|
|
127
|
-
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
128
|
+
import { findModelInfo, resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
128
129
|
import { assertThinkingWithinCeiling, decodeThinkingCeiling, SUBAGENT_THINKING_CEILING_ENV } from "../../shared/thinking-ceiling.ts";
|
|
129
130
|
import { launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
130
131
|
import { writeInitialProgressFile } from "../../shared/settings.ts";
|
|
@@ -135,7 +136,6 @@ import { waitForImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
|
135
136
|
import { normalizeExtensionBindings } from "../shared/extension-bindings.ts";
|
|
136
137
|
import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests, statusStepDescription } from "./chain-append.ts";
|
|
137
138
|
import { asyncStatusChildIdentity } from "../shared/child-identity.ts";
|
|
138
|
-
import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, turnBudgetDecision, turnBudgetDeferredNote, turnBudgetDeferredState, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.ts";
|
|
139
139
|
import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
|
|
140
140
|
import { effectiveToolTimeoutMs, formatToolTimeoutMessage, toolTimeoutCallKey } from "../shared/tool-timeout.ts";
|
|
141
141
|
import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.ts";
|
|
@@ -197,7 +197,6 @@ interface SubagentRunConfig {
|
|
|
197
197
|
deadlineAt?: number;
|
|
198
198
|
/** Resolved configured hard per-tool-call timeout (ms); fast tools still have a default when undefined. */
|
|
199
199
|
toolTimeoutMs?: number;
|
|
200
|
-
turnBudget?: ResolvedTurnBudget;
|
|
201
200
|
toolBudget?: ResolvedToolBudget;
|
|
202
201
|
usageBudget?: UsageBudgetConfig;
|
|
203
202
|
revivalLease?: SessionLeaseRequest;
|
|
@@ -213,10 +212,13 @@ interface SubagentRunConfig {
|
|
|
213
212
|
launchBarrierToken?: string;
|
|
214
213
|
parentWorkflowRunId?: string;
|
|
215
214
|
workflowKey?: string;
|
|
215
|
+
lane?: WorkflowLaneMetadata;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
interface StepResult {
|
|
219
219
|
agent: string;
|
|
220
|
+
/** Human-readable display name for the child session, when derived at launch. */
|
|
221
|
+
sessionName?: string;
|
|
220
222
|
context?: "fresh" | "fork";
|
|
221
223
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
222
224
|
capabilityAudit?: import("../shared/capability-ceiling.ts").SubagentCapabilityAudit;
|
|
@@ -237,9 +239,6 @@ interface StepResult {
|
|
|
237
239
|
stopped?: boolean;
|
|
238
240
|
processSignal?: string | null;
|
|
239
241
|
timeoutRecovery?: import("../../shared/types.ts").TimeoutRecoverySummary;
|
|
240
|
-
turnBudget?: TurnBudgetState;
|
|
241
|
-
turnBudgetExceeded?: boolean;
|
|
242
|
-
wrapUpRequested?: boolean;
|
|
243
242
|
toolBudget?: ToolBudgetState;
|
|
244
243
|
toolBudgetBlocked?: boolean;
|
|
245
244
|
sessionFile?: string;
|
|
@@ -427,6 +426,23 @@ function costSummaryFromAttempts(attempts: ModelAttempt[] | undefined): CostSumm
|
|
|
427
426
|
: undefined;
|
|
428
427
|
}
|
|
429
428
|
|
|
429
|
+
function usageFromAttempts(attempts: ModelAttempt[] | undefined): Usage | undefined {
|
|
430
|
+
if (!attempts || attempts.length === 0) return undefined;
|
|
431
|
+
const usage = emptyUsage();
|
|
432
|
+
for (const attempt of attempts) {
|
|
433
|
+
if (!attempt.usage) continue;
|
|
434
|
+
usage.input += attempt.usage.input;
|
|
435
|
+
usage.output += attempt.usage.output;
|
|
436
|
+
usage.cacheRead += attempt.usage.cacheRead;
|
|
437
|
+
usage.cacheWrite += attempt.usage.cacheWrite;
|
|
438
|
+
usage.cost += attempt.usage.cost;
|
|
439
|
+
usage.turns += attempt.usage.turns;
|
|
440
|
+
}
|
|
441
|
+
return usage.input !== 0 || usage.output !== 0 || usage.cacheRead !== 0 || usage.cacheWrite !== 0 || usage.cost !== 0 || usage.turns !== 0
|
|
442
|
+
? usage
|
|
443
|
+
: undefined;
|
|
444
|
+
}
|
|
445
|
+
|
|
430
446
|
function appendRecentStepOutput(step: RunnerStatusStep, lines: string[]): void {
|
|
431
447
|
const nonEmpty = lines.filter((line) => line.trim());
|
|
432
448
|
if (nonEmpty.length === 0) return;
|
|
@@ -535,14 +551,12 @@ interface RunPiStreamingResult {
|
|
|
535
551
|
interrupted?: boolean;
|
|
536
552
|
timedOut?: boolean;
|
|
537
553
|
stopped?: boolean;
|
|
538
|
-
turnBudget?: TurnBudgetState;
|
|
539
|
-
turnBudgetExceeded?: boolean;
|
|
540
|
-
wrapUpRequested?: boolean;
|
|
541
554
|
toolBudget?: ToolBudgetState;
|
|
542
555
|
toolBudgetBlocked?: boolean;
|
|
543
556
|
observedMutationAttempt?: boolean;
|
|
544
557
|
structuredOutputToolInvoked?: boolean;
|
|
545
558
|
structuredOutputMessageStartIndex?: number;
|
|
559
|
+
structuredOutput?: unknown;
|
|
546
560
|
watchdog?: ChildWatchdogStateSnapshot;
|
|
547
561
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
|
|
548
562
|
processInstanceId: string;
|
|
@@ -553,24 +567,42 @@ interface RunPiStreamingResult {
|
|
|
553
567
|
currentToolArgs?: string;
|
|
554
568
|
currentPath?: string;
|
|
555
569
|
afterCompactionSettlement?: boolean;
|
|
570
|
+
abortRecoveryDiagnostic?: string;
|
|
571
|
+
effects?: import("../../shared/types.ts").EffectsProjection;
|
|
556
572
|
}
|
|
557
573
|
|
|
558
574
|
const MAX_CHILD_FAILURE_DIAGNOSTIC_CHARS = 8_192;
|
|
559
575
|
|
|
576
|
+
function formatRequiredOutputError(requiredOutput: {
|
|
577
|
+
kind: "file-only" | "structured";
|
|
578
|
+
path: string;
|
|
579
|
+
missing: boolean;
|
|
580
|
+
} | undefined): string | undefined {
|
|
581
|
+
if (!requiredOutput?.missing) return undefined;
|
|
582
|
+
return `Required ${requiredOutput.kind} output was not produced: ${requiredOutput.path.slice(0, 2_048)}`;
|
|
583
|
+
}
|
|
584
|
+
|
|
560
585
|
function formatChildFailureDiagnostic(input: {
|
|
561
586
|
error: string | undefined;
|
|
562
587
|
afterCompactionSettlement?: boolean;
|
|
563
|
-
|
|
588
|
+
abortRecoveryDiagnostic?: string;
|
|
589
|
+
requiredOutput?: {
|
|
590
|
+
kind: "file-only" | "structured";
|
|
591
|
+
path: string;
|
|
592
|
+
missing: boolean;
|
|
593
|
+
};
|
|
564
594
|
}): string | undefined {
|
|
565
|
-
|
|
595
|
+
const missingOutput = formatRequiredOutputError(input.requiredOutput);
|
|
566
596
|
const notes = [
|
|
597
|
+
input.abortRecoveryDiagnostic,
|
|
567
598
|
input.afterCompactionSettlement ? "Child failure followed session compaction and agent settlement." : undefined,
|
|
568
|
-
input.
|
|
599
|
+
missingOutput && input.error !== missingOutput ? missingOutput : undefined,
|
|
569
600
|
].filter((note): note is string => Boolean(note));
|
|
570
601
|
if (notes.length === 0) return input.error;
|
|
571
602
|
const context = notes.join("\n");
|
|
572
603
|
const errorLimit = MAX_CHILD_FAILURE_DIAGNOSTIC_CHARS - (context ? context.length + 1 : 0);
|
|
573
|
-
|
|
604
|
+
const baseError = input.error || "Subagent failed.";
|
|
605
|
+
return `${baseError.slice(0, Math.max(0, errorLimit))}${context ? `\n${context}` : ""}`;
|
|
574
606
|
}
|
|
575
607
|
|
|
576
608
|
function runPiStreaming(
|
|
@@ -589,13 +621,13 @@ function runPiStreaming(
|
|
|
589
621
|
timeoutMessage?: string,
|
|
590
622
|
registerStop?: (stop: (() => void) | undefined) => void,
|
|
591
623
|
stopMessage?: string,
|
|
592
|
-
registerTurnBudgetAbort?: (abort: ((message: string, state?: TurnBudgetState) => void) | undefined) => void,
|
|
593
624
|
onWriterProcess?: (writer: { state: "none" | "spawning" } | { state: "running"; pid: number }) => void,
|
|
594
625
|
toolTimeoutMs?: number,
|
|
595
626
|
runDeadlineAt?: number,
|
|
596
627
|
orcaProgressTab?: OrcaProgressTab,
|
|
597
628
|
expectedModelForVerification?: string,
|
|
598
629
|
modelVerificationRegistry?: Array<{ provider: string; id: string; fullId: string }>,
|
|
630
|
+
mutationTools?: readonly string[],
|
|
599
631
|
): Promise<RunPiStreamingResult> {
|
|
600
632
|
return new Promise((resolve) => {
|
|
601
633
|
const startedAt = Date.now();
|
|
@@ -635,9 +667,6 @@ function runPiStreaming(
|
|
|
635
667
|
let interrupted = false;
|
|
636
668
|
let timedOut = false;
|
|
637
669
|
let stopped = false;
|
|
638
|
-
let turnBudgetExceeded = false;
|
|
639
|
-
let turnBudgetMessage: string | undefined;
|
|
640
|
-
let turnBudget: TurnBudgetState | undefined;
|
|
641
670
|
let observedMutationAttempt = false;
|
|
642
671
|
let structuredOutputToolInvoked = false;
|
|
643
672
|
let structuredOutputMessageStartIndex: number | undefined;
|
|
@@ -740,8 +769,19 @@ function runPiStreaming(
|
|
|
740
769
|
appendChildEvent(event as unknown as Record<string, unknown>);
|
|
741
770
|
transcriptWriter?.writeChildEvent(event);
|
|
742
771
|
if (event.type === "compaction_start") compactionStartedReceived = true;
|
|
772
|
+
if (event.type === "compaction_end" && event.willRetry === true) {
|
|
773
|
+
compactionStartedReceived = false;
|
|
774
|
+
afterCompactionSettlement = false;
|
|
775
|
+
}
|
|
776
|
+
if (event.type === "agent_start" || event.type === "auto_retry_start") {
|
|
777
|
+
compactionStartedReceived = false;
|
|
778
|
+
afterCompactionSettlement = false;
|
|
779
|
+
}
|
|
743
780
|
const lifecycleAction = projectChildLifecycle(event, false, childLifecycleState);
|
|
744
|
-
if (event.type === "agent_settled" && lifecycleAction === "start-drain")
|
|
781
|
+
if (event.type === "agent_settled" && lifecycleAction === "start-drain") {
|
|
782
|
+
agentSettledReceived = true;
|
|
783
|
+
afterCompactionSettlement = compactionStartedReceived;
|
|
784
|
+
}
|
|
745
785
|
applyChildLifecycle(lifecycleAction);
|
|
746
786
|
|
|
747
787
|
if (isChildWatchdogStatusEvent(event)) {
|
|
@@ -791,7 +831,7 @@ function runPiStreaming(
|
|
|
791
831
|
structuredOutputToolInvoked = true;
|
|
792
832
|
structuredOutputMessageStartIndex = messages.length;
|
|
793
833
|
}
|
|
794
|
-
observedMutationAttempt = observedMutationAttempt || isMutatingTool(event.toolName, event.args);
|
|
834
|
+
observedMutationAttempt = observedMutationAttempt || isMutatingTool(event.toolName, event.args, mutationTools);
|
|
795
835
|
const toolArgs = extractToolArgsPreview(event.args ?? {});
|
|
796
836
|
writeOutputLine(toolArgs ? `${event.toolName}: ${toolArgs}` : event.toolName);
|
|
797
837
|
return;
|
|
@@ -849,11 +889,10 @@ function runPiStreaming(
|
|
|
849
889
|
let cleanTerminalAssistantStopReceived = false;
|
|
850
890
|
let agentSettledReceived = false;
|
|
851
891
|
let compactionStartedReceived = false;
|
|
892
|
+
let afterCompactionSettlement = false;
|
|
852
893
|
let finalDrainTimer: NodeJS.Timeout | undefined;
|
|
853
894
|
let finalHardKillTimer: NodeJS.Timeout | undefined;
|
|
854
895
|
let watchdogTailTimer: NodeJS.Timeout | undefined;
|
|
855
|
-
let turnBudgetTerminationTimer: NodeJS.Timeout | undefined;
|
|
856
|
-
let turnBudgetHardKillTimer: NodeJS.Timeout | undefined;
|
|
857
896
|
let protocolHardKillTimer: NodeJS.Timeout | undefined;
|
|
858
897
|
let protocolError: ProtocolOutputLimit | undefined;
|
|
859
898
|
let settled = false;
|
|
@@ -974,23 +1013,6 @@ function runPiStreaming(
|
|
|
974
1013
|
if (processTreeController) void processTreeController.terminate();
|
|
975
1014
|
else trySignalChild(child, "SIGTERM");
|
|
976
1015
|
});
|
|
977
|
-
registerTurnBudgetAbort?.((message, state) => {
|
|
978
|
-
if (settled || timedOut || stopped || turnBudgetExceeded) return;
|
|
979
|
-
turnBudgetExceeded = true;
|
|
980
|
-
turnBudgetMessage = message;
|
|
981
|
-
turnBudget = state;
|
|
982
|
-
interrupted = false;
|
|
983
|
-
error = message;
|
|
984
|
-
trySignalChild(child, "SIGINT");
|
|
985
|
-
turnBudgetTerminationTimer = setTimeout(() => {
|
|
986
|
-
if (!settled && !timedOut && !stopped) trySignalChild(child, "SIGTERM");
|
|
987
|
-
}, 1000);
|
|
988
|
-
turnBudgetTerminationTimer.unref?.();
|
|
989
|
-
turnBudgetHardKillTimer = setTimeout(() => {
|
|
990
|
-
if (!settled && !timedOut && !stopped) trySignalChild(child, "SIGKILL");
|
|
991
|
-
}, 4000);
|
|
992
|
-
turnBudgetHardKillTimer.unref?.();
|
|
993
|
-
});
|
|
994
1016
|
const clearDrainTimers = () => {
|
|
995
1017
|
clearAllToolTimeouts();
|
|
996
1018
|
if (finalDrainTimer) {
|
|
@@ -1002,14 +1024,6 @@ function runPiStreaming(
|
|
|
1002
1024
|
finalHardKillTimer = undefined;
|
|
1003
1025
|
}
|
|
1004
1026
|
clearWatchdogTailTimer();
|
|
1005
|
-
if (turnBudgetTerminationTimer) {
|
|
1006
|
-
clearTimeout(turnBudgetTerminationTimer);
|
|
1007
|
-
turnBudgetTerminationTimer = undefined;
|
|
1008
|
-
}
|
|
1009
|
-
if (turnBudgetHardKillTimer) {
|
|
1010
|
-
clearTimeout(turnBudgetHardKillTimer);
|
|
1011
|
-
turnBudgetHardKillTimer = undefined;
|
|
1012
|
-
}
|
|
1013
1027
|
if (protocolHardKillTimer) {
|
|
1014
1028
|
clearTimeout(protocolHardKillTimer);
|
|
1015
1029
|
protocolHardKillTimer = undefined;
|
|
@@ -1077,7 +1091,6 @@ function runPiStreaming(
|
|
|
1077
1091
|
registerInterrupt?.(undefined);
|
|
1078
1092
|
registerTimeout?.(undefined);
|
|
1079
1093
|
registerStop?.(undefined);
|
|
1080
|
-
registerTurnBudgetAbort?.(undefined);
|
|
1081
1094
|
clearDrainTimers();
|
|
1082
1095
|
clearStdioGuard();
|
|
1083
1096
|
stdoutReader.end();
|
|
@@ -1087,32 +1100,32 @@ function runPiStreaming(
|
|
|
1087
1100
|
const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
|
|
1088
1101
|
const finalError = error ?? assistantError;
|
|
1089
1102
|
const forcedDrainAfterFinalSuccess = Boolean(forcedTerminationSignal || signal) && (cleanTerminalAssistantStopReceived || agentSettledReceived) && !finalError;
|
|
1103
|
+
const forcedDrainAfterEmptyTerminal = forcedDrainAfterFinalSuccess && hasEmptyTerminalAssistantResponse(messages);
|
|
1104
|
+
const forcedDrainError = forcedDrainAfterEmptyTerminal && stderr.trim()
|
|
1105
|
+
? stderr.trim()
|
|
1106
|
+
: undefined;
|
|
1090
1107
|
const signalError = isUnexplainedProcessSignal({
|
|
1091
1108
|
processSignal: signal,
|
|
1092
1109
|
interrupted,
|
|
1093
1110
|
timedOut,
|
|
1094
1111
|
stopped,
|
|
1095
|
-
|
|
1096
|
-
forcedDrainAfterFinalSuccess,
|
|
1112
|
+
forcedDrainAfterFinalSuccess: forcedDrainAfterFinalSuccess && !forcedDrainAfterEmptyTerminal,
|
|
1097
1113
|
}) ? formatProcessSignalError(signal!) : undefined;
|
|
1098
1114
|
resolve(omitUndefinedProperties({
|
|
1099
1115
|
stderr,
|
|
1100
|
-
exitCode: timedOut || stopped ? 1 :
|
|
1116
|
+
exitCode: timedOut || stopped ? 1 : interrupted || (forcedDrainAfterFinalSuccess && !forcedDrainAfterEmptyTerminal) ? 0 : forcedTerminationSignal || signal ? (exitCode ?? 1) : exitCode,
|
|
1101
1117
|
messages,
|
|
1102
1118
|
usage,
|
|
1103
1119
|
toolCount,
|
|
1104
1120
|
durationMs: Date.now() - startedAt,
|
|
1105
1121
|
model,
|
|
1106
|
-
error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") :
|
|
1122
|
+
error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : interrupted || (forcedDrainAfterFinalSuccess && !forcedDrainAfterEmptyTerminal) ? undefined : finalError ?? forcedDrainError ?? signalError,
|
|
1107
1123
|
protocolError,
|
|
1108
1124
|
finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput,
|
|
1109
1125
|
outputState: finalOutput.trim() ? "present" : "absent",
|
|
1110
1126
|
interrupted,
|
|
1111
1127
|
timedOut,
|
|
1112
1128
|
stopped,
|
|
1113
|
-
turnBudget,
|
|
1114
|
-
turnBudgetExceeded,
|
|
1115
|
-
wrapUpRequested: turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined,
|
|
1116
1129
|
observedMutationAttempt,
|
|
1117
1130
|
structuredOutputToolInvoked,
|
|
1118
1131
|
structuredOutputMessageStartIndex,
|
|
@@ -1124,7 +1137,7 @@ function runPiStreaming(
|
|
|
1124
1137
|
currentTool,
|
|
1125
1138
|
currentToolArgs,
|
|
1126
1139
|
currentPath,
|
|
1127
|
-
afterCompactionSettlement:
|
|
1140
|
+
afterCompactionSettlement: afterCompactionSettlement || undefined,
|
|
1128
1141
|
}));
|
|
1129
1142
|
});
|
|
1130
1143
|
|
|
@@ -1138,7 +1151,6 @@ function runPiStreaming(
|
|
|
1138
1151
|
registerInterrupt?.(undefined);
|
|
1139
1152
|
registerTimeout?.(undefined);
|
|
1140
1153
|
registerStop?.(undefined);
|
|
1141
|
-
registerTurnBudgetAbort?.(undefined);
|
|
1142
1154
|
clearDrainTimers();
|
|
1143
1155
|
clearStdioGuard();
|
|
1144
1156
|
stdoutReader.end();
|
|
@@ -1147,7 +1159,7 @@ function runPiStreaming(
|
|
|
1147
1159
|
const stderr = stderrTail.text();
|
|
1148
1160
|
const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
|
|
1149
1161
|
const spawnErrorMessage = spawnError instanceof Error ? spawnError.message : String(spawnError);
|
|
1150
|
-
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.") :
|
|
1162
|
+
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.") : 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, observedMutationAttempt, structuredOutputToolInvoked, structuredOutputMessageStartIndex, watchdog: childWatchdogState, processInstanceId, processTree: { state: "unknown", reason: "verification-failed", diagnostic: spawnErrorMessage } }));
|
|
1151
1163
|
});
|
|
1152
1164
|
});
|
|
1153
1165
|
}
|
|
@@ -1282,7 +1294,6 @@ interface SingleStepContext {
|
|
|
1282
1294
|
registerInterrupt?: (interrupt: (() => void) | undefined) => void;
|
|
1283
1295
|
registerTimeout?: (interrupt: (() => void) | undefined) => void;
|
|
1284
1296
|
registerStop?: (stop: (() => void) | undefined) => void;
|
|
1285
|
-
registerTurnBudgetAbort?: (abort: ((message: string, state?: TurnBudgetState) => void) | undefined) => void;
|
|
1286
1297
|
timeoutSignal?: AbortSignal;
|
|
1287
1298
|
stopSignal?: AbortSignal;
|
|
1288
1299
|
timeoutMessage?: string;
|
|
@@ -1291,18 +1302,18 @@ interface SingleStepContext {
|
|
|
1291
1302
|
toolTimeoutMs?: number;
|
|
1292
1303
|
/** Effective step deadline (Date.now() + effective timeout) when a run budget exists. */
|
|
1293
1304
|
deadlineAt?: number;
|
|
1294
|
-
turnBudget?: ResolvedTurnBudget;
|
|
1295
1305
|
childIntercomTarget?: string;
|
|
1296
1306
|
orchestratorIntercomTarget?: string;
|
|
1297
1307
|
nestedRoute?: NestedRouteInfo;
|
|
1298
1308
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1299
1309
|
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
1300
|
-
onAttemptStart?: (attempt: { model?: string; thinking?: string }) => void;
|
|
1310
|
+
onAttemptStart?: (attempt: { model?: string; thinking?: string; contextLimit?: number }) => void;
|
|
1301
1311
|
onChildEvent?: (event: ChildEvent) => void;
|
|
1302
1312
|
onWriterProcess?: (writer: { state: "none" | "spawning" } | { state: "running"; pid: number }) => void;
|
|
1303
1313
|
onExternalProcess?: (process: ExternalProcessStatus) => void;
|
|
1304
1314
|
onExternalJob?: (status: ExternalJobStatus) => void;
|
|
1305
1315
|
skipAcceptance?: () => boolean;
|
|
1316
|
+
usageBudgetExhausted?: () => boolean;
|
|
1306
1317
|
/** False when sibling work in the same Git worktree could have caused the tracked diff. */
|
|
1307
1318
|
trackedMutationEvidenceForCompletionGuard?: boolean;
|
|
1308
1319
|
orcaProgressTab?: OrcaProgressTab;
|
|
@@ -1371,10 +1382,13 @@ async function runSingleStepInner(
|
|
|
1371
1382
|
modelAttempts: imported.modelAttempts,
|
|
1372
1383
|
contextOverflow: imported.contextOverflow,
|
|
1373
1384
|
totalCost: imported.totalCost,
|
|
1385
|
+
usage: imported.usage,
|
|
1374
1386
|
structuredOutput: timedOut || stopped ? undefined : imported.structuredOutput,
|
|
1375
1387
|
structuredOutputPath: timedOut || stopped ? undefined : imported.structuredOutputPath,
|
|
1376
1388
|
structuredOutputSchemaPath: timedOut || stopped ? undefined : imported.structuredOutputSchemaPath,
|
|
1377
1389
|
acceptance: timedOut || stopped ? undefined : imported.acceptance,
|
|
1390
|
+
execution: timedOut || stopped ? undefined : imported.execution,
|
|
1391
|
+
effects: timedOut || stopped ? undefined : imported.effects,
|
|
1378
1392
|
});
|
|
1379
1393
|
} finally {
|
|
1380
1394
|
ctx.registerTimeout?.(undefined);
|
|
@@ -1393,12 +1407,15 @@ async function runSingleStepInner(
|
|
|
1393
1407
|
if (!step.runner) {
|
|
1394
1408
|
resolvedTaskToolPlan = resolvePiLaunchToolPlan(omitUndefinedProperties({
|
|
1395
1409
|
tools: step.tools,
|
|
1410
|
+
allowNestedSubagents: step.allowNestedSubagents,
|
|
1396
1411
|
extensions: step.extensions,
|
|
1397
1412
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
1398
1413
|
fast: step.fast,
|
|
1399
1414
|
model: step.model,
|
|
1400
1415
|
modelCandidates: step.modelCandidates,
|
|
1401
1416
|
mcpDirectTools: step.mcpDirectTools,
|
|
1417
|
+
mcpConfig: step.mcpConfig,
|
|
1418
|
+
runtimeServerNames: step.runtimeServerNames,
|
|
1402
1419
|
cwd: step.cwd ?? ctx.cwd,
|
|
1403
1420
|
requireReadTool: Boolean(step.skills?.length),
|
|
1404
1421
|
structuredOutput: Boolean(effectiveStructuredOutput),
|
|
@@ -1429,6 +1446,9 @@ async function runSingleStepInner(
|
|
|
1429
1446
|
});
|
|
1430
1447
|
}
|
|
1431
1448
|
}
|
|
1449
|
+
// Derive from the pre-acceptance task so internal acceptance/recovery
|
|
1450
|
+
// instructions never leak into the display name.
|
|
1451
|
+
const childSessionName = step.sessionName ?? deriveChildSessionName({ agent: step.agent, task, label: step.label });
|
|
1432
1452
|
if (step.effectiveAcceptance) {
|
|
1433
1453
|
const acceptancePrompt = formatAcceptancePrompt(step.effectiveAcceptance, { reportOptional: isAgentContractV1(step.agentContract), structuredOutput: Boolean(step.structuredOutput?.acceptanceReportPath) });
|
|
1434
1454
|
if (acceptancePrompt) task = `${task}\n${acceptancePrompt}`;
|
|
@@ -1492,14 +1512,18 @@ async function runSingleStepInner(
|
|
|
1492
1512
|
}));
|
|
1493
1513
|
try { fs.writeFileSync(ctx.outputFile, external.output, "utf-8"); } catch { /* Observability output is best-effort. */ }
|
|
1494
1514
|
const resolvedOutput = step.outputPath && external.exitCode === 0
|
|
1495
|
-
? resolveSingleOutput(step.outputPath, external.output, outputSnapshot)
|
|
1515
|
+
? resolveSingleOutput(step.outputPath, external.output, outputSnapshot, step.outputClaimPath)
|
|
1496
1516
|
: { fullOutput: external.output };
|
|
1497
1517
|
const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
|
|
1518
|
+
const exitCode = resolvedOutput.fatalError ? 1 : external.exitCode;
|
|
1519
|
+
const error = resolvedOutput.fatalError && resolvedOutput.saveError
|
|
1520
|
+
? external.error ? `${external.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError
|
|
1521
|
+
: external.error;
|
|
1498
1522
|
const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
|
|
1499
1523
|
fullOutput: resolvedOutput.fullOutput,
|
|
1500
1524
|
outputPath: step.outputPath,
|
|
1501
1525
|
outputMode: step.outputMode,
|
|
1502
|
-
exitCode:
|
|
1526
|
+
exitCode: exitCode ?? 1,
|
|
1503
1527
|
savedPath: resolvedOutput.savedPath,
|
|
1504
1528
|
outputReference,
|
|
1505
1529
|
saveError: resolvedOutput.saveError,
|
|
@@ -1514,16 +1538,17 @@ async function runSingleStepInner(
|
|
|
1514
1538
|
: {};
|
|
1515
1539
|
return omitUndefinedProperties({
|
|
1516
1540
|
agent: step.agent,
|
|
1541
|
+
...(childSessionName ? { sessionName: childSessionName } : {}),
|
|
1517
1542
|
context: step.context,
|
|
1518
1543
|
output: finalizedOutput.displayOutput,
|
|
1519
1544
|
outputState: external.output.trim() ? "present" : "absent",
|
|
1520
|
-
exitCode
|
|
1521
|
-
error
|
|
1545
|
+
exitCode,
|
|
1546
|
+
error,
|
|
1522
1547
|
timedOut: external.timedOut,
|
|
1523
1548
|
stopped: external.stopped,
|
|
1524
1549
|
processSignal: external.processSignal,
|
|
1525
1550
|
artifactPaths,
|
|
1526
|
-
outputSaveError: artifactErrors.outputSaveError,
|
|
1551
|
+
outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined,
|
|
1527
1552
|
metadataSaveError: artifactErrors.metadataSaveError,
|
|
1528
1553
|
runner,
|
|
1529
1554
|
externalProcess: external.externalProcess,
|
|
@@ -1557,14 +1582,18 @@ async function runSingleStepInner(
|
|
|
1557
1582
|
}));
|
|
1558
1583
|
try { fs.writeFileSync(ctx.outputFile, external.output, "utf-8"); } catch { /* Observability output is best-effort. */ }
|
|
1559
1584
|
const resolvedOutput = step.outputPath && external.exitCode === 0
|
|
1560
|
-
? resolveSingleOutput(step.outputPath, external.output, outputSnapshot)
|
|
1585
|
+
? resolveSingleOutput(step.outputPath, external.output, outputSnapshot, step.outputClaimPath)
|
|
1561
1586
|
: { fullOutput: external.output };
|
|
1562
1587
|
const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
|
|
1588
|
+
const exitCode = resolvedOutput.fatalError ? 1 : external.exitCode;
|
|
1589
|
+
const error = resolvedOutput.fatalError && resolvedOutput.saveError
|
|
1590
|
+
? external.error ? `${external.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError
|
|
1591
|
+
: external.error;
|
|
1563
1592
|
const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
|
|
1564
1593
|
fullOutput: resolvedOutput.fullOutput,
|
|
1565
1594
|
outputPath: step.outputPath,
|
|
1566
1595
|
outputMode: step.outputMode,
|
|
1567
|
-
exitCode:
|
|
1596
|
+
exitCode: exitCode ?? 1,
|
|
1568
1597
|
savedPath: resolvedOutput.savedPath,
|
|
1569
1598
|
outputReference,
|
|
1570
1599
|
saveError: resolvedOutput.saveError,
|
|
@@ -1579,21 +1608,26 @@ async function runSingleStepInner(
|
|
|
1579
1608
|
: {};
|
|
1580
1609
|
return omitUndefinedProperties({
|
|
1581
1610
|
agent: step.agent,
|
|
1611
|
+
...(childSessionName ? { sessionName: childSessionName } : {}),
|
|
1582
1612
|
context: step.context,
|
|
1583
1613
|
output: finalizedOutput.displayOutput,
|
|
1584
1614
|
outputState: external.output.trim() ? "present" : "absent",
|
|
1585
|
-
exitCode
|
|
1586
|
-
error
|
|
1615
|
+
exitCode,
|
|
1616
|
+
error,
|
|
1587
1617
|
timedOut: external.timedOut,
|
|
1588
1618
|
stopped: external.stopped,
|
|
1589
1619
|
artifactPaths,
|
|
1590
|
-
outputSaveError: artifactErrors.outputSaveError,
|
|
1620
|
+
outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined,
|
|
1591
1621
|
metadataSaveError: artifactErrors.metadataSaveError,
|
|
1592
1622
|
runner,
|
|
1593
1623
|
externalJob: external.externalJob,
|
|
1594
1624
|
});
|
|
1595
1625
|
}
|
|
1596
1626
|
|
|
1627
|
+
const effectiveCwd = step.cwd ?? ctx.cwd;
|
|
1628
|
+
const cwdError = preflightLaunchCwd(step.requestedCwd ?? effectiveCwd, effectiveCwd);
|
|
1629
|
+
if (cwdError) return { agent: step.agent, output: cwdError, error: cwdError, exitCode: 1, context: step.context };
|
|
1630
|
+
|
|
1597
1631
|
const candidates = step.modelCandidates !== undefined
|
|
1598
1632
|
? step.modelCandidates.length > 0 ? step.modelCandidates : [undefined]
|
|
1599
1633
|
: step.model
|
|
@@ -1612,7 +1646,6 @@ async function runSingleStepInner(
|
|
|
1612
1646
|
let structuredAcceptanceReport: unknown;
|
|
1613
1647
|
let structuredAcceptanceReportError: string | undefined;
|
|
1614
1648
|
let completionGuardTriggeredFinal = false;
|
|
1615
|
-
let turnBudget = ctx.turnBudget ? initialTurnBudgetState(ctx.turnBudget) : undefined;
|
|
1616
1649
|
let toolBudget = step.toolBudget ? initialToolBudgetState(step.toolBudget) : undefined;
|
|
1617
1650
|
let toolBudgetBlocked = false;
|
|
1618
1651
|
let actualLaunchContractDigest = step.launchContractDigest;
|
|
@@ -1626,8 +1659,12 @@ async function runSingleStepInner(
|
|
|
1626
1659
|
let taskDeliveryOverride: SubagentTaskDelivery | undefined;
|
|
1627
1660
|
let contextOverflow = false;
|
|
1628
1661
|
let launchWarningsEmitted = false;
|
|
1662
|
+
let abortRecoveryAttempted = false;
|
|
1663
|
+
let nextAttemptTask = task;
|
|
1629
1664
|
modelAttemptsLoop: while (modelIndex < candidates.length) {
|
|
1630
1665
|
if (ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
|
|
1666
|
+
const recoveringAbort = abortRecoveryAttempted;
|
|
1667
|
+
const attemptTask = nextAttemptTask;
|
|
1631
1668
|
const candidate = candidates[modelIndex];
|
|
1632
1669
|
const expectedModelForVerification = candidate && !(step.skipPrimaryModelVerification && modelIndex === 0) ? candidate : undefined;
|
|
1633
1670
|
try {
|
|
@@ -1636,7 +1673,11 @@ async function runSingleStepInner(
|
|
|
1636
1673
|
const message = error instanceof Error ? error.message : String(error);
|
|
1637
1674
|
return omitUndefinedProperties({ agent: step.agent, output: message, error: message, exitCode: 1, context: step.context, thinkingCeiling: step.thinkingCeiling });
|
|
1638
1675
|
}
|
|
1639
|
-
ctx.onAttemptStart?.(omitUndefinedProperties({
|
|
1676
|
+
ctx.onAttemptStart?.(omitUndefinedProperties({
|
|
1677
|
+
model: candidate,
|
|
1678
|
+
thinking: resolveEffectiveThinking(candidate, step.thinking),
|
|
1679
|
+
contextLimit: findModelInfo(candidate, step.modelVerificationRegistry)?.contextWindow,
|
|
1680
|
+
}));
|
|
1640
1681
|
const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
|
|
1641
1682
|
if (effectiveStructuredOutput) {
|
|
1642
1683
|
try {
|
|
@@ -1658,27 +1699,32 @@ async function runSingleStepInner(
|
|
|
1658
1699
|
const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit, warnings } = buildPiArgs(omitUndefinedProperties({
|
|
1659
1700
|
parentSessionId: step.parentSessionId,
|
|
1660
1701
|
baseArgs: ["--mode", "json", "-p"],
|
|
1661
|
-
task,
|
|
1702
|
+
task: attemptTask,
|
|
1662
1703
|
taskDelivery: taskDeliveryOverride,
|
|
1663
1704
|
sessionEnabled,
|
|
1664
1705
|
sessionDir,
|
|
1665
1706
|
sessionFile: step.sessionFile,
|
|
1666
1707
|
model: candidate,
|
|
1667
1708
|
inheritProjectContext: step.inheritProjectContext,
|
|
1709
|
+
inheritGlobalContext: step.inheritGlobalContext,
|
|
1668
1710
|
inheritSkills: step.inheritSkills,
|
|
1669
1711
|
requireReadTool: Boolean(step.skills?.length),
|
|
1670
1712
|
tools: step.tools,
|
|
1713
|
+
allowNestedSubagents: step.allowNestedSubagents,
|
|
1671
1714
|
extensions: step.extensions,
|
|
1672
1715
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
1673
1716
|
fast: step.fast,
|
|
1674
1717
|
modelCandidates: step.modelCandidates,
|
|
1675
|
-
systemPrompt:
|
|
1718
|
+
systemPrompt: step.systemPrompt ?? "",
|
|
1676
1719
|
systemPromptMode: step.systemPromptMode,
|
|
1677
1720
|
mcpDirectTools: step.mcpDirectTools,
|
|
1721
|
+
mcpConfig: step.mcpConfig,
|
|
1722
|
+
runtimeServerNames: step.runtimeServerNames,
|
|
1678
1723
|
capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
|
|
1679
1724
|
cwd: step.cwd ?? ctx.cwd,
|
|
1680
1725
|
promptFileStem: step.agent,
|
|
1681
1726
|
intercomSessionName: ctx.childIntercomTarget,
|
|
1727
|
+
sessionName: childSessionName,
|
|
1682
1728
|
orchestratorIntercomTarget: ctx.orchestratorIntercomTarget,
|
|
1683
1729
|
runId: ctx.id,
|
|
1684
1730
|
childAgentName: step.agent,
|
|
@@ -1702,6 +1748,7 @@ async function runSingleStepInner(
|
|
|
1702
1748
|
: undefined,
|
|
1703
1749
|
childWatchdog,
|
|
1704
1750
|
waitToolEnabled: step.waitToolEnabled,
|
|
1751
|
+
waitToolDefaultTimeoutMs: step.waitToolDefaultTimeoutMs,
|
|
1705
1752
|
thinkingCeiling: step.thinkingCeiling,
|
|
1706
1753
|
extensionBindings,
|
|
1707
1754
|
}));
|
|
@@ -1712,12 +1759,15 @@ async function runSingleStepInner(
|
|
|
1712
1759
|
if (step.definitionDigest) {
|
|
1713
1760
|
const toolPlan = resolvedTaskToolPlan ?? resolvePiLaunchToolPlan(omitUndefinedProperties({
|
|
1714
1761
|
tools: step.tools,
|
|
1762
|
+
allowNestedSubagents: step.allowNestedSubagents,
|
|
1715
1763
|
extensions: step.extensions,
|
|
1716
1764
|
subagentOnlyExtensions: step.subagentOnlyExtensions,
|
|
1717
1765
|
fast: step.fast,
|
|
1718
1766
|
model: step.model,
|
|
1719
1767
|
modelCandidates: step.modelCandidates,
|
|
1720
1768
|
mcpDirectTools: step.mcpDirectTools,
|
|
1769
|
+
mcpConfig: step.mcpConfig,
|
|
1770
|
+
runtimeServerNames: step.runtimeServerNames,
|
|
1721
1771
|
cwd: step.cwd ?? ctx.cwd,
|
|
1722
1772
|
requireReadTool: Boolean(step.skills?.length),
|
|
1723
1773
|
structuredOutput: Boolean(effectiveStructuredOutput),
|
|
@@ -1734,9 +1784,10 @@ async function runSingleStepInner(
|
|
|
1734
1784
|
...(step.fast !== undefined ? { fast: step.fast } : {}),
|
|
1735
1785
|
...(resolveEffectiveThinking(candidate, step.thinking) ? { thinking: resolveEffectiveThinking(candidate, step.thinking) } : {}),
|
|
1736
1786
|
...(step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {}),
|
|
1737
|
-
systemPrompt:
|
|
1787
|
+
systemPrompt: step.systemPrompt ?? "",
|
|
1738
1788
|
systemPromptMode: step.systemPromptMode,
|
|
1739
1789
|
inheritProjectContext: step.inheritProjectContext,
|
|
1790
|
+
inheritGlobalContext: step.inheritGlobalContext,
|
|
1740
1791
|
inheritSkills: step.inheritSkills,
|
|
1741
1792
|
skills: step.skills,
|
|
1742
1793
|
tools: toolPlan.effectiveToolAllowlist,
|
|
@@ -1766,13 +1817,13 @@ async function runSingleStepInner(
|
|
|
1766
1817
|
ctx.timeoutMessage,
|
|
1767
1818
|
ctx.registerStop,
|
|
1768
1819
|
ctx.stopMessage,
|
|
1769
|
-
ctx.registerTurnBudgetAbort,
|
|
1770
1820
|
ctx.onWriterProcess,
|
|
1771
1821
|
ctx.toolTimeoutMs,
|
|
1772
1822
|
ctx.deadlineAt,
|
|
1773
1823
|
ctx.orcaProgressTab,
|
|
1774
1824
|
expectedModelForVerification,
|
|
1775
1825
|
step.modelVerificationRegistry,
|
|
1826
|
+
step.mutationTools,
|
|
1776
1827
|
);
|
|
1777
1828
|
if (run.processCloseObservedAt !== undefined) {
|
|
1778
1829
|
writerProcesses.push({
|
|
@@ -1785,25 +1836,6 @@ async function runSingleStepInner(
|
|
|
1785
1836
|
processTree: run.processTree,
|
|
1786
1837
|
});
|
|
1787
1838
|
}
|
|
1788
|
-
if (run.turnBudget) turnBudget = run.turnBudget;
|
|
1789
|
-
else if (ctx.turnBudget) {
|
|
1790
|
-
const assistantMessages = run.messages.filter((message) => message.role === "assistant");
|
|
1791
|
-
const turnCount = assistantMessages.length;
|
|
1792
|
-
const lastAssistantMessage = assistantMessages.at(-1);
|
|
1793
|
-
if (turnCount > 0 && turnCount < ctx.turnBudget.maxTurns) {
|
|
1794
|
-
turnBudget = { ...ctx.turnBudget, outcome: "within-budget", turnCount };
|
|
1795
|
-
} else if (turnCount >= ctx.turnBudget.maxTurns) {
|
|
1796
|
-
const decision = turnBudgetDecision(
|
|
1797
|
-
ctx.turnBudget,
|
|
1798
|
-
turnCount,
|
|
1799
|
-
lastAssistantMessage ? isTerminalAssistantStop(lastAssistantMessage) : false,
|
|
1800
|
-
lastAssistantMessage ? assistantStartsToolCall(lastAssistantMessage) : false,
|
|
1801
|
-
);
|
|
1802
|
-
turnBudget = decision === "defer"
|
|
1803
|
-
? turnBudgetDeferredState(ctx.turnBudget, turnCount)
|
|
1804
|
-
: turnBudgetState(ctx.turnBudget, turnCount, decision === "abort");
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
1839
|
const toolAvailabilityError = run.exitCode === 0 && !run.error
|
|
1808
1840
|
? readChildToolDiagnosticError(toolDiagnosticPath)
|
|
1809
1841
|
: undefined;
|
|
@@ -1814,7 +1846,6 @@ async function runSingleStepInner(
|
|
|
1814
1846
|
&& !run.interrupted
|
|
1815
1847
|
&& !run.timedOut
|
|
1816
1848
|
&& !run.stopped
|
|
1817
|
-
&& !run.turnBudgetExceeded
|
|
1818
1849
|
&& !run.protocolError
|
|
1819
1850
|
&& !toolAvailabilityError
|
|
1820
1851
|
? formatMidToolExitError({
|
|
@@ -1852,17 +1883,21 @@ async function runSingleStepInner(
|
|
|
1852
1883
|
const hiddenError = run.exitCode === 0 && !run.error && !toolAvailabilityError && !structuredError && !midToolExitError
|
|
1853
1884
|
? detectSubagentError(errorMessages)
|
|
1854
1885
|
: null;
|
|
1886
|
+
const terminalEmptyAfterUsefulWork = !validatedStructuredOutput
|
|
1887
|
+
&& hasEmptyTerminalAssistantResponse(run.messages)
|
|
1888
|
+
&& (run.toolCount > 0 || Boolean(run.finalOutput.trim()));
|
|
1855
1889
|
const emptyOutputError = run.exitCode === 0
|
|
1856
1890
|
&& !run.error
|
|
1857
1891
|
&& !toolAvailabilityError
|
|
1858
1892
|
&& !structuredError
|
|
1859
|
-
&& !run.finalOutput.trim()
|
|
1860
1893
|
&& !validatedStructuredOutput
|
|
1894
|
+
&& (!run.finalOutput.trim() || terminalEmptyAfterUsefulWork)
|
|
1861
1895
|
&& (!hiddenError?.hasError || hasEmptyTerminalAssistantResponse(run.messages))
|
|
1862
|
-
?
|
|
1896
|
+
? formatEmptyTerminalAssistantResponseError(run.messages)
|
|
1863
1897
|
: undefined;
|
|
1864
1898
|
const completionGuardEnabled = isAgentContractV1(step.agentContract) ? step.completionGuard === true : step.completionGuard !== false;
|
|
1865
1899
|
const completionToolPlan = resolvedTaskToolPlan;
|
|
1900
|
+
const completionTools = completionToolPlan ? (completionToolPlan.explicitToolAllowlist ? completionToolPlan.effectiveToolAllowlist : undefined) : step.tools;
|
|
1866
1901
|
const mutationEvidence = collectTrackedMutationEvidence(mutationSnapshot, step.cwd ?? ctx.cwd);
|
|
1867
1902
|
finalMutationEvidence = mutationEvidence;
|
|
1868
1903
|
const completionMutationEvidence = ctx.trackedMutationEvidenceForCompletionGuard === false ? undefined : mutationEvidence;
|
|
@@ -1871,29 +1906,32 @@ async function runSingleStepInner(
|
|
|
1871
1906
|
agent: step.agent,
|
|
1872
1907
|
task: taskForCompletionGuard,
|
|
1873
1908
|
messages: run.messages,
|
|
1874
|
-
tools:
|
|
1909
|
+
tools: completionTools,
|
|
1875
1910
|
mcpDirectTools: completionToolPlan?.effectiveMcpTools ?? step.mcpDirectTools,
|
|
1911
|
+
mutationTools: step.mutationTools,
|
|
1876
1912
|
toolAvailabilityError,
|
|
1877
1913
|
mutationEvidence: completionMutationEvidence,
|
|
1878
1914
|
}))
|
|
1879
1915
|
: undefined;
|
|
1880
1916
|
const mutationAttemptObserved = run.observedMutationAttempt === true || completionMutationEvidence?.attemptedMutation === true;
|
|
1881
|
-
const
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
:
|
|
1893
|
-
|
|
1894
|
-
|
|
1917
|
+
const completionEvidence = planCompletionEvidence({
|
|
1918
|
+
guard: completionGuard,
|
|
1919
|
+
completionGuardEnabled,
|
|
1920
|
+
mutationCapable: hasMutationToolCapability(completionTools, completionToolPlan?.effectiveMcpTools ?? step.mcpDirectTools),
|
|
1921
|
+
implementationMutationExpected: expectsImplementationMutation(step.agent, taskForCompletionGuard),
|
|
1922
|
+
mutationAttemptObserved,
|
|
1923
|
+
mutationEvidence: completionMutationEvidence,
|
|
1924
|
+
agentContractV1: isAgentContractV1(step.agentContract),
|
|
1925
|
+
});
|
|
1926
|
+
const finalOutputHasPersistableFileContent = run.exitCode === 0 && !run.error && !emptyOutputError && Boolean(stripAcceptanceReport(run.finalOutput).trim());
|
|
1927
|
+
const requiredOutput = step.outputMode === "file-only" && step.outputPath
|
|
1928
|
+
? { kind: "file-only" as const, path: step.outputPath, missing: !fs.existsSync(step.outputPath) && !finalOutputHasPersistableFileContent }
|
|
1929
|
+
: effectiveStructuredOutput
|
|
1930
|
+
? { kind: "structured" as const, path: effectiveStructuredOutput.outputPath, missing: !fs.existsSync(effectiveStructuredOutput.outputPath) }
|
|
1895
1931
|
: undefined;
|
|
1896
|
-
const
|
|
1932
|
+
const missingRequiredOutputError = formatRequiredOutputError(requiredOutput);
|
|
1933
|
+
const missingRequiredOutputAfterMutation = Boolean(missingRequiredOutputError) && (mutationAttemptObserved || Boolean(mutationEvidence.changedFiles.length));
|
|
1934
|
+
const effectiveExitCode = toolAvailabilityError || completionEvidence.legacyFailureError || midToolExitError || structuredError || emptyOutputError || missingRequiredOutputError
|
|
1897
1935
|
? 1
|
|
1898
1936
|
: hiddenError?.hasError
|
|
1899
1937
|
? (hiddenError.exitCode ?? 1)
|
|
@@ -1905,19 +1943,23 @@ async function runSingleStepInner(
|
|
|
1905
1943
|
interrupted: run.interrupted,
|
|
1906
1944
|
timedOut: run.timedOut,
|
|
1907
1945
|
stopped: run.stopped,
|
|
1908
|
-
turnBudgetExceeded: run.turnBudgetExceeded,
|
|
1909
1946
|
})) ? formatProcessSignalError(run.processSignal!) : undefined;
|
|
1947
|
+
const underlyingError = toolAvailabilityError
|
|
1948
|
+
?? midToolExitError
|
|
1949
|
+
?? structuredError
|
|
1950
|
+
?? run.error
|
|
1951
|
+
?? signalError
|
|
1952
|
+
?? (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined)
|
|
1953
|
+
?? ((emptyOutputError || missingRequiredOutputError) && run.stderr.trim() ? run.stderr.trim() : undefined)
|
|
1954
|
+
?? emptyOutputError
|
|
1955
|
+
?? (missingRequiredOutputAfterMutation ? missingRequiredOutputError : undefined)
|
|
1956
|
+
?? (hiddenError?.hasError
|
|
1957
|
+
? hiddenError.details
|
|
1958
|
+
? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
|
|
1959
|
+
: `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
|
|
1960
|
+
: undefined);
|
|
1910
1961
|
const error = formatSubagentExtensionConflictError(
|
|
1911
|
-
|
|
1912
|
-
?? completionGuardError
|
|
1913
|
-
?? midToolExitError
|
|
1914
|
-
?? structuredError
|
|
1915
|
-
?? emptyOutputError
|
|
1916
|
-
?? (hiddenError?.hasError
|
|
1917
|
-
? hiddenError.details
|
|
1918
|
-
? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
|
|
1919
|
-
: `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
|
|
1920
|
-
: run.error || signalError || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined)),
|
|
1962
|
+
underlyingError ?? missingRequiredOutputError ?? completionEvidence.legacyFailureError,
|
|
1921
1963
|
{
|
|
1922
1964
|
agent: step.agent,
|
|
1923
1965
|
ambientExtensionsEnabled: launchResolvedExtensions?.disableAmbientExtensions === false,
|
|
@@ -1931,8 +1973,8 @@ async function runSingleStepInner(
|
|
|
1931
1973
|
usage: run.usage,
|
|
1932
1974
|
});
|
|
1933
1975
|
modelAttempts.push(attempt);
|
|
1934
|
-
if (candidate && startupAttemptIndex === 0) attemptedModels.push(candidate);
|
|
1935
|
-
completionGuardTriggeredFinal =
|
|
1976
|
+
if (!recoveringAbort && candidate && startupAttemptIndex === 0) attemptedModels.push(candidate);
|
|
1977
|
+
completionGuardTriggeredFinal = completionEvidence.guardTriggered && !underlyingError && !missingRequiredOutputError;
|
|
1936
1978
|
finalOutputSnapshot = outputSnapshot;
|
|
1937
1979
|
if (step.toolBudget) {
|
|
1938
1980
|
const toolMessages = run.messages.filter((message) => message.role === "toolResult");
|
|
@@ -1940,10 +1982,48 @@ async function runSingleStepInner(
|
|
|
1940
1982
|
toolBudgetBlocked = Boolean(blockedMessage);
|
|
1941
1983
|
toolBudget = toolBudgetState(step.toolBudget, toolMessages.length, blockedMessage ? (blockedMessage as { toolName?: string }).toolName : undefined);
|
|
1942
1984
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1985
|
+
const settlementDiagnostic = projectSettlementDiagnostic(completionEvidence, {
|
|
1986
|
+
terminalFailed: effectiveExitCode !== 0,
|
|
1987
|
+
finalTextPresent: Boolean(stripAcceptanceReport(run.finalOutput).trim()),
|
|
1988
|
+
mutationObserved: mutationEvidence.attemptedMutation,
|
|
1989
|
+
requiredOutput,
|
|
1990
|
+
afterCompactionSettlement: run.afterCompactionSettlement === true,
|
|
1991
|
+
});
|
|
1992
|
+
const fileMutationEffect = completionEvidence.fileMutation ?? (missingRequiredOutputAfterMutation ? { status: "observed" as const, expected: completionEvidence.mutationExpected, attempted: true, evidence: mutationEvidence } : undefined);
|
|
1993
|
+
finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput, runtimeAcknowledgedExtensions, ...(step.agentContract ? { agentContract: step.agentContract } : {}), ...(fileMutationEffect || settlementDiagnostic ? { effects: { ...(fileMutationEffect ? { fileMutation: fileMutationEffect } : {}), ...(settlementDiagnostic ? { settlementDiagnostic } : {}) } } : {}) } as RunPiStreamingResult;
|
|
1994
|
+
const abortRecovery = !attempt.success ? planAbortRecovery({
|
|
1995
|
+
messages: run.messages,
|
|
1996
|
+
error,
|
|
1997
|
+
processSignal: run.processSignal,
|
|
1998
|
+
sessionAvailable: Boolean(step.sessionFile && fs.existsSync(step.sessionFile)),
|
|
1999
|
+
alreadyResumed: abortRecoveryAttempted,
|
|
2000
|
+
stopped: run.stopped || ctx.stopSignal?.aborted || ctx.skipAcceptance?.(),
|
|
2001
|
+
interrupted: run.interrupted,
|
|
2002
|
+
timedOut: run.timedOut || ctx.timeoutSignal?.aborted,
|
|
2003
|
+
toolBudgetExhausted: run.toolBudgetBlocked || toolBudgetBlocked,
|
|
2004
|
+
usageBudgetExhausted: ctx.usageBudgetExhausted?.(),
|
|
2005
|
+
structuredOutputFailed: Boolean(structuredError),
|
|
2006
|
+
acceptanceFailed: false,
|
|
2007
|
+
currentTool: run.currentTool,
|
|
2008
|
+
afterCompactionSettlement: run.afterCompactionSettlement,
|
|
2009
|
+
}) : undefined;
|
|
2010
|
+
if (abortRecovery?.action === "settle" && abortRecovery.diagnostic) {
|
|
2011
|
+
attempt.error = attempt.error
|
|
2012
|
+
? `${abortRecovery.diagnostic}\n${attempt.error.slice(0, 8_000)}`
|
|
2013
|
+
: abortRecovery.diagnostic;
|
|
2014
|
+
if (finalResult) finalResult.abortRecoveryDiagnostic = abortRecovery.diagnostic;
|
|
2015
|
+
}
|
|
1945
2016
|
if (run.stopped || run.timedOut || ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break modelAttemptsLoop;
|
|
1946
|
-
if (
|
|
2017
|
+
if (abortRecovery?.action === "settle" && abortRecovery.diagnostic) break modelAttemptsLoop;
|
|
2018
|
+
if (attempt.success) break modelAttemptsLoop;
|
|
2019
|
+
if (recoveringAbort) break modelAttemptsLoop;
|
|
2020
|
+
if (abortRecovery?.action === "resume") {
|
|
2021
|
+
abortRecoveryAttempted = true;
|
|
2022
|
+
nextAttemptTask = abortRecovery.prompt;
|
|
2023
|
+
attemptNotes.push("[abort-recovery] provider/transport abort after useful progress; resuming the retained child session once.");
|
|
2024
|
+
continue;
|
|
2025
|
+
}
|
|
2026
|
+
if (completionEvidence.guardTriggered) break modelAttemptsLoop;
|
|
1947
2027
|
|
|
1948
2028
|
const startupFailure = isRetryableSubagentStartupFailure(omitUndefinedProperties({
|
|
1949
2029
|
exitCode: effectiveExitCode,
|
|
@@ -1959,7 +2039,6 @@ async function runSingleStepInner(
|
|
|
1959
2039
|
interrupted: run.interrupted,
|
|
1960
2040
|
timedOut: run.timedOut,
|
|
1961
2041
|
stopped: run.stopped,
|
|
1962
|
-
turnBudgetExceeded: run.turnBudgetExceeded,
|
|
1963
2042
|
}));
|
|
1964
2043
|
const retryDelayMs = SUBAGENT_STARTUP_RETRY_DELAYS_MS[startupAttemptIndex];
|
|
1965
2044
|
if (startupFailure && retryDelayMs !== undefined) {
|
|
@@ -2006,8 +2085,14 @@ async function runSingleStepInner(
|
|
|
2006
2085
|
const rawOutput = finalResult?.finalOutput ?? "";
|
|
2007
2086
|
const outputForPersistence = stripAcceptanceReport(rawOutput);
|
|
2008
2087
|
const resolvedOutput = step.outputPath && finalResult?.exitCode === 0
|
|
2009
|
-
? resolveSingleOutput(step.outputPath, outputForPersistence, finalOutputSnapshot)
|
|
2088
|
+
? resolveSingleOutput(step.outputPath, outputForPersistence, finalOutputSnapshot, step.outputClaimPath)
|
|
2010
2089
|
: { fullOutput: outputForPersistence };
|
|
2090
|
+
if (resolvedOutput.fatalError) {
|
|
2091
|
+
if (finalResult) {
|
|
2092
|
+
finalResult.exitCode = 1;
|
|
2093
|
+
finalResult.error = finalResult.error ? `${finalResult.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2011
2096
|
const output = stripAcceptanceReport(resolvedOutput.fullOutput);
|
|
2012
2097
|
const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, output) : undefined;
|
|
2013
2098
|
let outputForSummary = output;
|
|
@@ -2016,14 +2101,6 @@ async function runSingleStepInner(
|
|
|
2016
2101
|
}
|
|
2017
2102
|
if (finalResult?.stopped && !outputForSummary.trim()) {
|
|
2018
2103
|
outputForSummary = ctx.stopMessage ?? "Subagent stopped by user.";
|
|
2019
|
-
} else if (!finalResult?.timedOut && !finalResult?.stopped && finalResult?.turnBudgetExceeded && turnBudget) {
|
|
2020
|
-
outputForSummary = formatTurnBudgetOutput(turnBudgetExceededMessage(turnBudget, turnBudget.turnCount), outputForSummary);
|
|
2021
|
-
} else if (!finalResult?.timedOut && !finalResult?.stopped && turnBudget?.outcome === "termination-deferred") {
|
|
2022
|
-
const note = turnBudgetDeferredNote(turnBudget, turnBudget.terminationDeferredAtTurn ?? turnBudget.turnCount);
|
|
2023
|
-
outputForSummary = outputForSummary.trim() ? `${note}\n\n${outputForSummary}` : note;
|
|
2024
|
-
} else if (!finalResult?.timedOut && !finalResult?.stopped && turnBudget?.outcome === "wrap-up-requested") {
|
|
2025
|
-
const note = turnBudgetSoftNote(turnBudget, turnBudget.wrapUpRequestedAtTurn ?? turnBudget.turnCount);
|
|
2026
|
-
outputForSummary = outputForSummary.trim() ? `${note}\n\n${outputForSummary}` : note;
|
|
2027
2104
|
}
|
|
2028
2105
|
const outputForAcceptance = rawOutput;
|
|
2029
2106
|
const childWrittenOutput = step.outputPath
|
|
@@ -2061,7 +2138,7 @@ async function runSingleStepInner(
|
|
|
2061
2138
|
saveError: resolvedOutput.saveError,
|
|
2062
2139
|
}));
|
|
2063
2140
|
outputForSummary = finalizedOutput.displayOutput;
|
|
2064
|
-
const acceptance = step.effectiveAcceptance && !finalResult?.stopped && !
|
|
2141
|
+
const acceptance = step.effectiveAcceptance && !finalResult?.stopped && !ctx.timeoutSignal?.aborted && !ctx.stopSignal?.aborted && !ctx.skipAcceptance?.()
|
|
2065
2142
|
? await evaluateAcceptance(omitUndefinedProperties({
|
|
2066
2143
|
acceptance: step.effectiveAcceptance,
|
|
2067
2144
|
output: outputForAcceptance,
|
|
@@ -2080,40 +2157,31 @@ async function runSingleStepInner(
|
|
|
2080
2157
|
: undefined;
|
|
2081
2158
|
const stoppedAfterAcceptance = finalResult?.stopped === true || ctx.stopSignal?.aborted === true;
|
|
2082
2159
|
const timedOutAfterAcceptance = !stoppedAfterAcceptance && (finalResult?.timedOut === true || ctx.timeoutSignal?.aborted === true);
|
|
2083
|
-
const turnBudgetExceeded = finalResult?.turnBudgetExceeded === true;
|
|
2084
2160
|
const effectiveAcceptance = step.effectiveAcceptance
|
|
2085
2161
|
? stoppedAfterAcceptance
|
|
2086
2162
|
? buildSkippedAcceptanceLedger(step.effectiveAcceptance, { id: "stopped", message: "Acceptance was not evaluated because the subagent was stopped." })
|
|
2087
2163
|
: timedOutAfterAcceptance
|
|
2088
2164
|
? buildSkippedAcceptanceLedger(step.effectiveAcceptance, { id: "timeout", message: "Acceptance was not evaluated because the subagent timed out." })
|
|
2089
|
-
:
|
|
2090
|
-
? buildSkippedAcceptanceLedger(step.effectiveAcceptance, { id: "turn-budget", message: "Acceptance was not evaluated because the subagent exceeded its turn budget." })
|
|
2091
|
-
: acceptance
|
|
2165
|
+
: acceptance
|
|
2092
2166
|
: undefined;
|
|
2093
2167
|
const acceptanceFailure = effectiveAcceptance ? acceptanceFailureMessage(effectiveAcceptance) : undefined;
|
|
2094
|
-
const acceptanceCanFailRun = acceptanceFailure && effectiveAcceptance?.explicit && (finalResult?.exitCode ?? 1) === 0 && !finalResult?.interrupted && !timedOutAfterAcceptance && !stoppedAfterAcceptance && !
|
|
2095
|
-
const effectiveFinalExitCode = timedOutAfterAcceptance || stoppedAfterAcceptance
|
|
2168
|
+
const acceptanceCanFailRun = acceptanceFailure && effectiveAcceptance?.explicit && (finalResult?.exitCode ?? 1) === 0 && !finalResult?.interrupted && !timedOutAfterAcceptance && !stoppedAfterAcceptance && !isAgentContractV1(step.agentContract);
|
|
2169
|
+
const effectiveFinalExitCode = timedOutAfterAcceptance || stoppedAfterAcceptance ? 1 : acceptanceCanFailRun ? 1 : finalResult?.exitCode ?? 1;
|
|
2096
2170
|
const intercomDetachReceipt = finalResult?.finalOutput === INTERCOM_DETACH_RECEIPT;
|
|
2097
2171
|
const baseFinalError = stoppedAfterAcceptance
|
|
2098
2172
|
? ctx.stopMessage ?? "Subagent stopped by user."
|
|
2099
2173
|
: timedOutAfterAcceptance
|
|
2100
2174
|
? finalResult?.error ?? ctx.timeoutMessage ?? "Subagent timed out."
|
|
2101
|
-
:
|
|
2102
|
-
? finalResult?.error ?? (turnBudget ? turnBudgetExceededMessage(turnBudget, turnBudget.turnCount) : "Subagent exceeded turn budget.")
|
|
2103
|
-
: acceptanceCanFailRun
|
|
2175
|
+
: acceptanceCanFailRun
|
|
2104
2176
|
? (finalResult?.error ? `${finalResult.error}\n${acceptanceFailure}` : acceptanceFailure)
|
|
2105
2177
|
: finalResult?.error ?? (intercomDetachReceipt ? INTERCOM_DETACH_RECEIPT : undefined);
|
|
2106
2178
|
const effectiveFinalError = formatChildFailureDiagnostic({
|
|
2107
2179
|
error: baseFinalError,
|
|
2108
|
-
afterCompactionSettlement: finalResult?.afterCompactionSettlement,
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
&& step.outputMode === "file-only"
|
|
2112
|
-
&& step.outputPath
|
|
2113
|
-
&& !fs.existsSync(step.outputPath)
|
|
2114
|
-
? step.outputPath
|
|
2115
|
-
: undefined,
|
|
2180
|
+
afterCompactionSettlement: effectiveFinalExitCode !== 0 ? finalResult?.afterCompactionSettlement : undefined,
|
|
2181
|
+
abortRecoveryDiagnostic: effectiveFinalExitCode !== 0 ? finalResult?.abortRecoveryDiagnostic : undefined,
|
|
2182
|
+
requiredOutput: effectiveFinalExitCode !== 0 ? finalResult?.effects?.settlementDiagnostic?.requiredOutput : undefined,
|
|
2116
2183
|
});
|
|
2184
|
+
const usage = usageFromAttempts(modelAttempts);
|
|
2117
2185
|
|
|
2118
2186
|
const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
|
|
2119
2187
|
? persistStepArtifacts({
|
|
@@ -2133,6 +2201,7 @@ async function runSingleStepInner(
|
|
|
2133
2201
|
model: finalResult?.model,
|
|
2134
2202
|
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
2135
2203
|
modelAttempts,
|
|
2204
|
+
usage,
|
|
2136
2205
|
error: effectiveFinalError,
|
|
2137
2206
|
acceptance: effectiveAcceptance,
|
|
2138
2207
|
...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
|
|
@@ -2149,6 +2218,7 @@ async function runSingleStepInner(
|
|
|
2149
2218
|
|
|
2150
2219
|
const result: StepResult & { completionGuardTriggered?: boolean } = omitUndefinedProperties({
|
|
2151
2220
|
agent: step.agent,
|
|
2221
|
+
...(childSessionName ? { sessionName: childSessionName } : {}),
|
|
2152
2222
|
context: step.context,
|
|
2153
2223
|
...(step.agentContract ? { agentContract: step.agentContract } : {}),
|
|
2154
2224
|
launchContractDigest: actualLaunchContractDigest,
|
|
@@ -2164,26 +2234,24 @@ async function runSingleStepInner(
|
|
|
2164
2234
|
modelAttempts,
|
|
2165
2235
|
contextOverflow: contextOverflow || undefined,
|
|
2166
2236
|
totalCost: costSummaryFromAttempts(modelAttempts),
|
|
2237
|
+
usage,
|
|
2167
2238
|
artifactPaths,
|
|
2168
|
-
outputSaveError: artifactErrors.outputSaveError,
|
|
2239
|
+
outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined,
|
|
2169
2240
|
metadataSaveError: artifactErrors.metadataSaveError,
|
|
2170
2241
|
transcriptPath: transcriptWriter ? artifactPaths?.transcriptPath : undefined,
|
|
2171
2242
|
transcriptError: transcriptWriter?.getError(),
|
|
2172
|
-
interrupted: timedOutAfterAcceptance || stoppedAfterAcceptance
|
|
2243
|
+
interrupted: timedOutAfterAcceptance || stoppedAfterAcceptance ? false : finalResult?.interrupted,
|
|
2173
2244
|
timedOut: timedOutAfterAcceptance ? true : finalResult?.timedOut,
|
|
2174
2245
|
stopped: stoppedAfterAcceptance ? true : finalResult?.stopped,
|
|
2175
2246
|
processSignal: finalResult?.processSignal,
|
|
2176
2247
|
timeoutRecovery,
|
|
2177
|
-
turnBudget,
|
|
2178
|
-
turnBudgetExceeded: turnBudgetExceeded || undefined,
|
|
2179
|
-
wrapUpRequested: finalResult?.wrapUpRequested || turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined,
|
|
2180
2248
|
toolBudget,
|
|
2181
2249
|
toolBudgetBlocked: toolBudgetBlocked || undefined,
|
|
2182
2250
|
completionGuardTriggered: completionGuardTriggeredFinal,
|
|
2183
2251
|
...((finalResult as (RunPiStreamingResult & { effects?: import("../../shared/types.ts").EffectsProjection }) | undefined)?.effects ? { effects: (finalResult as RunPiStreamingResult & { effects?: import("../../shared/types.ts").EffectsProjection }).effects } : {}),
|
|
2184
|
-
structuredOutput: timedOutAfterAcceptance || stoppedAfterAcceptance
|
|
2185
|
-
structuredOutputPath: timedOutAfterAcceptance || stoppedAfterAcceptance
|
|
2186
|
-
structuredOutputSchemaPath: timedOutAfterAcceptance || stoppedAfterAcceptance
|
|
2252
|
+
structuredOutput: timedOutAfterAcceptance || stoppedAfterAcceptance ? undefined : (finalResult as (RunPiStreamingResult & { structuredOutput?: unknown }) | undefined)?.structuredOutput,
|
|
2253
|
+
structuredOutputPath: timedOutAfterAcceptance || stoppedAfterAcceptance ? undefined : effectiveStructuredOutput?.outputPath,
|
|
2254
|
+
structuredOutputSchemaPath: timedOutAfterAcceptance || stoppedAfterAcceptance ? undefined : effectiveStructuredOutput?.schemaPath,
|
|
2187
2255
|
acceptance: effectiveAcceptance,
|
|
2188
2256
|
watchdog: finalResult?.watchdog,
|
|
2189
2257
|
...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
|
|
@@ -2257,6 +2325,11 @@ function requiredStatusStep(statusPayload: RunnerStatusPayload, index: number):
|
|
|
2257
2325
|
return step;
|
|
2258
2326
|
}
|
|
2259
2327
|
|
|
2328
|
+
function setStatusWorktreeReference(statusStep: RunnerStatusStep, worktree: WorktreeSetup["worktrees"][number]): void {
|
|
2329
|
+
statusStep.worktreePath = worktree.path;
|
|
2330
|
+
statusStep.branch = worktree.branch;
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2260
2333
|
function markParallelGroupSetupFailure(input: {
|
|
2261
2334
|
statusPayload: RunnerStatusPayload;
|
|
2262
2335
|
results: StepResult[];
|
|
@@ -2385,6 +2458,25 @@ function resolveAsyncStepTranscriptPath(input: {
|
|
|
2385
2458
|
|
|
2386
2459
|
type SingleStepResult = Awaited<ReturnType<typeof runSingleStep>>;
|
|
2387
2460
|
|
|
2461
|
+
function missingRequiredOutputAfterUsefulMutation(result: SingleStepResult): boolean {
|
|
2462
|
+
const effects = result.effects;
|
|
2463
|
+
return effects?.settlementDiagnostic?.requiredOutput?.missing === true
|
|
2464
|
+
&& (effects.settlementDiagnostic.mutation.attempted || effects.fileMutation?.attempted === true || Boolean(effects.fileMutation?.evidence?.changedFiles.length));
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
function partialExecutionWithUsefulMutation(result: SingleStepResult): boolean {
|
|
2468
|
+
const fileMutation = result.effects?.fileMutation;
|
|
2469
|
+
return result.execution?.status === "partial" && (fileMutation?.attempted === true || Boolean(fileMutation?.evidence?.changedFiles.length));
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
function partialEvidenceResult(result: SingleStepResult): boolean {
|
|
2473
|
+
return missingRequiredOutputAfterUsefulMutation(result) || partialExecutionWithUsefulMutation(result);
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
function concreteFailureResult(result: SingleStepResult): boolean {
|
|
2477
|
+
return result.success === false && !partialEvidenceResult(result);
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2388
2480
|
function combinedAbortSignal(signals: Array<AbortSignal | undefined>): AbortSignal | undefined {
|
|
2389
2481
|
const activeSignals = signals.filter((signal): signal is AbortSignal => Boolean(signal));
|
|
2390
2482
|
if (activeSignals.length === 0) return undefined;
|
|
@@ -2456,6 +2548,8 @@ async function runSubagent(
|
|
|
2456
2548
|
const overallStartTime = Date.now();
|
|
2457
2549
|
const shareEnabled = config.share === true;
|
|
2458
2550
|
const asyncDir = config.asyncDir;
|
|
2551
|
+
const handoffWorkflowKey = config.workflowKey;
|
|
2552
|
+
const handoffChildRunId = handoffWorkflowKey ? id : undefined;
|
|
2459
2553
|
const statusPath = path.join(asyncDir, "status.json");
|
|
2460
2554
|
const eventsPath = path.join(asyncDir, "events.jsonl");
|
|
2461
2555
|
const logPath = path.join(asyncDir, `subagent-log-${id}.md`);
|
|
@@ -2464,7 +2558,6 @@ async function runSubagent(
|
|
|
2464
2558
|
const activeChildTimeouts = new Map<number, () => void>();
|
|
2465
2559
|
const activeChildStops = new Map<number, () => void>();
|
|
2466
2560
|
const childStopRequests = new Map<number, { childId: string; requestedAt: number }>();
|
|
2467
|
-
const activeChildTurnBudgetAborts = new Map<number, (message: string, state?: TurnBudgetState) => void>();
|
|
2468
2561
|
const pendingStepSteers: SteerRequest[] = [];
|
|
2469
2562
|
const steeringCapabilities = new Map<number, SteerCapability>();
|
|
2470
2563
|
let interrupted = false;
|
|
@@ -2473,7 +2566,6 @@ async function runSubagent(
|
|
|
2473
2566
|
let timeoutTimer: NodeJS.Timeout | undefined;
|
|
2474
2567
|
let timedOut = false;
|
|
2475
2568
|
let stopped = false;
|
|
2476
|
-
let turnBudgetExceeded = false;
|
|
2477
2569
|
let usageBudgetExceeded = false;
|
|
2478
2570
|
const timeoutMessage = config.timeoutMs !== undefined ? `Subagent timed out after ${config.timeoutMs}ms.` : undefined;
|
|
2479
2571
|
const stopMessage = "Subagent stopped by user.";
|
|
@@ -2494,8 +2586,11 @@ async function runSubagent(
|
|
|
2494
2586
|
for (const task of step.parallel) {
|
|
2495
2587
|
const taskFlatIndex = flatStepCount;
|
|
2496
2588
|
const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: taskFlatIndex, flatStepCount: initialFlatStepCount }));
|
|
2589
|
+
const taskSessionName = task.sessionName ?? deriveChildSessionName({ agent: task.agent, task: task.task, label: task.label });
|
|
2497
2590
|
initialStatusSteps.push(omitUndefinedProperties({
|
|
2498
2591
|
agent: task.agent,
|
|
2592
|
+
...(task.lane ? { lane: task.lane } : config.lane ? { lane: config.lane } : {}),
|
|
2593
|
+
...(taskSessionName ? { sessionName: taskSessionName } : {}),
|
|
2499
2594
|
...(externalRunnerStatus(task.runner) ? { runner: externalRunnerStatus(task.runner) } : {}),
|
|
2500
2595
|
...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
|
|
2501
2596
|
...(task.context ? { context: task.context } : {}),
|
|
@@ -2514,6 +2609,7 @@ async function runSubagent(
|
|
|
2514
2609
|
...(transcriptPath ? { transcriptPath } : {}),
|
|
2515
2610
|
skills: task.skills,
|
|
2516
2611
|
model: task.model,
|
|
2612
|
+
...(task.contextLimit !== undefined ? { contextLimit: task.contextLimit } : {}),
|
|
2517
2613
|
thinking: task.thinking,
|
|
2518
2614
|
attemptedModels: task.modelCandidates && task.modelCandidates.length > 0 ? task.modelCandidates : task.model ? [task.model] : undefined,
|
|
2519
2615
|
recentTools: [],
|
|
@@ -2531,6 +2627,7 @@ async function runSubagent(
|
|
|
2531
2627
|
label: step.label ?? step.parallel.label ?? `Dynamic fanout (${step.collect.as})`,
|
|
2532
2628
|
outputName: step.collect.as,
|
|
2533
2629
|
structured: Boolean(step.collect.outputSchema),
|
|
2630
|
+
...(step.parallel.contextLimit !== undefined ? { contextLimit: step.parallel.contextLimit } : {}),
|
|
2534
2631
|
...(step.agentContract ? { agentContract: step.agentContract } : {}),
|
|
2535
2632
|
...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
|
|
2536
2633
|
...(step.thinkingCeiling ? { thinkingCeiling: step.thinkingCeiling } : {}),
|
|
@@ -2543,8 +2640,11 @@ async function runSubagent(
|
|
|
2543
2640
|
} else {
|
|
2544
2641
|
const stepFlatIndex = flatStepCount;
|
|
2545
2642
|
const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: step.agent, flatIndex: stepFlatIndex, flatStepCount: initialFlatStepCount }));
|
|
2643
|
+
const stepSessionName = step.sessionName ?? deriveChildSessionName({ agent: step.agent, task: step.task, label: step.label });
|
|
2546
2644
|
initialStatusSteps.push(omitUndefinedProperties({
|
|
2547
2645
|
agent: step.agent,
|
|
2646
|
+
...(step.lane ? { lane: step.lane } : config.lane ? { lane: config.lane } : {}),
|
|
2647
|
+
...(stepSessionName ? { sessionName: stepSessionName } : {}),
|
|
2548
2648
|
...(externalRunnerStatus(step.runner) ? { runner: externalRunnerStatus(step.runner) } : {}),
|
|
2549
2649
|
...(statusStepDescription(step.task) ? { description: statusStepDescription(step.task) } : {}),
|
|
2550
2650
|
...(step.context ? { context: step.context } : {}),
|
|
@@ -2563,6 +2663,7 @@ async function runSubagent(
|
|
|
2563
2663
|
...(transcriptPath ? { transcriptPath } : {}),
|
|
2564
2664
|
skills: step.skills,
|
|
2565
2665
|
model: step.model,
|
|
2666
|
+
...(step.contextLimit !== undefined ? { contextLimit: step.contextLimit } : {}),
|
|
2566
2667
|
thinking: step.thinking,
|
|
2567
2668
|
attemptedModels: step.modelCandidates && step.modelCandidates.length > 0 ? step.modelCandidates : step.model ? [step.model] : undefined,
|
|
2568
2669
|
recentTools: [],
|
|
@@ -2606,7 +2707,6 @@ async function runSubagent(
|
|
|
2606
2707
|
lastUpdate: overallStartTime,
|
|
2607
2708
|
...(config.timeoutMs !== undefined ? { timeoutMs: config.timeoutMs } : {}),
|
|
2608
2709
|
...(config.deadlineAt !== undefined ? { deadlineAt: config.deadlineAt } : {}),
|
|
2609
|
-
...(config.turnBudget ? { turnBudget: initialTurnBudgetState(config.turnBudget) } : {}),
|
|
2610
2710
|
...(config.toolBudget ? { toolBudget: initialToolBudgetState(config.toolBudget) } : {}),
|
|
2611
2711
|
...(config.usageBudget ? { usageBudget: usageBudgetState(config.usageBudget, undefined) } : {}),
|
|
2612
2712
|
pid: process.pid,
|
|
@@ -2621,6 +2721,7 @@ async function runSubagent(
|
|
|
2621
2721
|
...(config.runFanoutBudget ? { runFanoutBudget: getRunFanoutBudgetSnapshot(config.runFanoutBudget) } : {}),
|
|
2622
2722
|
...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
|
|
2623
2723
|
...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
|
|
2724
|
+
...(config.lane ? { lane: config.lane } : {}),
|
|
2624
2725
|
...(config.runnerProcessInstanceId ? { processTerminal: { version: 1 as const, state: "pending" as const, runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId } } : {}),
|
|
2625
2726
|
steps: initialStatusSteps,
|
|
2626
2727
|
artifactsDir,
|
|
@@ -2738,6 +2839,7 @@ async function runSubagent(
|
|
|
2738
2839
|
const statusResultSummary = (state: AsyncStatus["state"]): string => {
|
|
2739
2840
|
if (statusPayload.error) return statusPayload.error;
|
|
2740
2841
|
if (state === "paused") return "Paused after interrupt. Waiting for explicit next action.";
|
|
2842
|
+
if (state === "partial") return "Subagent needs attention after partial work.";
|
|
2741
2843
|
if (state === "stopped") return stopMessage;
|
|
2742
2844
|
if (state === "rejected") return "Subagent rejected.";
|
|
2743
2845
|
return state === "complete" ? "Subagent completed." : "Subagent failed.";
|
|
@@ -2746,12 +2848,13 @@ async function runSubagent(
|
|
|
2746
2848
|
if (step.status === "complete" || step.status === "completed") return true;
|
|
2747
2849
|
if (step.status === "failed" || step.status === "stopped" || step.status === "rejected") return false;
|
|
2748
2850
|
if (state === "complete") return true;
|
|
2749
|
-
if (state === "failed" || state === "stopped" || state === "rejected") return false;
|
|
2851
|
+
if (state === "failed" || state === "partial" || state === "stopped" || state === "rejected") return false;
|
|
2750
2852
|
return undefined;
|
|
2751
2853
|
};
|
|
2752
2854
|
const writeRecoverableStatusResult = (): void => {
|
|
2753
2855
|
const state = statusResultState();
|
|
2754
2856
|
if (!state || finalResultCommitted || !config.sessionId) return;
|
|
2857
|
+
if ((state as string) === "complete") return;
|
|
2755
2858
|
const now = statusPayload.endedAt ?? statusPayload.lastUpdate ?? Date.now();
|
|
2756
2859
|
const summary = statusResultSummary(state);
|
|
2757
2860
|
runPersistence.write(resultPath, omitUndefinedProperties({
|
|
@@ -2763,10 +2866,11 @@ async function runSubagent(
|
|
|
2763
2866
|
success: state === "complete",
|
|
2764
2867
|
state,
|
|
2765
2868
|
summary,
|
|
2766
|
-
error: state === "failed" || state === "stopped" || state === "rejected" ? summary : undefined,
|
|
2869
|
+
error: state === "failed" || state === "partial" || state === "stopped" || state === "rejected" ? summary : undefined,
|
|
2767
2870
|
stopped: state === "stopped" ? true : undefined,
|
|
2768
2871
|
results: statusPayload.steps.map((step) => omitUndefinedProperties({
|
|
2769
2872
|
agent: step.agent,
|
|
2873
|
+
...(step.sessionName ? { sessionName: step.sessionName } : {}),
|
|
2770
2874
|
output: step.status === "complete" || step.status === "completed" ? "" : step.error ?? summary,
|
|
2771
2875
|
error: step.error,
|
|
2772
2876
|
success: statusResultSuccess(state, step),
|
|
@@ -2774,6 +2878,7 @@ async function runSubagent(
|
|
|
2774
2878
|
model: step.model,
|
|
2775
2879
|
attemptedModels: step.attemptedModels,
|
|
2776
2880
|
modelAttempts: step.modelAttempts,
|
|
2881
|
+
usage: usageFromAttempts(step.modelAttempts),
|
|
2777
2882
|
contextOverflow: step.contextOverflow,
|
|
2778
2883
|
})),
|
|
2779
2884
|
exitCode: state === "complete" || state === "paused" ? 0 : 1,
|
|
@@ -2868,7 +2973,7 @@ async function runSubagent(
|
|
|
2868
2973
|
};
|
|
2869
2974
|
const childStopResult = (index: number, agent: string, context?: "fresh" | "fork"): SingleStepResult => {
|
|
2870
2975
|
markChildStopped(index);
|
|
2871
|
-
return stoppedStepResult(agent, context);
|
|
2976
|
+
return stoppedStepResult(agent, context, requiredStatusStep(statusPayload, index).sessionName);
|
|
2872
2977
|
};
|
|
2873
2978
|
const stopChildStep = (request: StopRequest): void => {
|
|
2874
2979
|
if (request.targetIndex === undefined) {
|
|
@@ -2911,13 +3016,6 @@ async function runSubagent(
|
|
|
2911
3016
|
activeChildStops.set(flatIndex, stop);
|
|
2912
3017
|
if (stopped || childStopRequests.has(flatIndex)) stop();
|
|
2913
3018
|
};
|
|
2914
|
-
const registerStepTurnBudgetAbort = (flatIndex: number, abort: ((message: string, state?: TurnBudgetState) => void) | undefined): void => {
|
|
2915
|
-
if (!abort) {
|
|
2916
|
-
activeChildTurnBudgetAborts.delete(flatIndex);
|
|
2917
|
-
return;
|
|
2918
|
-
}
|
|
2919
|
-
activeChildTurnBudgetAborts.set(flatIndex, abort);
|
|
2920
|
-
};
|
|
2921
3019
|
const interruptActiveChildren = (): void => {
|
|
2922
3020
|
for (const interrupt of [...activeChildInterrupts.values()]) interrupt();
|
|
2923
3021
|
};
|
|
@@ -3027,23 +3125,26 @@ async function runSubagent(
|
|
|
3027
3125
|
}
|
|
3028
3126
|
}
|
|
3029
3127
|
};
|
|
3030
|
-
const pausedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
|
|
3128
|
+
const pausedStepResult = (agent: string, context?: "fresh" | "fork", sessionName?: string): SingleStepResult => omitUndefinedProperties({
|
|
3031
3129
|
agent,
|
|
3130
|
+
sessionName,
|
|
3032
3131
|
context,
|
|
3033
3132
|
output: "Paused after interrupt. Waiting for explicit next action.",
|
|
3034
3133
|
exitCode: 0,
|
|
3035
3134
|
interrupted: true,
|
|
3036
3135
|
});
|
|
3037
|
-
const timedOutStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
|
|
3136
|
+
const timedOutStepResult = (agent: string, context?: "fresh" | "fork", sessionName?: string): SingleStepResult => omitUndefinedProperties({
|
|
3038
3137
|
agent,
|
|
3138
|
+
sessionName,
|
|
3039
3139
|
context,
|
|
3040
3140
|
output: timeoutMessage ?? "Subagent timed out.",
|
|
3041
3141
|
error: timeoutMessage ?? "Subagent timed out.",
|
|
3042
3142
|
exitCode: 1,
|
|
3043
3143
|
timedOut: true,
|
|
3044
3144
|
});
|
|
3045
|
-
const stoppedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
|
|
3145
|
+
const stoppedStepResult = (agent: string, context?: "fresh" | "fork", sessionName?: string): SingleStepResult => omitUndefinedProperties({
|
|
3046
3146
|
agent,
|
|
3147
|
+
sessionName,
|
|
3047
3148
|
context,
|
|
3048
3149
|
output: stopMessage,
|
|
3049
3150
|
error: stopMessage,
|
|
@@ -3424,74 +3525,15 @@ async function runSubagent(
|
|
|
3424
3525
|
}
|
|
3425
3526
|
pendingStepSteers.push(...remaining);
|
|
3426
3527
|
};
|
|
3427
|
-
const updateStepModel = (flatIndex: number, model: string | undefined, thinking: string | undefined, now = Date.now()): void => {
|
|
3528
|
+
const updateStepModel = (flatIndex: number, model: string | undefined, thinking: string | undefined, contextLimit?: number, now = Date.now()): void => {
|
|
3428
3529
|
const step = statusPayload.steps[flatIndex];
|
|
3429
3530
|
if (!step) return;
|
|
3430
3531
|
setOptionalProperty(step, "model", model);
|
|
3431
3532
|
setOptionalProperty(step, "thinking", thinking);
|
|
3533
|
+
setOptionalProperty(step, "contextLimit", contextLimit);
|
|
3432
3534
|
statusPayload.lastUpdate = now;
|
|
3433
3535
|
writeStatusPayload();
|
|
3434
3536
|
};
|
|
3435
|
-
const updateStepTurnBudget = (
|
|
3436
|
-
flatIndex: number,
|
|
3437
|
-
turnCount: number,
|
|
3438
|
-
now: number,
|
|
3439
|
-
terminalAssistantStop: boolean,
|
|
3440
|
-
toolWorkActiveOrStarting: boolean,
|
|
3441
|
-
): void => {
|
|
3442
|
-
const budget = config.turnBudget;
|
|
3443
|
-
const step = statusPayload.steps[flatIndex];
|
|
3444
|
-
if (!budget || !step || timedOut || stopped || turnBudgetExceeded || step.turnBudgetExceeded) return;
|
|
3445
|
-
if (turnCount < budget.maxTurns) {
|
|
3446
|
-
const state: TurnBudgetState = { ...budget, outcome: "within-budget", turnCount };
|
|
3447
|
-
step.turnBudget = state;
|
|
3448
|
-
statusPayload.turnBudget = state;
|
|
3449
|
-
return;
|
|
3450
|
-
}
|
|
3451
|
-
if (!step.wrapUpRequested) {
|
|
3452
|
-
step.wrapUpRequested = true;
|
|
3453
|
-
statusPayload.wrapUpRequested = true;
|
|
3454
|
-
appendRecentStepOutput(step, [turnBudgetSoftNote(budget, turnCount)]);
|
|
3455
|
-
}
|
|
3456
|
-
const decision = turnBudgetDecision(budget, turnCount, terminalAssistantStop, toolWorkActiveOrStarting);
|
|
3457
|
-
if (decision === "defer") {
|
|
3458
|
-
const firstDeferredTurn = step.turnBudget?.terminationDeferredAtTurn;
|
|
3459
|
-
const deferredState = turnBudgetDeferredState(budget, turnCount, firstDeferredTurn);
|
|
3460
|
-
step.turnBudget = deferredState;
|
|
3461
|
-
statusPayload.turnBudget = deferredState;
|
|
3462
|
-
if (firstDeferredTurn === undefined) {
|
|
3463
|
-
appendJsonl(eventsPath, JSON.stringify({
|
|
3464
|
-
type: "subagent.step.turn_budget_deferred",
|
|
3465
|
-
ts: now,
|
|
3466
|
-
runId: id,
|
|
3467
|
-
stepIndex: flatIndex,
|
|
3468
|
-
agent: step.agent,
|
|
3469
|
-
turnCount,
|
|
3470
|
-
maxTurns: budget.maxTurns,
|
|
3471
|
-
graceTurns: budget.graceTurns,
|
|
3472
|
-
}));
|
|
3473
|
-
}
|
|
3474
|
-
return;
|
|
3475
|
-
}
|
|
3476
|
-
const state = turnBudgetState(budget, turnCount, false);
|
|
3477
|
-
step.turnBudget = state;
|
|
3478
|
-
statusPayload.turnBudget = state;
|
|
3479
|
-
if (decision !== "abort") return;
|
|
3480
|
-
const exceededState = turnBudgetState(budget, turnCount, true);
|
|
3481
|
-
const message = turnBudgetExceededMessage(budget, turnCount);
|
|
3482
|
-
step.turnBudget = exceededState;
|
|
3483
|
-
step.turnBudgetExceeded = true;
|
|
3484
|
-
step.wrapUpRequested = true;
|
|
3485
|
-
step.error = message;
|
|
3486
|
-
turnBudgetExceeded = true;
|
|
3487
|
-
statusPayload.turnBudget = exceededState;
|
|
3488
|
-
statusPayload.turnBudgetExceeded = true;
|
|
3489
|
-
statusPayload.wrapUpRequested = true;
|
|
3490
|
-
statusPayload.error = message;
|
|
3491
|
-
statusPayload.lastUpdate = now;
|
|
3492
|
-
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.turn_budget_exceeded", ts: now, runId: id, stepIndex: flatIndex, agent: step.agent, turnCount, maxTurns: budget.maxTurns, graceTurns: budget.graceTurns, message }));
|
|
3493
|
-
activeChildTurnBudgetAborts.get(flatIndex)?.(message, exceededState);
|
|
3494
|
-
};
|
|
3495
3537
|
const updateStepFromChildEvent = (flatIndex: number, event: ChildEvent): void => {
|
|
3496
3538
|
const step = statusPayload.steps[flatIndex];
|
|
3497
3539
|
if (!step) return;
|
|
@@ -3514,7 +3556,7 @@ async function runSubagent(
|
|
|
3514
3556
|
return;
|
|
3515
3557
|
}
|
|
3516
3558
|
if (event.type === "tool_execution_start" && event.toolName) {
|
|
3517
|
-
const mutates = isMutatingTool(event.toolName, event.args);
|
|
3559
|
+
const mutates = isMutatingTool(event.toolName, event.args, flatSteps[flatIndex]?.mutationTools);
|
|
3518
3560
|
const currentPath = resolveCurrentPath(event.toolName, event.args);
|
|
3519
3561
|
const argsPreview = extractToolArgsPreview(event.args ?? {});
|
|
3520
3562
|
const blocksSupervisor = isBlockingSupervisorTool(event.toolName, event.args);
|
|
@@ -3632,13 +3674,6 @@ async function runSubagent(
|
|
|
3632
3674
|
refreshUsageBudget();
|
|
3633
3675
|
}
|
|
3634
3676
|
statusPayload.turnCount = Math.max(statusPayload.turnCount ?? 0, step.turnCount);
|
|
3635
|
-
updateStepTurnBudget(
|
|
3636
|
-
flatIndex,
|
|
3637
|
-
step.turnCount,
|
|
3638
|
-
now,
|
|
3639
|
-
isTerminalAssistantStop(event.message),
|
|
3640
|
-
assistantStartsToolCall(event.message) || Boolean(step.currentTool),
|
|
3641
|
-
);
|
|
3642
3677
|
}
|
|
3643
3678
|
syncTopLevelCurrentTool();
|
|
3644
3679
|
step.lastActivityAt = now;
|
|
@@ -3867,7 +3902,7 @@ async function runSubagent(
|
|
|
3867
3902
|
let flatIndex = 0;
|
|
3868
3903
|
let stepCursor = 0;
|
|
3869
3904
|
while (true) {
|
|
3870
|
-
if (interrupted || timedOut || stopped
|
|
3905
|
+
if (interrupted || timedOut || stopped) break;
|
|
3871
3906
|
consumePendingAppendRequests();
|
|
3872
3907
|
if (stepCursor >= steps.length) break;
|
|
3873
3908
|
refreshUsageBudget();
|
|
@@ -4012,10 +4047,12 @@ async function runSubagent(
|
|
|
4012
4047
|
: step.parallel.outputPath;
|
|
4013
4048
|
const taskText = task.task ?? step.parallel.task;
|
|
4014
4049
|
const materializedTask = step.parallel.namespaceOutputPath ? injectSingleOutputInstruction(taskText, outputPath, step.parallel) : taskText;
|
|
4050
|
+
const sessionName = deriveChildSessionName({ agent: step.parallel.agent, task: taskText, label: task.label ?? step.parallel.label });
|
|
4015
4051
|
return omitUndefinedProperties({
|
|
4016
4052
|
...step.parallel,
|
|
4017
4053
|
runFanoutPath: `chain[${stepIndex}].expand[${itemIndex}]`,
|
|
4018
4054
|
task: materializedTask,
|
|
4055
|
+
...(sessionName ? { sessionName } : {}),
|
|
4019
4056
|
effectiveAcceptance: resolveEffectiveAcceptance(omitUndefinedProperties({
|
|
4020
4057
|
explicit: step.parallel.acceptanceInput,
|
|
4021
4058
|
agentName: step.parallel.agent,
|
|
@@ -4046,6 +4083,7 @@ async function runSubagent(
|
|
|
4046
4083
|
const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: groupStartFlatIndex + itemIndex, flatStepCount: dynamicFlatStepCount }));
|
|
4047
4084
|
return omitUndefinedProperties({
|
|
4048
4085
|
agent: task.agent,
|
|
4086
|
+
...(task.sessionName ? { sessionName: task.sessionName } : {}),
|
|
4049
4087
|
...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
|
|
4050
4088
|
...(task.context ? { context: task.context } : {}),
|
|
4051
4089
|
...(task.phase ?? step.phase ? { phase: task.phase ?? step.phase } : {}),
|
|
@@ -4059,6 +4097,7 @@ async function runSubagent(
|
|
|
4059
4097
|
...(transcriptPath ? { transcriptPath } : {}),
|
|
4060
4098
|
...(task.skills ? { skills: task.skills } : {}),
|
|
4061
4099
|
...(task.model ? { model: task.model } : {}),
|
|
4100
|
+
...(task.contextLimit !== undefined ? { contextLimit: task.contextLimit } : {}),
|
|
4062
4101
|
...(task.thinking ? { thinking: task.thinking } : {}),
|
|
4063
4102
|
...(task.thinkingCeiling ? { thinkingCeiling: task.thinkingCeiling } : {}),
|
|
4064
4103
|
...(task.modelCandidates && task.modelCandidates.length > 0 ? { attemptedModels: task.modelCandidates } : task.model ? { attemptedModels: [task.model] } : {}),
|
|
@@ -4128,12 +4167,12 @@ async function runSubagent(
|
|
|
4128
4167
|
usageBudgetExceeded = true;
|
|
4129
4168
|
writeStatusPayload();
|
|
4130
4169
|
appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0 }));
|
|
4131
|
-
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
|
|
4170
|
+
return omitUndefinedProperties({ agent: task.agent, ...(task.sessionName ? { sessionName: task.sessionName } : {}), context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
|
|
4132
4171
|
}
|
|
4133
|
-
if (timedOut) return timedOutStepResult(task.agent, task.context);
|
|
4134
|
-
if (stopped) return stoppedStepResult(task.agent, task.context);
|
|
4172
|
+
if (timedOut) return timedOutStepResult(task.agent, task.context, task.sessionName);
|
|
4173
|
+
if (stopped) return stoppedStepResult(task.agent, task.context, task.sessionName);
|
|
4135
4174
|
if (childStopRequests.has(fi)) return childStopResult(fi, task.agent, task.context);
|
|
4136
|
-
if (interrupted) return pausedStepResult(task.agent, task.context);
|
|
4175
|
+
if (interrupted) return pausedStepResult(task.agent, task.context, task.sessionName);
|
|
4137
4176
|
if (aborted && failFast) {
|
|
4138
4177
|
const skippedAt = Date.now();
|
|
4139
4178
|
requiredStatusStep(statusPayload, fi).status = "failed";
|
|
@@ -4144,7 +4183,7 @@ async function runSubagent(
|
|
|
4144
4183
|
requiredStatusStep(statusPayload, fi).exitCode = -1;
|
|
4145
4184
|
statusPayload.lastUpdate = skippedAt;
|
|
4146
4185
|
writeStatusPayload();
|
|
4147
|
-
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
|
|
4186
|
+
return omitUndefinedProperties({ agent: task.agent, ...(task.sessionName ? { sessionName: task.sessionName } : {}), context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
|
|
4148
4187
|
}
|
|
4149
4188
|
const taskStartTime = Date.now();
|
|
4150
4189
|
statusPayload.currentStep = fi;
|
|
@@ -4180,20 +4219,19 @@ async function runSubagent(
|
|
|
4180
4219
|
registerInterrupt: (interrupt) => registerStepInterrupt(fi, interrupt),
|
|
4181
4220
|
registerTimeout: (interrupt) => registerStepTimeout(fi, interrupt),
|
|
4182
4221
|
registerStop: (stop) => registerStepStop(fi, stop),
|
|
4183
|
-
registerTurnBudgetAbort: (abort) => registerStepTurnBudgetAbort(fi, abort),
|
|
4184
4222
|
timeoutSignal: timeoutAbortController.signal,
|
|
4185
4223
|
stopSignal: stopAbortController.signal,
|
|
4186
4224
|
trackedMutationEvidenceForCompletionGuard: false,
|
|
4187
4225
|
timeoutMessage,
|
|
4188
4226
|
stopMessage,
|
|
4189
|
-
turnBudget: config.turnBudget,
|
|
4190
4227
|
toolTimeoutMs: task.toolTimeoutMs ?? config.toolTimeoutMs,
|
|
4191
|
-
onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking),
|
|
4228
|
+
onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking, attempt.contextLimit),
|
|
4192
4229
|
onChildEvent: (event) => updateStepFromChildEvent(fi, event),
|
|
4193
4230
|
onWriterProcess,
|
|
4194
4231
|
onExternalProcess: (process) => updateExternalProcess(fi, process),
|
|
4195
4232
|
onExternalJob: (externalJob) => updateExternalJob(fi, externalJob),
|
|
4196
4233
|
skipAcceptance: () => timedOut || stopped || childStopRequests.has(fi),
|
|
4234
|
+
usageBudgetExhausted: () => refreshUsageBudget()?.exhausted === true,
|
|
4197
4235
|
orcaProgressTab,
|
|
4198
4236
|
}), config.deadlineAt);
|
|
4199
4237
|
const taskEndTime = Date.now();
|
|
@@ -4205,16 +4243,11 @@ async function runSubagent(
|
|
|
4205
4243
|
requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
|
|
4206
4244
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
|
|
4207
4245
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
|
|
4208
|
-
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudget", singleResult.turnBudget);
|
|
4209
|
-
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
|
|
4210
|
-
setOptionalProperty(requiredStatusStep(statusPayload, fi), "wrapUpRequested", singleResult.wrapUpRequested);
|
|
4211
4246
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
|
|
4212
4247
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
|
|
4213
4248
|
if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
|
|
4214
4249
|
if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
|
|
4215
|
-
|
|
4216
|
-
if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
|
|
4217
|
-
if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
|
|
4250
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "sessionName", singleResult.sessionName);
|
|
4218
4251
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
|
|
4219
4252
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
|
|
4220
4253
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
|
|
@@ -4266,6 +4299,7 @@ async function runSubagent(
|
|
|
4266
4299
|
for (const pr of parallelResults) {
|
|
4267
4300
|
results.push(omitUndefinedProperties({
|
|
4268
4301
|
agent: pr.agent,
|
|
4302
|
+
...(pr.sessionName ? { sessionName: pr.sessionName } : {}),
|
|
4269
4303
|
context: pr.context,
|
|
4270
4304
|
agentContract: pr.agentContract,
|
|
4271
4305
|
launchContractDigest: pr.launchContractDigest,
|
|
@@ -4281,9 +4315,6 @@ async function runSubagent(
|
|
|
4281
4315
|
interrupted: pr.interrupted,
|
|
4282
4316
|
timedOut: pr.timedOut,
|
|
4283
4317
|
stopped: pr.stopped,
|
|
4284
|
-
turnBudget: pr.turnBudget,
|
|
4285
|
-
turnBudgetExceeded: pr.turnBudgetExceeded,
|
|
4286
|
-
wrapUpRequested: pr.wrapUpRequested,
|
|
4287
4318
|
toolBudget: pr.toolBudget,
|
|
4288
4319
|
toolBudgetBlocked: pr.toolBudgetBlocked,
|
|
4289
4320
|
sessionFile: pr.sessionFile,
|
|
@@ -4293,6 +4324,7 @@ async function runSubagent(
|
|
|
4293
4324
|
modelAttempts: pr.modelAttempts,
|
|
4294
4325
|
contextOverflow: pr.contextOverflow,
|
|
4295
4326
|
totalCost: pr.totalCost,
|
|
4327
|
+
usage: pr.usage,
|
|
4296
4328
|
artifactPaths: pr.artifactPaths,
|
|
4297
4329
|
transcriptPath: pr.transcriptPath,
|
|
4298
4330
|
transcriptError: pr.transcriptError,
|
|
@@ -4436,6 +4468,23 @@ async function runSubagent(
|
|
|
4436
4468
|
? omitUndefinedProperties({ hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs })
|
|
4437
4469
|
: undefined,
|
|
4438
4470
|
baseDir: config.worktreeBaseDir,
|
|
4471
|
+
beforeCreate: (plannedSetup) => {
|
|
4472
|
+
for (const worktree of plannedSetup.worktrees) setStatusWorktreeReference(requiredStatusStep(statusPayload, groupStartFlatIndex + worktree.index), worktree);
|
|
4473
|
+
const pendingHandoff = writePendingParallelHandoff({
|
|
4474
|
+
manifestPath: parallelHandoffPath(asyncDir),
|
|
4475
|
+
runId: id,
|
|
4476
|
+
mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" : "chain",
|
|
4477
|
+
source: "async",
|
|
4478
|
+
cwd,
|
|
4479
|
+
stepIndex,
|
|
4480
|
+
flatStartIndex: groupStartFlatIndex,
|
|
4481
|
+
setup: plannedSetup,
|
|
4482
|
+
laneBindings: handoffWorkflowKey || config.lane ? [{ index: groupStartFlatIndex, taskIndex: 0, ...(handoffWorkflowKey ? { workflowKey: handoffWorkflowKey } : {}), ...(handoffChildRunId ? { runId: handoffChildRunId } : {}), ...(config.lane ? { lane: config.lane } : {}) }] : undefined,
|
|
4483
|
+
});
|
|
4484
|
+
statusPayload.parallelHandoff = pendingHandoff;
|
|
4485
|
+
statusPayload.lastUpdate = Date.now();
|
|
4486
|
+
writeStatusPayload();
|
|
4487
|
+
},
|
|
4439
4488
|
}));
|
|
4440
4489
|
} catch (error) {
|
|
4441
4490
|
const setupError = error instanceof Error ? error.message : String(error);
|
|
@@ -4460,18 +4509,6 @@ async function runSubagent(
|
|
|
4460
4509
|
}
|
|
4461
4510
|
|
|
4462
4511
|
try {
|
|
4463
|
-
if (worktreeSetup) {
|
|
4464
|
-
writePendingParallelHandoff({
|
|
4465
|
-
manifestPath: parallelHandoffPath(asyncDir),
|
|
4466
|
-
runId: id,
|
|
4467
|
-
mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" : "chain",
|
|
4468
|
-
source: "async",
|
|
4469
|
-
cwd,
|
|
4470
|
-
stepIndex,
|
|
4471
|
-
flatStartIndex: groupStartFlatIndex,
|
|
4472
|
-
setup: worktreeSetup,
|
|
4473
|
-
});
|
|
4474
|
-
}
|
|
4475
4512
|
if (group.worktree) ensureParallelProgressFile(cwd, group);
|
|
4476
4513
|
const groupStartTime = Date.now();
|
|
4477
4514
|
markParallelGroupRunning({
|
|
@@ -4508,12 +4545,12 @@ async function runSubagent(
|
|
|
4508
4545
|
appendJsonl(eventsPath, JSON.stringify({
|
|
4509
4546
|
type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0,
|
|
4510
4547
|
}));
|
|
4511
|
-
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
|
|
4548
|
+
return omitUndefinedProperties({ agent: task.agent, ...(task.sessionName ? { sessionName: task.sessionName } : {}), context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
|
|
4512
4549
|
}
|
|
4513
|
-
if (timedOut) return timedOutStepResult(task.agent, task.context);
|
|
4514
|
-
if (stopped) return stoppedStepResult(task.agent, task.context);
|
|
4550
|
+
if (timedOut) return timedOutStepResult(task.agent, task.context, task.sessionName);
|
|
4551
|
+
if (stopped) return stoppedStepResult(task.agent, task.context, task.sessionName);
|
|
4515
4552
|
if (childStopRequests.has(fi)) return childStopResult(fi, task.agent, task.context);
|
|
4516
|
-
if (interrupted) return pausedStepResult(task.agent, task.context);
|
|
4553
|
+
if (interrupted) return pausedStepResult(task.agent, task.context, task.sessionName);
|
|
4517
4554
|
if (aborted && failFast) {
|
|
4518
4555
|
const skippedAt = Date.now();
|
|
4519
4556
|
requiredStatusStep(statusPayload, fi).status = "failed";
|
|
@@ -4528,7 +4565,7 @@ async function runSubagent(
|
|
|
4528
4565
|
appendJsonl(eventsPath, JSON.stringify({
|
|
4529
4566
|
type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: -1, durationMs: 0,
|
|
4530
4567
|
}));
|
|
4531
|
-
return omitUndefinedProperties({ agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
|
|
4568
|
+
return omitUndefinedProperties({ agent: task.agent, ...(task.sessionName ? { sessionName: task.sessionName } : {}), context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
|
|
4532
4569
|
}
|
|
4533
4570
|
|
|
4534
4571
|
const taskStartTime = Date.now();
|
|
@@ -4576,20 +4613,19 @@ async function runSubagent(
|
|
|
4576
4613
|
registerInterrupt: (interrupt) => registerStepInterrupt(fi, interrupt),
|
|
4577
4614
|
registerTimeout: (interrupt) => registerStepTimeout(fi, interrupt),
|
|
4578
4615
|
registerStop: (stop) => registerStepStop(fi, stop),
|
|
4579
|
-
registerTurnBudgetAbort: (abort) => registerStepTurnBudgetAbort(fi, abort),
|
|
4580
4616
|
timeoutSignal: timeoutAbortController.signal,
|
|
4581
4617
|
stopSignal: stopAbortController.signal,
|
|
4582
4618
|
trackedMutationEvidenceForCompletionGuard: Boolean(worktreeSetup),
|
|
4583
4619
|
timeoutMessage,
|
|
4584
4620
|
stopMessage,
|
|
4585
|
-
turnBudget: config.turnBudget,
|
|
4586
4621
|
toolTimeoutMs: taskForRun.toolTimeoutMs ?? config.toolTimeoutMs,
|
|
4587
|
-
onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking),
|
|
4622
|
+
onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking, attempt.contextLimit),
|
|
4588
4623
|
onChildEvent: (event) => updateStepFromChildEvent(fi, event),
|
|
4589
4624
|
onWriterProcess,
|
|
4590
4625
|
onExternalProcess: (process) => updateExternalProcess(fi, process),
|
|
4591
4626
|
onExternalJob: (externalJob) => updateExternalJob(fi, externalJob),
|
|
4592
4627
|
skipAcceptance: () => timedOut || stopped || childStopRequests.has(fi),
|
|
4628
|
+
usageBudgetExhausted: () => refreshUsageBudget()?.exhausted === true,
|
|
4593
4629
|
orcaProgressTab,
|
|
4594
4630
|
}), config.deadlineAt);
|
|
4595
4631
|
if (task.sessionFile) {
|
|
@@ -4607,16 +4643,11 @@ async function runSubagent(
|
|
|
4607
4643
|
requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
|
|
4608
4644
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
|
|
4609
4645
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
|
|
4610
|
-
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudget", singleResult.turnBudget);
|
|
4611
|
-
setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
|
|
4612
|
-
setOptionalProperty(requiredStatusStep(statusPayload, fi), "wrapUpRequested", singleResult.wrapUpRequested);
|
|
4613
4646
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
|
|
4614
4647
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
|
|
4615
4648
|
if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
|
|
4616
4649
|
if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
|
|
4617
|
-
|
|
4618
|
-
if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
|
|
4619
|
-
if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
|
|
4650
|
+
setOptionalProperty(requiredStatusStep(statusPayload, fi), "sessionName", singleResult.sessionName);
|
|
4620
4651
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
|
|
4621
4652
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
|
|
4622
4653
|
setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
|
|
@@ -4725,9 +4756,6 @@ async function runSubagent(
|
|
|
4725
4756
|
interrupted: pr.interrupted,
|
|
4726
4757
|
timedOut: pr.timedOut,
|
|
4727
4758
|
stopped: pr.stopped,
|
|
4728
|
-
turnBudget: pr.turnBudget,
|
|
4729
|
-
turnBudgetExceeded: pr.turnBudgetExceeded,
|
|
4730
|
-
wrapUpRequested: pr.wrapUpRequested,
|
|
4731
4759
|
toolBudget: pr.toolBudget,
|
|
4732
4760
|
toolBudgetBlocked: pr.toolBudgetBlocked,
|
|
4733
4761
|
sessionFile: pr.sessionFile,
|
|
@@ -4737,6 +4765,7 @@ async function runSubagent(
|
|
|
4737
4765
|
modelAttempts: pr.modelAttempts,
|
|
4738
4766
|
contextOverflow: pr.contextOverflow,
|
|
4739
4767
|
totalCost: pr.totalCost,
|
|
4768
|
+
usage: pr.usage,
|
|
4740
4769
|
artifactPaths: pr.artifactPaths,
|
|
4741
4770
|
transcriptPath: pr.transcriptPath,
|
|
4742
4771
|
transcriptError: pr.transcriptError,
|
|
@@ -4790,12 +4819,14 @@ async function runSubagent(
|
|
|
4790
4819
|
diffs: captured.diffs,
|
|
4791
4820
|
results: parallelResults.map((result) => ({
|
|
4792
4821
|
agent: result.agent,
|
|
4822
|
+
...(handoffWorkflowKey ? { workflowKey: handoffWorkflowKey } : {}),
|
|
4823
|
+
...(handoffChildRunId ? { runId: handoffChildRunId } : {}),
|
|
4824
|
+
...(config.lane ? { lane: config.lane } : {}),
|
|
4793
4825
|
status: result.stopped || (result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
|
|
4794
4826
|
processSignal: result.processSignal,
|
|
4795
4827
|
interrupted: result.interrupted,
|
|
4796
4828
|
timedOut: result.timedOut,
|
|
4797
4829
|
stopped: result.stopped,
|
|
4798
|
-
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
4799
4830
|
}))) ? "stopped" as const : result.interrupted ? "paused" as const : result.exitCode === 0 ? "completed" as const : "failed" as const,
|
|
4800
4831
|
summary: result.output || result.error || "(no output)",
|
|
4801
4832
|
...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
|
|
@@ -4841,12 +4872,12 @@ async function runSubagent(
|
|
|
4841
4872
|
} else {
|
|
4842
4873
|
const seqStep = step as SubagentStep;
|
|
4843
4874
|
if (timedOut) {
|
|
4844
|
-
results.push(timedOutStepResult(seqStep.agent, seqStep.context));
|
|
4875
|
+
results.push(timedOutStepResult(seqStep.agent, seqStep.context, seqStep.sessionName));
|
|
4845
4876
|
flatIndex++;
|
|
4846
4877
|
continue;
|
|
4847
4878
|
}
|
|
4848
4879
|
if (stopped) {
|
|
4849
|
-
results.push(stoppedStepResult(seqStep.agent, seqStep.context));
|
|
4880
|
+
results.push(stoppedStepResult(seqStep.agent, seqStep.context, seqStep.sessionName));
|
|
4850
4881
|
flatIndex++;
|
|
4851
4882
|
continue;
|
|
4852
4883
|
}
|
|
@@ -4856,7 +4887,7 @@ async function runSubagent(
|
|
|
4856
4887
|
continue;
|
|
4857
4888
|
}
|
|
4858
4889
|
if (interrupted) {
|
|
4859
|
-
results.push(pausedStepResult(seqStep.agent, seqStep.context));
|
|
4890
|
+
results.push(pausedStepResult(seqStep.agent, seqStep.context, seqStep.sessionName));
|
|
4860
4891
|
flatIndex++;
|
|
4861
4892
|
continue;
|
|
4862
4893
|
}
|
|
@@ -4869,17 +4900,27 @@ async function runSubagent(
|
|
|
4869
4900
|
? omitUndefinedProperties({ hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs })
|
|
4870
4901
|
: undefined,
|
|
4871
4902
|
baseDir: config.worktreeBaseDir,
|
|
4903
|
+
beforeCreate: (plannedSetup) => {
|
|
4904
|
+
const worktree = plannedSetup.worktrees[0];
|
|
4905
|
+
if (worktree) {
|
|
4906
|
+
setStatusWorktreeReference(requiredStatusStep(statusPayload, flatIndex), worktree);
|
|
4907
|
+
}
|
|
4908
|
+
const pendingHandoff = writePendingParallelHandoff({
|
|
4909
|
+
manifestPath: parallelHandoffPath(asyncDir),
|
|
4910
|
+
runId: id,
|
|
4911
|
+
mode: "single",
|
|
4912
|
+
source: "async",
|
|
4913
|
+
cwd,
|
|
4914
|
+
stepIndex,
|
|
4915
|
+
flatStartIndex: flatIndex,
|
|
4916
|
+
setup: plannedSetup,
|
|
4917
|
+
laneBindings: handoffWorkflowKey || config.lane ? [{ index: flatIndex, taskIndex: 0, ...(handoffWorkflowKey ? { workflowKey: handoffWorkflowKey } : {}), ...(handoffChildRunId ? { runId: handoffChildRunId } : {}), ...(config.lane ? { lane: config.lane } : {}) }] : undefined,
|
|
4918
|
+
});
|
|
4919
|
+
statusPayload.parallelHandoff = pendingHandoff;
|
|
4920
|
+
statusPayload.lastUpdate = Date.now();
|
|
4921
|
+
writeStatusPayload();
|
|
4922
|
+
},
|
|
4872
4923
|
}));
|
|
4873
|
-
writePendingParallelHandoff({
|
|
4874
|
-
manifestPath: parallelHandoffPath(asyncDir),
|
|
4875
|
-
runId: id,
|
|
4876
|
-
mode: "single",
|
|
4877
|
-
source: "async",
|
|
4878
|
-
cwd,
|
|
4879
|
-
stepIndex,
|
|
4880
|
-
flatStartIndex: flatIndex,
|
|
4881
|
-
setup: singleWorktreeSetup,
|
|
4882
|
-
});
|
|
4883
4924
|
} catch (error) {
|
|
4884
4925
|
if (singleWorktreeSetup) cleanupWorktrees(singleWorktreeSetup);
|
|
4885
4926
|
throw error;
|
|
@@ -4932,19 +4973,18 @@ async function runSubagent(
|
|
|
4932
4973
|
registerInterrupt: (interrupt) => registerStepInterrupt(flatIndex, interrupt),
|
|
4933
4974
|
registerTimeout: (interrupt) => registerStepTimeout(flatIndex, interrupt),
|
|
4934
4975
|
registerStop: (stop) => registerStepStop(flatIndex, stop),
|
|
4935
|
-
registerTurnBudgetAbort: (abort) => registerStepTurnBudgetAbort(flatIndex, abort),
|
|
4936
4976
|
timeoutSignal: timeoutAbortController.signal,
|
|
4937
4977
|
stopSignal: stopAbortController.signal,
|
|
4938
4978
|
timeoutMessage,
|
|
4939
4979
|
stopMessage,
|
|
4940
|
-
turnBudget: config.turnBudget,
|
|
4941
4980
|
toolTimeoutMs: seqStep.toolTimeoutMs ?? config.toolTimeoutMs,
|
|
4942
|
-
onAttemptStart: (attempt) => updateStepModel(flatIndex, attempt.model, attempt.thinking),
|
|
4981
|
+
onAttemptStart: (attempt) => updateStepModel(flatIndex, attempt.model, attempt.thinking, attempt.contextLimit),
|
|
4943
4982
|
onChildEvent: (event) => updateStepFromChildEvent(flatIndex, event),
|
|
4944
4983
|
onWriterProcess,
|
|
4945
4984
|
onExternalProcess: (process) => updateExternalProcess(flatIndex, process),
|
|
4946
4985
|
onExternalJob: (externalJob) => updateExternalJob(flatIndex, externalJob),
|
|
4947
4986
|
skipAcceptance: () => timedOut || stopped || childStopRequests.has(flatIndex),
|
|
4987
|
+
usageBudgetExhausted: () => refreshUsageBudget()?.exhausted === true,
|
|
4948
4988
|
orcaProgressTab,
|
|
4949
4989
|
}), config.deadlineAt);
|
|
4950
4990
|
} catch (error) {
|
|
@@ -4959,6 +4999,7 @@ async function runSubagent(
|
|
|
4959
4999
|
const childStopped = singleResult.stopped === true;
|
|
4960
5000
|
results.push(omitUndefinedProperties({
|
|
4961
5001
|
agent: singleResult.agent,
|
|
5002
|
+
...(singleResult.sessionName ? { sessionName: singleResult.sessionName } : {}),
|
|
4962
5003
|
context: singleResult.context,
|
|
4963
5004
|
agentContract: singleResult.agentContract,
|
|
4964
5005
|
launchContractDigest: singleResult.launchContractDigest,
|
|
@@ -4977,6 +5018,7 @@ async function runSubagent(
|
|
|
4977
5018
|
modelAttempts: singleResult.modelAttempts,
|
|
4978
5019
|
contextOverflow: singleResult.contextOverflow,
|
|
4979
5020
|
totalCost: singleResult.totalCost,
|
|
5021
|
+
usage: singleResult.usage,
|
|
4980
5022
|
artifactPaths: singleResult.artifactPaths,
|
|
4981
5023
|
transcriptPath: singleResult.transcriptPath,
|
|
4982
5024
|
transcriptError: singleResult.transcriptError,
|
|
@@ -4994,9 +5036,6 @@ async function runSubagent(
|
|
|
4994
5036
|
interrupted: singleResult.interrupted,
|
|
4995
5037
|
timedOut: timedOut || singleResult.timedOut ? true : undefined,
|
|
4996
5038
|
stopped: stopped || childStopped ? true : undefined,
|
|
4997
|
-
turnBudget: singleResult.turnBudget,
|
|
4998
|
-
turnBudgetExceeded: singleResult.turnBudgetExceeded,
|
|
4999
|
-
wrapUpRequested: singleResult.wrapUpRequested,
|
|
5000
5039
|
toolBudget: singleResult.toolBudget,
|
|
5001
5040
|
toolBudgetBlocked: singleResult.toolBudgetBlocked,
|
|
5002
5041
|
runner: singleResult.runner,
|
|
@@ -5051,16 +5090,11 @@ async function runSubagent(
|
|
|
5051
5090
|
requiredStatusStep(statusPayload, flatIndex).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
|
|
5052
5091
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
|
|
5053
5092
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "stopped", stopped || childStopped ? true : undefined);
|
|
5054
|
-
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "turnBudget", singleResult.turnBudget);
|
|
5055
|
-
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
|
|
5056
|
-
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "wrapUpRequested", singleResult.wrapUpRequested);
|
|
5057
5093
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudget", singleResult.toolBudget);
|
|
5058
5094
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
|
|
5059
5095
|
if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
|
|
5060
5096
|
if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
|
|
5061
|
-
|
|
5062
|
-
if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
|
|
5063
|
-
if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
|
|
5097
|
+
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "sessionName", singleResult.sessionName);
|
|
5064
5098
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "model", singleResult.model);
|
|
5065
5099
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, flatIndex).thinking));
|
|
5066
5100
|
setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "attemptedModels", singleResult.attemptedModels);
|
|
@@ -5121,6 +5155,9 @@ async function runSubagent(
|
|
|
5121
5155
|
diffs,
|
|
5122
5156
|
results: [{
|
|
5123
5157
|
agent: singleResult.agent,
|
|
5158
|
+
...(handoffWorkflowKey ? { workflowKey: handoffWorkflowKey } : {}),
|
|
5159
|
+
...(handoffChildRunId ? { runId: handoffChildRunId } : {}),
|
|
5160
|
+
...(config.lane ? { lane: config.lane } : {}),
|
|
5124
5161
|
status: singleResult.stopped ? "stopped" as const : singleResult.interrupted ? "paused" as const : singleResult.exitCode === 0 ? "completed" as const : "failed" as const,
|
|
5125
5162
|
summary: singleResult.output || singleResult.error || "(no output)",
|
|
5126
5163
|
...(singleResult.artifactPaths?.outputPath ? { outputPath: singleResult.artifactPaths.outputPath } : {}),
|
|
@@ -5241,14 +5278,14 @@ async function runSubagent(
|
|
|
5241
5278
|
if (!timedOut && !stopped && !interrupted && config.timeoutMs !== undefined && results.some((result) => result.timedOut === true && result.error === timeoutMessage)) {
|
|
5242
5279
|
timedOut = true;
|
|
5243
5280
|
}
|
|
5244
|
-
const signalTerminated = !stopped && !timedOut && !
|
|
5281
|
+
const signalTerminated = !stopped && !timedOut && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
|
|
5245
5282
|
processSignal: result.processSignal,
|
|
5246
5283
|
interrupted: result.interrupted,
|
|
5247
5284
|
timedOut: result.timedOut,
|
|
5248
5285
|
stopped: result.stopped,
|
|
5249
|
-
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
5250
5286
|
})));
|
|
5251
|
-
|
|
5287
|
+
const partialWithEvidence = !stopped && !signalTerminated && !timedOut && !usageBudgetExceeded && !interrupted && results.some(partialEvidenceResult) && !results.some(concreteFailureResult);
|
|
5288
|
+
statusPayload.state = stopped || signalTerminated ? "stopped" : timedOut || usageBudgetExceeded ? "failed" : interrupted ? "paused" : results.every((r) => r.success) ? "complete" : partialWithEvidence ? "partial" : "failed";
|
|
5252
5289
|
closeSteerInbox(asyncDir, statusPayload.state, (filePath, payload) => runPersistence.write(filePath, payload));
|
|
5253
5290
|
disposeControlInbox();
|
|
5254
5291
|
for (const request of consumeSteerRequests(asyncDir)) deliverSteerRequest(request);
|
|
@@ -5278,13 +5315,17 @@ async function runSubagent(
|
|
|
5278
5315
|
statusPayload.timedOut = true;
|
|
5279
5316
|
statusPayload.error = timeoutMessage ?? "Subagent timed out.";
|
|
5280
5317
|
}
|
|
5281
|
-
if (turnBudgetExceeded && !statusPayload.error) {
|
|
5282
|
-
const budget = statusPayload.turnBudget;
|
|
5283
|
-
statusPayload.error = budget ? turnBudgetExceededMessage(budget, budget.turnCount) : "Subagent exceeded turn budget.";
|
|
5284
|
-
}
|
|
5285
5318
|
if (usageBudgetExceeded && statusPayload.usageBudget && !statusPayload.error) {
|
|
5286
5319
|
statusPayload.error = usageBudgetExceededMessage(statusPayload.usageBudget);
|
|
5287
5320
|
}
|
|
5321
|
+
if (partialWithEvidence) {
|
|
5322
|
+
const partialResult = results.find(partialEvidenceResult);
|
|
5323
|
+
statusPayload.activityState = "needs_attention";
|
|
5324
|
+
statusPayload.error = partialResult?.error ?? statusPayload.error;
|
|
5325
|
+
for (const step of statusPayload.steps) {
|
|
5326
|
+
if (step.status === "failed") step.activityState = "needs_attention";
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5288
5329
|
statusPayload.endedAt = runEndedAt;
|
|
5289
5330
|
statusPayload.lastUpdate = runEndedAt;
|
|
5290
5331
|
setOptionalProperty(statusPayload, "sessionFile", effectiveSessionFile);
|
|
@@ -5294,8 +5335,10 @@ async function runSubagent(
|
|
|
5294
5335
|
setOptionalProperty(statusPayload, "shareUrl", shareUrl);
|
|
5295
5336
|
setOptionalProperty(statusPayload, "gistUrl", gistUrl);
|
|
5296
5337
|
setOptionalProperty(statusPayload, "shareError", shareError);
|
|
5297
|
-
if (statusPayload.state === "failed" && !statusPayload.error) {
|
|
5298
|
-
const
|
|
5338
|
+
if ((statusPayload.state === "failed" || statusPayload.state === "partial") && !statusPayload.error) {
|
|
5339
|
+
const concreteFailure = results.find(concreteFailureResult);
|
|
5340
|
+
const failedStep = concreteFailure ? undefined : statusPayload.steps.find((s) => s.status === "failed");
|
|
5341
|
+
if (concreteFailure?.error) statusPayload.error = concreteFailure.error;
|
|
5299
5342
|
if (failedStep?.agent) {
|
|
5300
5343
|
statusPayload.error = `Step failed: ${failedStep.agent}`;
|
|
5301
5344
|
}
|
|
@@ -5307,20 +5350,18 @@ async function runSubagent(
|
|
|
5307
5350
|
id,
|
|
5308
5351
|
agent: agentName,
|
|
5309
5352
|
mode: resultMode,
|
|
5310
|
-
success:
|
|
5311
|
-
state:
|
|
5312
|
-
summary: stopped ? stopMessage : signalTerminated ? (statusPayload.error ?? "Subagent process terminated by signal.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") :
|
|
5353
|
+
success: statusPayload.state === "complete",
|
|
5354
|
+
state: statusPayload.state,
|
|
5355
|
+
summary: stopped ? stopMessage : signalTerminated ? (statusPayload.error ?? "Subagent process terminated by signal.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : usageBudgetExceeded ? (statusPayload.error ?? "Usage budget exhausted.") : interrupted ? "Paused after interrupt. Waiting for explicit next action." : statusPayload.state === "partial" ? (statusPayload.error ?? summary) : summary,
|
|
5313
5356
|
...(config.timeoutMs !== undefined ? { timeoutMs: config.timeoutMs } : {}),
|
|
5314
5357
|
...(config.deadlineAt !== undefined ? { deadlineAt: config.deadlineAt } : {}),
|
|
5315
|
-
...(statusPayload.turnBudget ? { turnBudget: statusPayload.turnBudget } : {}),
|
|
5316
|
-
...(statusPayload.turnBudgetExceeded ? { turnBudgetExceeded: true } : {}),
|
|
5317
|
-
...(statusPayload.wrapUpRequested ? { wrapUpRequested: true } : {}),
|
|
5318
5358
|
...(statusPayload.toolBudget ? { toolBudget: statusPayload.toolBudget } : {}),
|
|
5319
5359
|
...(statusPayload.toolBudgetBlocked ? { toolBudgetBlocked: true } : {}),
|
|
5320
5360
|
...(statusPayload.usageBudget ? { usageBudget: statusPayload.usageBudget } : {}),
|
|
5321
|
-
...(stopped ? { stopped: true, error: stopMessage } : timedOut ? { timedOut: true, error: timeoutMessage ?? "Subagent timed out." } :
|
|
5361
|
+
...(stopped ? { stopped: true, error: stopMessage } : timedOut ? { timedOut: true, error: timeoutMessage ?? "Subagent timed out." } : usageBudgetExceeded ? { error: statusPayload.error ?? "Usage budget exhausted." } : {}),
|
|
5322
5362
|
results: results.map((r) => omitUndefinedProperties({
|
|
5323
5363
|
agent: r.agent,
|
|
5364
|
+
...(r.sessionName ? { sessionName: r.sessionName } : {}),
|
|
5324
5365
|
context: r.context,
|
|
5325
5366
|
output: r.output,
|
|
5326
5367
|
outputState: r.outputState,
|
|
@@ -5332,9 +5373,6 @@ async function runSubagent(
|
|
|
5332
5373
|
timedOut: r.timedOut || undefined,
|
|
5333
5374
|
stopped: r.stopped || undefined,
|
|
5334
5375
|
processSignal: r.processSignal || undefined,
|
|
5335
|
-
turnBudget: r.turnBudget,
|
|
5336
|
-
turnBudgetExceeded: r.turnBudgetExceeded || undefined,
|
|
5337
|
-
wrapUpRequested: r.wrapUpRequested || undefined,
|
|
5338
5376
|
toolBudget: r.toolBudget,
|
|
5339
5377
|
toolBudgetBlocked: r.toolBudgetBlocked || undefined,
|
|
5340
5378
|
sessionFile: r.sessionFile,
|
|
@@ -5344,6 +5382,7 @@ async function runSubagent(
|
|
|
5344
5382
|
modelAttempts: r.modelAttempts,
|
|
5345
5383
|
contextOverflow: r.contextOverflow,
|
|
5346
5384
|
totalCost: r.totalCost,
|
|
5385
|
+
usage: r.usage,
|
|
5347
5386
|
artifactPaths: r.artifactPaths,
|
|
5348
5387
|
outputSaveError: r.outputSaveError,
|
|
5349
5388
|
metadataSaveError: r.metadataSaveError,
|
|
@@ -5376,7 +5415,7 @@ async function runSubagent(
|
|
|
5376
5415
|
capabilityAudit: statusPayload.capabilityAudit,
|
|
5377
5416
|
...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
|
|
5378
5417
|
...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
|
|
5379
|
-
exitCode:
|
|
5418
|
+
exitCode: statusPayload.state === "complete" || statusPayload.state === "paused" ? 0 : 1,
|
|
5380
5419
|
timestamp: runEndedAt,
|
|
5381
5420
|
durationMs: runEndedAt - overallStartTime,
|
|
5382
5421
|
totalTokens: statusPayload.totalTokens,
|