@selesai/code 0.8.4 → 0.8.6
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 +22 -0
- package/README.md +7 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/defaults/models.json +46 -55
- package/dist/defaults/settings.json +7 -8
- package/dist/extensions/agent-browser.test.ts +178 -2
- package/dist/extensions/agent-browser.ts +2 -0
- package/dist/extensions/copy-turn.test.ts +229 -0
- package/dist/extensions/copy-turn.ts +11 -0
- package/dist/extensions/grep-app/index.test.ts +356 -1
- package/dist/extensions/grep-app/index.ts +6 -1
- package/dist/extensions/handoff-new.test.ts +351 -161
- package/dist/extensions/handoff-new.ts +3 -0
- package/dist/extensions/inline-skills.test.ts +93 -0
- package/dist/extensions/inline-skills.ts +3 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +26 -3
- package/dist/extensions/pi-subagents/README.md +2 -0
- package/dist/extensions/pi-subagents/agents/builder.md +5 -2
- package/dist/extensions/pi-subagents/agents/commentator.md +1 -1
- package/dist/extensions/pi-subagents/docs/configuration.md +54 -2
- package/dist/extensions/pi-subagents/docs/observability.md +1 -1
- package/dist/extensions/pi-subagents/docs/tool-reference.md +1 -1
- package/dist/extensions/pi-subagents/docs/workflows.md +1 -1
- package/dist/extensions/pi-subagents/package-lock.json +2 -2
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +1 -1
- package/dist/extensions/pi-subagents/src/agents/agents.ts +9 -3
- package/dist/extensions/pi-subagents/src/extension/config.ts +12 -0
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +40 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +104 -14
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +5 -0
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +3 -9
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +2 -2
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -1
- package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +4 -7
- package/dist/extensions/pi-subagents/src/missions/store.ts +4 -4
- package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +6 -2
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +374 -0
- package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +9 -5
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +117 -29
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -1
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +14 -5
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +33 -15
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +104 -0
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +17 -3
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +19 -1
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +84 -36
- package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +37 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +135 -22
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +12 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +7 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +171 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +653 -196
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +13 -4
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +286 -0
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +23 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +44 -1
- package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +280 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +4 -2
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +19 -3
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +17 -5
- package/dist/extensions/pi-subagents/src/shared/session-lineage.ts +71 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +108 -0
- package/dist/extensions/pi-subagents/src/shared/utils.ts +3 -1
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +7 -5
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +226 -13
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +22 -5
- package/dist/extensions/pi-subagents/src/workflows/workflow-auto-relaunch.ts +28 -0
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +87 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +96 -6
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +28 -5
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +8 -5
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +83 -2
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +211 -15
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +41 -3
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +314 -10
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +31 -1
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +317 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +21 -2
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +16 -1
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +6 -1
- package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +75 -4
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +29 -1
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +31 -5
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +139 -1
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/handoff-adoption.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +2 -1
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +171 -0
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +30 -4
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/owned-process-tree.test.ts +69 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +83 -0
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +55 -2
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +12 -1
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +7 -7
- package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +9 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +4 -3
- package/dist/extensions/pi-subagents/test/unit/session-lineage.test.ts +73 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +10 -1
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +39 -0
- package/dist/extensions/pi-subagents/test/unit/timeout-defaults.test.ts +65 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-auto-relaunch.test.ts +45 -0
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +61 -0
- package/dist/extensions/ponytail/index.js +11 -0
- package/dist/extensions/ponytail/ponytail-config.cjs +2 -0
- package/dist/extensions/ponytail/ponytail-instructions.cjs +6 -0
- package/dist/extensions/ponytail/test/extension.test.js +274 -140
- package/dist/extensions/ponytail/test/helpers.test.js +280 -92
- package/dist/extensions/question/index.ts +18 -0
- package/dist/extensions/question/question-list.ts +22 -0
- package/dist/extensions/question/tests/batch.test.ts +103 -65
- package/dist/extensions/question/tests/helpers.test.ts +68 -35
- package/dist/extensions/question/tests/question-list.test.ts +506 -204
- package/dist/extensions/question/tests/row-layout.test.ts +180 -114
- package/dist/extensions/question/tests/schemas.test.ts +42 -19
- package/dist/extensions/question/tests/shortcuts.test.ts +106 -84
- package/dist/extensions/question/tests/wizard.test.ts +771 -50
- package/dist/extensions/rtk.test.ts +180 -1
- package/dist/extensions/tokenin-onboarding.ts +3 -0
- package/dist/extensions/undo.test.ts +720 -0
- package/dist/extensions/undo.ts +6 -0
- package/dist/extensions/web-agent-onboarding.test.ts +415 -0
- package/dist/extensions/workflow/extension.ts +3 -3
- package/dist/extensions/workflow/modes.ts +41 -19
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.js +48 -1
- package/dist/skills/pi-subagents/references/execution-controls.md +1 -1
- package/docs/plans/workflow-autoloop-reference.md +1 -2
- package/docs/plans/workflow-handoff-carryover.md +108 -0
- package/docs/quickstart.md +27 -43
- package/docs/settings.md +4 -0
- package/docs/usage.md +1 -0
- package/package.json +5 -1
|
@@ -25,11 +25,14 @@ import {
|
|
|
25
25
|
type LaunchResolvedChildExtensionsV1,
|
|
26
26
|
type RuntimeAcknowledgedChildExtensionsV1,
|
|
27
27
|
type ModelAttempt,
|
|
28
|
+
type PiWriterProcessInstanceExitV1,
|
|
29
|
+
type ProcessTreeTerminalV1,
|
|
28
30
|
type NestedRouteInfo,
|
|
29
31
|
type NestedRunSummary,
|
|
30
32
|
type ResolvedControlConfig,
|
|
31
33
|
type ResolvedTurnBudget,
|
|
32
34
|
type ResolvedToolBudget,
|
|
35
|
+
type RunFanoutBudgetDescriptor,
|
|
33
36
|
type SubagentRunMode,
|
|
34
37
|
type SubagentOutputState,
|
|
35
38
|
type UsageBudgetConfig,
|
|
@@ -68,15 +71,16 @@ import {
|
|
|
68
71
|
DEFAULT_GLOBAL_CONCURRENCY_LIMIT,
|
|
69
72
|
Semaphore,
|
|
70
73
|
} from "../shared/parallel-utils.ts";
|
|
71
|
-
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan } from "../shared/pi-args.ts";
|
|
74
|
+
import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
|
|
72
75
|
import { readRuntimeAcknowledgedExtensions } from "../shared/runtime-acknowledged-extensions.ts";
|
|
73
76
|
import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.ts";
|
|
74
77
|
import { createStructuredOutputRuntime, MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput } from "../shared/structured-output.ts";
|
|
75
78
|
import { formatProcessSignalError, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
|
|
76
79
|
import { readChildToolDiagnosticError } from "../shared/tool-availability.ts";
|
|
77
80
|
import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection } from "../shared/dynamic-fanout.ts";
|
|
81
|
+
import { claimRunFanoutBatch, getRunFanoutBudgetSnapshot } from "../shared/run-fanout-budget.ts";
|
|
78
82
|
import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent } from "../shared/nested-events.ts";
|
|
79
|
-
import { formatModelAttemptNote, isRetryableModelFailure } from "../shared/model-fallback.ts";
|
|
83
|
+
import { formatModelAttemptNote, formatModelRetryNote, isRetryableModelFailure, MODEL_RETRY_DELAYS_MS } from "../shared/model-fallback.ts";
|
|
80
84
|
import {
|
|
81
85
|
SUBAGENT_STARTUP_RETRY_DELAYS_MS,
|
|
82
86
|
formatSubagentStartupRetryExhaustedError,
|
|
@@ -85,9 +89,10 @@ import {
|
|
|
85
89
|
waitForSubagentStartupRetry,
|
|
86
90
|
} from "../shared/subagent-startup-retry.ts";
|
|
87
91
|
import { markProcessTerminalCandidateLeaseRelease, writeProcessTerminalCandidate, type ProcessTerminalCandidate } from "./process-terminal.ts";
|
|
92
|
+
import { createOwnedProcessTreeController, type OwnedProcessTreeController } from "./owned-process-tree.ts";
|
|
88
93
|
import { createSteeringStatus, recordSteeringRequest, steeringStatus, terminalSteeringNoticeState, updateSteeringTarget } from "./steering.ts";
|
|
89
94
|
import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
|
|
90
|
-
import { detectSubagentError, extractTextFromContent, extractToolArgsPreview, getFinalOutput, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.ts";
|
|
95
|
+
import { PROMPT_REDACTED, detectSubagentError, extractTextFromContent, extractToolArgsPreview, getFinalOutput, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.ts";
|
|
91
96
|
import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
|
|
92
97
|
import {
|
|
93
98
|
createMutatingFailureState,
|
|
@@ -177,6 +182,7 @@ interface SubagentRunConfig {
|
|
|
177
182
|
/** Global cap on simultaneously-running subagent tasks within this run. */
|
|
178
183
|
globalConcurrencyLimit?: number;
|
|
179
184
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
185
|
+
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
180
186
|
launchContractDigest?: string;
|
|
181
187
|
launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
|
|
182
188
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
|
|
@@ -232,7 +238,7 @@ interface StepResult {
|
|
|
232
238
|
structuredOutputSchemaPath?: string;
|
|
233
239
|
acceptance?: import("../../shared/types.ts").AcceptanceLedger;
|
|
234
240
|
watchdog?: import("../../shared/types.ts").ChildWatchdogProgress;
|
|
235
|
-
writerProcesses?:
|
|
241
|
+
writerProcesses?: PiWriterProcessInstanceExitV1[];
|
|
236
242
|
writerAttemptCount?: number;
|
|
237
243
|
runner?: ExternalCliRunnerStatus;
|
|
238
244
|
externalProcess?: ExternalProcessStatus;
|
|
@@ -512,6 +518,7 @@ interface RunPiStreamingResult {
|
|
|
512
518
|
processInstanceId: string;
|
|
513
519
|
processCloseObservedAt?: number;
|
|
514
520
|
processSignal?: string | null;
|
|
521
|
+
processTree: ProcessTreeTerminalV1;
|
|
515
522
|
}
|
|
516
523
|
|
|
517
524
|
function runPiStreaming(
|
|
@@ -548,7 +555,9 @@ function runPiStreaming(
|
|
|
548
555
|
stdio: ["ignore", "pipe", "pipe"],
|
|
549
556
|
env: spawnEnv,
|
|
550
557
|
windowsHide: true,
|
|
558
|
+
detached: process.platform !== "win32",
|
|
551
559
|
});
|
|
560
|
+
let processTreeController: OwnedProcessTreeController | undefined;
|
|
552
561
|
const stderrTail = createBoundedByteTail();
|
|
553
562
|
const rawStdoutTail = createBoundedByteTail();
|
|
554
563
|
const messages: Message[] = [];
|
|
@@ -556,6 +565,7 @@ function runPiStreaming(
|
|
|
556
565
|
let model: string | undefined;
|
|
557
566
|
let writerRegistrationError: string | undefined;
|
|
558
567
|
if (typeof child.pid === "number") {
|
|
568
|
+
processTreeController = createOwnedProcessTreeController(child.pid);
|
|
559
569
|
try {
|
|
560
570
|
onWriterProcess?.({ state: "running", pid: child.pid });
|
|
561
571
|
} catch (writerError) {
|
|
@@ -703,7 +713,6 @@ function runPiStreaming(
|
|
|
703
713
|
// a lingering stdio holder after `exit`, or a child that never exits.
|
|
704
714
|
const FINAL_STOP_GRACE_MS = 1000;
|
|
705
715
|
const HARD_KILL_MS = 3000;
|
|
706
|
-
const TIMEOUT_HARD_KILL_MS = 3000;
|
|
707
716
|
let childExited = false;
|
|
708
717
|
let forcedTerminationSignal = false;
|
|
709
718
|
let cleanTerminalAssistantStopReceived = false;
|
|
@@ -711,7 +720,6 @@ function runPiStreaming(
|
|
|
711
720
|
let finalDrainTimer: NodeJS.Timeout | undefined;
|
|
712
721
|
let finalHardKillTimer: NodeJS.Timeout | undefined;
|
|
713
722
|
let watchdogTailTimer: NodeJS.Timeout | undefined;
|
|
714
|
-
let timeoutHardKillTimer: NodeJS.Timeout | undefined;
|
|
715
723
|
let turnBudgetTerminationTimer: NodeJS.Timeout | undefined;
|
|
716
724
|
let turnBudgetHardKillTimer: NodeJS.Timeout | undefined;
|
|
717
725
|
let protocolHardKillTimer: NodeJS.Timeout | undefined;
|
|
@@ -776,22 +784,16 @@ function runPiStreaming(
|
|
|
776
784
|
timedOut = true;
|
|
777
785
|
interrupted = false;
|
|
778
786
|
error = timeoutMessage ?? "Subagent timed out.";
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
if (!settled) trySignalChild(child, "SIGKILL");
|
|
782
|
-
}, TIMEOUT_HARD_KILL_MS);
|
|
783
|
-
timeoutHardKillTimer.unref?.();
|
|
787
|
+
if (processTreeController) void processTreeController.terminate();
|
|
788
|
+
else trySignalChild(child, "SIGTERM");
|
|
784
789
|
});
|
|
785
790
|
registerStop?.(() => {
|
|
786
791
|
if (settled || timedOut || stopped) return;
|
|
787
792
|
stopped = true;
|
|
788
793
|
interrupted = false;
|
|
789
794
|
error = stopMessage ?? "Subagent stopped by user.";
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
if (!settled) trySignalChild(child, "SIGKILL");
|
|
793
|
-
}, TIMEOUT_HARD_KILL_MS);
|
|
794
|
-
timeoutHardKillTimer.unref?.();
|
|
795
|
+
if (processTreeController) void processTreeController.terminate();
|
|
796
|
+
else trySignalChild(child, "SIGTERM");
|
|
795
797
|
});
|
|
796
798
|
registerTurnBudgetAbort?.((message, state) => {
|
|
797
799
|
if (settled || timedOut || stopped || turnBudgetExceeded) return;
|
|
@@ -820,10 +822,6 @@ function runPiStreaming(
|
|
|
820
822
|
finalHardKillTimer = undefined;
|
|
821
823
|
}
|
|
822
824
|
clearWatchdogTailTimer();
|
|
823
|
-
if (timeoutHardKillTimer) {
|
|
824
|
-
clearTimeout(timeoutHardKillTimer);
|
|
825
|
-
timeoutHardKillTimer = undefined;
|
|
826
|
-
}
|
|
827
825
|
if (turnBudgetTerminationTimer) {
|
|
828
826
|
clearTimeout(turnBudgetTerminationTimer);
|
|
829
827
|
turnBudgetTerminationTimer = undefined;
|
|
@@ -885,9 +883,12 @@ function runPiStreaming(
|
|
|
885
883
|
childExited = true;
|
|
886
884
|
clearDrainTimers();
|
|
887
885
|
});
|
|
888
|
-
child.on("close", (exitCode, signal) => {
|
|
886
|
+
child.on("close", async (exitCode, signal) => {
|
|
889
887
|
settled = true;
|
|
890
888
|
const processCloseObservedAt = Date.now();
|
|
889
|
+
const processTree = processTreeController
|
|
890
|
+
? await processTreeController.finishAfterWriterClose()
|
|
891
|
+
: { state: "unknown" as const, reason: "verification-failed" as const, diagnostic: "Writer PID was unavailable." };
|
|
891
892
|
try {
|
|
892
893
|
onWriterProcess?.({ state: "none" });
|
|
893
894
|
} catch {
|
|
@@ -939,6 +940,7 @@ function runPiStreaming(
|
|
|
939
940
|
processInstanceId,
|
|
940
941
|
processCloseObservedAt,
|
|
941
942
|
processSignal: signal,
|
|
943
|
+
processTree,
|
|
942
944
|
}));
|
|
943
945
|
});
|
|
944
946
|
|
|
@@ -961,7 +963,7 @@ function runPiStreaming(
|
|
|
961
963
|
const stderr = stderrTail.text();
|
|
962
964
|
const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
|
|
963
965
|
const spawnErrorMessage = spawnError instanceof Error ? spawnError.message : String(spawnError);
|
|
964
|
-
resolve(omitUndefinedProperties({ stderr, exitCode: 1, messages, usage, toolCount, durationMs: Date.now() - startedAt, model, error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : error ?? assistantError ?? spawnErrorMessage, protocolError, finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput, outputState: finalOutput.trim() ? "present" : "absent", timedOut, stopped, turnBudget, turnBudgetExceeded, wrapUpRequested: turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined, observedMutationAttempt, structuredOutputToolInvoked, structuredOutputMessageStartIndex, watchdog: childWatchdogState, processInstanceId }));
|
|
966
|
+
resolve(omitUndefinedProperties({ stderr, exitCode: 1, messages, usage, toolCount, durationMs: Date.now() - startedAt, model, error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : error ?? assistantError ?? spawnErrorMessage, protocolError, finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput, outputState: finalOutput.trim() ? "present" : "absent", timedOut, stopped, turnBudget, turnBudgetExceeded, wrapUpRequested: turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined, observedMutationAttempt, structuredOutputToolInvoked, structuredOutputMessageStartIndex, watchdog: childWatchdogState, processInstanceId, processTree: { state: "unknown", reason: "verification-failed", diagnostic: spawnErrorMessage } }));
|
|
965
967
|
});
|
|
966
968
|
});
|
|
967
969
|
}
|
|
@@ -1105,6 +1107,7 @@ interface SingleStepContext {
|
|
|
1105
1107
|
orchestratorIntercomTarget?: string;
|
|
1106
1108
|
nestedRoute?: NestedRouteInfo;
|
|
1107
1109
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1110
|
+
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
1108
1111
|
onAttemptStart?: (attempt: { model?: string; thinking?: string }) => void;
|
|
1109
1112
|
onChildEvent?: (event: ChildEvent) => void;
|
|
1110
1113
|
onWriterProcess?: (writer: { state: "none" | "spawning" } | { state: "running"; pid: number }) => void;
|
|
@@ -1206,7 +1209,7 @@ async function runSingleStep(
|
|
|
1206
1209
|
artifactPaths = getArtifactPaths(ctx.artifactsDir, ctx.id, step.agent, index);
|
|
1207
1210
|
fs.mkdirSync(ctx.artifactsDir, { recursive: true });
|
|
1208
1211
|
if (ctx.artifactConfig?.includeInput !== false) {
|
|
1209
|
-
fs.writeFileSync(artifactPaths.inputPath, `# Task for ${step.agent}\n\n${
|
|
1212
|
+
fs.writeFileSync(artifactPaths.inputPath, `# Task for ${step.agent}\n\n${PROMPT_REDACTED}; live Prompt Audit only.\n`, "utf-8");
|
|
1210
1213
|
}
|
|
1211
1214
|
if (ctx.artifactConfig?.includeTranscript !== false) {
|
|
1212
1215
|
transcriptWriter = createChildTranscriptWriter({
|
|
@@ -1219,7 +1222,7 @@ async function runSingleStep(
|
|
|
1219
1222
|
});
|
|
1220
1223
|
}
|
|
1221
1224
|
}
|
|
1222
|
-
transcriptWriter?.writeInitialUserMessage(
|
|
1225
|
+
transcriptWriter?.writeInitialUserMessage(`${PROMPT_REDACTED}; live Prompt Audit only.`);
|
|
1223
1226
|
|
|
1224
1227
|
if (step.runner?.type === "external-cli") {
|
|
1225
1228
|
const runner: ExternalCliRunnerStatus = {
|
|
@@ -1262,7 +1265,7 @@ async function runSingleStep(
|
|
|
1262
1265
|
artifactPaths,
|
|
1263
1266
|
artifactConfig: ctx.artifactConfig,
|
|
1264
1267
|
output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, error: external.error, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })),
|
|
1265
|
-
metadata: { runId: ctx.id, agent: step.agent, task, runner, externalProcess: external.externalProcess, exitCode: external.exitCode, error: external.error, timestamp: Date.now() },
|
|
1268
|
+
metadata: { runId: ctx.id, agent: step.agent, task: PROMPT_REDACTED, runner, externalProcess: external.externalProcess, exitCode: external.exitCode, error: external.error, timestamp: Date.now() },
|
|
1266
1269
|
})
|
|
1267
1270
|
: {};
|
|
1268
1271
|
return omitUndefinedProperties({
|
|
@@ -1292,7 +1295,7 @@ async function runSingleStep(
|
|
|
1292
1295
|
let capabilityAudit: import("../shared/capability-ceiling.ts").SubagentCapabilityAudit | undefined;
|
|
1293
1296
|
let launchResolvedExtensions = step.launchResolvedExtensions;
|
|
1294
1297
|
const modelAttempts: ModelAttempt[] = [];
|
|
1295
|
-
const writerProcesses:
|
|
1298
|
+
const writerProcesses: PiWriterProcessInstanceExitV1[] = [];
|
|
1296
1299
|
let writerAttemptCount = 0;
|
|
1297
1300
|
const attemptNotes: string[] = [];
|
|
1298
1301
|
const eventsPath = path.join(path.dirname(ctx.outputFile), "events.jsonl");
|
|
@@ -1306,6 +1309,10 @@ async function runSingleStep(
|
|
|
1306
1309
|
|
|
1307
1310
|
let modelIndex = 0;
|
|
1308
1311
|
let startupAttemptIndex = 0;
|
|
1312
|
+
let modelRetryIndex = 0;
|
|
1313
|
+
// Escalated to "file" after an unexplained zero-activity startup failure so
|
|
1314
|
+
// retries keep the task text out of argv (endpoint pre-exec scans may deny it).
|
|
1315
|
+
let taskDeliveryOverride: SubagentTaskDelivery | undefined;
|
|
1309
1316
|
modelAttemptsLoop: while (modelIndex < candidates.length) {
|
|
1310
1317
|
if (ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
|
|
1311
1318
|
const candidate = candidates[modelIndex];
|
|
@@ -1331,6 +1338,7 @@ async function runSingleStep(
|
|
|
1331
1338
|
parentSessionId: step.parentSessionId,
|
|
1332
1339
|
baseArgs: ["--mode", "json", "-p"],
|
|
1333
1340
|
task,
|
|
1341
|
+
taskDelivery: taskDeliveryOverride,
|
|
1334
1342
|
sessionEnabled,
|
|
1335
1343
|
sessionDir,
|
|
1336
1344
|
sessionFile: step.sessionFile,
|
|
@@ -1356,6 +1364,10 @@ async function runSingleStep(
|
|
|
1356
1364
|
parentControlInbox: ctx.nestedRoute?.controlInbox,
|
|
1357
1365
|
parentRootRunId: ctx.nestedRoute?.rootRunId,
|
|
1358
1366
|
parentCapabilityToken: ctx.nestedRoute?.capabilityToken,
|
|
1367
|
+
runFanoutBudget: ctx.runFanoutBudget ? {
|
|
1368
|
+
...ctx.runFanoutBudget,
|
|
1369
|
+
...(step.runFanoutPath ? { parentPath: `${ctx.runFanoutBudget.parentPath ? `${ctx.runFanoutBudget.parentPath}/` : ""}${step.runFanoutPath}` } : {}),
|
|
1370
|
+
} : undefined,
|
|
1359
1371
|
steerInboxDir: ctx.steerInboxDir,
|
|
1360
1372
|
steerCapabilityPath: ctx.steerCapabilityPath,
|
|
1361
1373
|
steerAckDir: ctx.steerAckDir,
|
|
@@ -1429,6 +1441,7 @@ async function runSingleStep(
|
|
|
1429
1441
|
closeObservedAt: run.processCloseObservedAt,
|
|
1430
1442
|
exitCode: run.exitCode,
|
|
1431
1443
|
signal: run.processSignal ?? null,
|
|
1444
|
+
processTree: run.processTree,
|
|
1432
1445
|
});
|
|
1433
1446
|
}
|
|
1434
1447
|
if (run.turnBudget) turnBudget = run.turnBudget;
|
|
@@ -1583,6 +1596,10 @@ async function runSingleStep(
|
|
|
1583
1596
|
});
|
|
1584
1597
|
const shouldRetry = await waitForSubagentStartupRetry(retryDelayMs, [ctx.timeoutSignal, ctx.stopSignal]);
|
|
1585
1598
|
if (!shouldRetry || ctx.skipAcceptance?.()) break modelAttemptsLoop;
|
|
1599
|
+
if (!taskDeliveryOverride && run.processSignal === "SIGKILL") {
|
|
1600
|
+
taskDeliveryOverride = "file";
|
|
1601
|
+
attemptNotes.push("[startup-retry] retrying with file task delivery to keep the task text out of the child process argv.");
|
|
1602
|
+
}
|
|
1586
1603
|
attempt.error = retryNote;
|
|
1587
1604
|
attemptNotes.push(retryNote);
|
|
1588
1605
|
startupAttemptIndex += 1;
|
|
@@ -1598,10 +1615,32 @@ async function runSingleStep(
|
|
|
1598
1615
|
finalResult.finalOutput = startupError;
|
|
1599
1616
|
break modelAttemptsLoop;
|
|
1600
1617
|
}
|
|
1601
|
-
if (
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1618
|
+
if (isRetryableModelFailure(error)) {
|
|
1619
|
+
if (modelIndex < candidates.length - 1) {
|
|
1620
|
+
attemptNotes.push(formatModelAttemptNote(attempt, candidates[modelIndex + 1]));
|
|
1621
|
+
modelIndex += 1;
|
|
1622
|
+
modelRetryIndex = 0;
|
|
1623
|
+
startupAttemptIndex = 0;
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
const modelRetryDelayMs = MODEL_RETRY_DELAYS_MS[modelRetryIndex];
|
|
1627
|
+
if (modelRetryDelayMs !== undefined) {
|
|
1628
|
+
const retryNote = formatModelRetryNote({
|
|
1629
|
+
model: attempt.model,
|
|
1630
|
+
attempt: modelRetryIndex + 1,
|
|
1631
|
+
maxAttempts: MODEL_RETRY_DELAYS_MS.length + 1,
|
|
1632
|
+
delayMs: modelRetryDelayMs,
|
|
1633
|
+
});
|
|
1634
|
+
const shouldRetry = await waitForSubagentStartupRetry(modelRetryDelayMs, [ctx.timeoutSignal, ctx.stopSignal]);
|
|
1635
|
+
if (!shouldRetry || ctx.skipAcceptance?.()) break modelAttemptsLoop;
|
|
1636
|
+
attempt.error = retryNote;
|
|
1637
|
+
attemptNotes.push(retryNote);
|
|
1638
|
+
modelRetryIndex += 1;
|
|
1639
|
+
startupAttemptIndex = 0;
|
|
1640
|
+
continue;
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
break modelAttemptsLoop;
|
|
1605
1644
|
}
|
|
1606
1645
|
|
|
1607
1646
|
const rawOutput = finalResult?.finalOutput ?? "";
|
|
@@ -1700,7 +1739,7 @@ async function runSingleStep(
|
|
|
1700
1739
|
metadata: {
|
|
1701
1740
|
runId: ctx.id,
|
|
1702
1741
|
agent: step.agent,
|
|
1703
|
-
task,
|
|
1742
|
+
task: PROMPT_REDACTED,
|
|
1704
1743
|
exitCode: effectiveFinalExitCode,
|
|
1705
1744
|
model: finalResult?.model,
|
|
1706
1745
|
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
@@ -2171,6 +2210,7 @@ async function runSubagent(
|
|
|
2171
2210
|
...(config.launchContractDigest ? { launchContractDigest: config.launchContractDigest } : {}),
|
|
2172
2211
|
...(config.launchResolvedExtensions ? { launchResolvedExtensions: config.launchResolvedExtensions } : {}),
|
|
2173
2212
|
...(config.capabilityCeiling ? { capabilityCeiling: config.capabilityCeiling } : {}),
|
|
2213
|
+
...(config.runFanoutBudget ? { runFanoutBudget: getRunFanoutBudgetSnapshot(config.runFanoutBudget) } : {}),
|
|
2174
2214
|
...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
|
|
2175
2215
|
...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
|
|
2176
2216
|
...(config.runnerProcessInstanceId ? { processTerminal: { version: 1 as const, state: "pending" as const, runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId } } : {}),
|
|
@@ -2260,10 +2300,10 @@ async function runSubagent(
|
|
|
2260
2300
|
refreshWorkflowGraph();
|
|
2261
2301
|
writeAtomicJson(statusPath, statusPayload);
|
|
2262
2302
|
const activeState = isActiveAsyncState(statusPayload.state);
|
|
2263
|
-
if (activeState !== lastIndexedActiveState) {
|
|
2303
|
+
if (activeState && activeState !== lastIndexedActiveState) {
|
|
2264
2304
|
updateActiveRunIndex(asyncDir, statusPayload.state);
|
|
2265
|
-
lastIndexedActiveState = activeState;
|
|
2266
2305
|
}
|
|
2306
|
+
lastIndexedActiveState = activeState;
|
|
2267
2307
|
emitNestedSelfEvent(statusPayload.state === "running" || statusPayload.state === "queued" ? "subagent.nested.updated" : "subagent.nested.completed");
|
|
2268
2308
|
};
|
|
2269
2309
|
const statusWriteCoalescer = createFileCoalescer(writeStatusPayloadNow, 100);
|
|
@@ -3035,7 +3075,6 @@ async function runSubagent(
|
|
|
3035
3075
|
if (stopped || timedOut || interrupted || statusPayload.state !== "running") return;
|
|
3036
3076
|
stopped = true;
|
|
3037
3077
|
const now = Date.now();
|
|
3038
|
-
statusPayload.state = "stopped";
|
|
3039
3078
|
statusPayload.stopped = true;
|
|
3040
3079
|
statusPayload.error = stopMessage;
|
|
3041
3080
|
currentActivityState = undefined;
|
|
@@ -3068,7 +3107,6 @@ async function runSubagent(
|
|
|
3068
3107
|
timedOut = true;
|
|
3069
3108
|
const now = Date.now();
|
|
3070
3109
|
const message = timeoutMessage ?? "Subagent timed out.";
|
|
3071
|
-
statusPayload.state = "failed";
|
|
3072
3110
|
statusPayload.timedOut = true;
|
|
3073
3111
|
statusPayload.error = message;
|
|
3074
3112
|
currentActivityState = undefined;
|
|
@@ -3258,6 +3296,9 @@ async function runSubagent(
|
|
|
3258
3296
|
throw new DynamicFanoutError(`Dynamic chain step ${stepIndex + 1} materialized ${materialized.parallel.length} items that resolve output to the same path: ${step.parallel.outputPath}. Remove the explicit output path or use an inherited relative agent output so each item can be isolated.`);
|
|
3259
3297
|
}
|
|
3260
3298
|
if (materialized.collectedOnEmpty) await validateDynamicCollection(step.collect.outputSchema, materialized.collectedOnEmpty);
|
|
3299
|
+
if (!config.runFanoutBudget) throw new Error("Async runner is missing its run fan-out budget identity.");
|
|
3300
|
+
const runFanoutBudget = claimRunFanoutBatch(config.runFanoutBudget, materialized.parallel.map((_, itemIndex) => `chain[${stepIndex}].expand[${itemIndex}]`));
|
|
3301
|
+
statusPayload.runFanoutBudget = runFanoutBudget;
|
|
3261
3302
|
} catch (error) {
|
|
3262
3303
|
const now = Date.now();
|
|
3263
3304
|
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
@@ -3364,6 +3405,7 @@ async function runSubagent(
|
|
|
3364
3405
|
const materializedTask = step.parallel.namespaceOutputPath ? injectSingleOutputInstruction(taskText, outputPath, step.parallel) : taskText;
|
|
3365
3406
|
return omitUndefinedProperties({
|
|
3366
3407
|
...step.parallel,
|
|
3408
|
+
runFanoutPath: `chain[${stepIndex}].expand[${itemIndex}]`,
|
|
3367
3409
|
task: materializedTask,
|
|
3368
3410
|
effectiveAcceptance: resolveEffectiveAcceptance(omitUndefinedProperties({
|
|
3369
3411
|
explicit: step.parallel.acceptanceInput,
|
|
@@ -3523,6 +3565,7 @@ async function runSubagent(
|
|
|
3523
3565
|
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
3524
3566
|
nestedRoute: config.nestedRoute,
|
|
3525
3567
|
capabilityCeiling: config.capabilityCeiling,
|
|
3568
|
+
runFanoutBudget: config.runFanoutBudget,
|
|
3526
3569
|
registerInterrupt: (interrupt) => registerStepInterrupt(fi, interrupt),
|
|
3527
3570
|
registerTimeout: (interrupt) => registerStepTimeout(fi, interrupt),
|
|
3528
3571
|
registerStop: (stop) => registerStepStop(fi, stop),
|
|
@@ -3905,6 +3948,7 @@ async function runSubagent(
|
|
|
3905
3948
|
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
3906
3949
|
nestedRoute: config.nestedRoute,
|
|
3907
3950
|
capabilityCeiling: config.capabilityCeiling,
|
|
3951
|
+
runFanoutBudget: config.runFanoutBudget,
|
|
3908
3952
|
registerInterrupt: (interrupt) => registerStepInterrupt(fi, interrupt),
|
|
3909
3953
|
registerTimeout: (interrupt) => registerStepTimeout(fi, interrupt),
|
|
3910
3954
|
registerStop: (stop) => registerStepStop(fi, stop),
|
|
@@ -4194,6 +4238,7 @@ async function runSubagent(
|
|
|
4194
4238
|
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
4195
4239
|
nestedRoute: config.nestedRoute,
|
|
4196
4240
|
capabilityCeiling: config.capabilityCeiling,
|
|
4241
|
+
runFanoutBudget: config.runFanoutBudget,
|
|
4197
4242
|
registerInterrupt: (interrupt) => registerStepInterrupt(flatIndex, interrupt),
|
|
4198
4243
|
registerTimeout: (interrupt) => registerStepTimeout(flatIndex, interrupt),
|
|
4199
4244
|
registerStop: (stop) => registerStepStop(flatIndex, stop),
|
|
@@ -4438,6 +4483,9 @@ async function runSubagent(
|
|
|
4438
4483
|
clearTimeout(timeoutTimer);
|
|
4439
4484
|
timeoutTimer = undefined;
|
|
4440
4485
|
}
|
|
4486
|
+
if (!timedOut && !stopped && !interrupted && config.timeoutMs !== undefined && results.some((result) => result.timedOut === true && result.error === timeoutMessage)) {
|
|
4487
|
+
timedOut = true;
|
|
4488
|
+
}
|
|
4441
4489
|
const signalTerminated = !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
|
|
4442
4490
|
processSignal: result.processSignal,
|
|
4443
4491
|
interrupted: result.interrupted,
|
|
@@ -4630,7 +4678,7 @@ async function runSubagent(
|
|
|
4630
4678
|
shareError,
|
|
4631
4679
|
}));
|
|
4632
4680
|
if (config.runnerProcessInstanceId) {
|
|
4633
|
-
const writers: Record<string,
|
|
4681
|
+
const writers: Record<string, PiWriterProcessInstanceExitV1[]> = {};
|
|
4634
4682
|
const expectedWriters: Record<string, number> = {};
|
|
4635
4683
|
for (const [index, result] of results.entries()) {
|
|
4636
4684
|
writers[String(index)] = result.writerProcesses ?? [];
|
|
@@ -245,7 +245,8 @@ export function createWaitSubscriptionManager(
|
|
|
245
245
|
try {
|
|
246
246
|
const record = parseRecord(JSON.parse(fs.readFileSync(path.join(subscriptionsDir, file), "utf-8")));
|
|
247
247
|
if (!record || file !== `${record.token}.json`) continue;
|
|
248
|
-
|
|
248
|
+
const acceptedSessions = new Set(state.sessionLineage?.length ? state.sessionLineage : [state.currentSessionId]);
|
|
249
|
+
if (acceptedSessions.has(record.sessionId)) {
|
|
249
250
|
subscriptions.set(record.token, record);
|
|
250
251
|
if (record.targetKind === "foreground" && !state.foregroundRuns?.has(record.runId)) unresolvedRestoredForegroundTokens.add(record.token);
|
|
251
252
|
}
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
import { discoverAvailableSkills, normalizeSkillInput } from "../../agents/skills.ts";
|
|
35
35
|
import { INTERCOM_BRIDGE_MARKER } from "../../intercom/intercom-bridge.ts";
|
|
36
36
|
import { runSync } from "./execution.ts";
|
|
37
|
+
import { createTaskMutationArbiter } from "../shared/llm-intent-arbiter.ts";
|
|
37
38
|
import { workflowForegroundSteeringLaunchOptions } from "./workflow-foreground-steering.ts";
|
|
38
39
|
import {
|
|
39
40
|
beginForegroundChild,
|
|
@@ -42,6 +43,7 @@ import {
|
|
|
42
43
|
settleForegroundSchedulingOwner,
|
|
43
44
|
updateForegroundChild,
|
|
44
45
|
} from "./foreground-control.ts";
|
|
46
|
+
import { updateLiveEffectivePrompt } from "./prompt-audit.ts";
|
|
45
47
|
import { buildChainSummary } from "../../shared/formatters.ts";
|
|
46
48
|
import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, resolveChildCwd, sumResultsCost, sumResultsUsage } from "../../shared/utils.ts";
|
|
47
49
|
import { DEFAULT_GLOBAL_CONCURRENCY_LIMIT, Semaphore } from "../shared/parallel-utils.ts";
|
|
@@ -71,6 +73,7 @@ import {
|
|
|
71
73
|
type ResolvedControlConfig,
|
|
72
74
|
type ResolvedTurnBudget,
|
|
73
75
|
type ResolvedToolBudget,
|
|
76
|
+
type RunFanoutBudgetDescriptor,
|
|
74
77
|
type SingleResult,
|
|
75
78
|
type ToolBudgetConfig,
|
|
76
79
|
type ChainCheckpointState,
|
|
@@ -86,6 +89,7 @@ import { ChainOutputValidationError, outputEntryFromResult, resolveOutputReferen
|
|
|
86
89
|
import { createStructuredOutputRuntime } from "../shared/structured-output.ts";
|
|
87
90
|
import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection, type DynamicCollectedResult } from "../shared/dynamic-fanout.ts";
|
|
88
91
|
import { acceptanceFailureMessage, aggregateAcceptanceReport, evaluateAcceptance, resolveEffectiveAcceptance } from "../shared/acceptance.ts";
|
|
92
|
+
import { claimRunFanoutBatch, RunFanoutLimitError } from "../shared/run-fanout-budget.ts";
|
|
89
93
|
import { isAgentContractV1 } from "../shared/agent-contract.ts";
|
|
90
94
|
import type { ChainOutputMap } from "../../shared/types.ts";
|
|
91
95
|
import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
@@ -167,6 +171,7 @@ interface ParallelChainRunInput {
|
|
|
167
171
|
configToolBudget?: ToolBudgetConfig;
|
|
168
172
|
globalSemaphore?: Semaphore;
|
|
169
173
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
174
|
+
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
170
175
|
permissions?: PermissionConfig;
|
|
171
176
|
dynamic?: boolean;
|
|
172
177
|
}
|
|
@@ -368,7 +373,11 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
368
373
|
beginForegroundChild(input.foregroundControl, {
|
|
369
374
|
index: childIndex,
|
|
370
375
|
agent: task.agent,
|
|
371
|
-
|
|
376
|
+
authoredTask: cleanTask,
|
|
377
|
+
effectivePrompt: taskStr,
|
|
378
|
+
cwd: taskCwd,
|
|
379
|
+
...(outputPath ? { outputPath } : {}),
|
|
380
|
+
description: `${task.agent} child`,
|
|
372
381
|
...(effectiveModel ? { model: effectiveModel } : {}),
|
|
373
382
|
...(thinking ? { thinking } : {}),
|
|
374
383
|
interrupt: () => {
|
|
@@ -388,8 +397,10 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
388
397
|
result = await runSync(input.ctx.cwd, input.agents, task.agent, taskStr, {
|
|
389
398
|
permissions: input.permissions,
|
|
390
399
|
parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
|
|
400
|
+
llmIntentArbiter: createTaskMutationArbiter(input.ctx),
|
|
391
401
|
...workflowForegroundSteeringLaunchOptions(input.foregroundControl, childIndex),
|
|
392
402
|
capabilityCeiling: input.capabilityCeiling,
|
|
403
|
+
runFanoutBudget: input.runFanoutBudget ? { ...input.runFanoutBudget, parentPath: `${input.runFanoutBudget.parentPath ? `${input.runFanoutBudget.parentPath}/` : ""}chain[${input.stepIndex}]${input.dynamic ? `.expand[${taskIndex}]` : `.parallel[${taskIndex}]`}` } : undefined,
|
|
393
404
|
context: input.contextForAgent?.(task.agent),
|
|
394
405
|
cwd: taskCwd,
|
|
395
406
|
signal: input.signal,
|
|
@@ -422,6 +433,7 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
|
|
|
422
433
|
agentContract,
|
|
423
434
|
acceptance: task.acceptance,
|
|
424
435
|
acceptanceContext: { mode: "chain", dynamic: input.dynamic && task.acceptance === undefined },
|
|
436
|
+
onEffectivePrompt: input.foregroundControl ? (prompt) => updateLiveEffectivePrompt(input.foregroundControl!, childIndex, prompt) : undefined,
|
|
425
437
|
timeoutMs: input.timeoutMs,
|
|
426
438
|
deadlineAt: input.deadlineAt,
|
|
427
439
|
turnBudget: input.turnBudget,
|
|
@@ -540,6 +552,7 @@ interface ChainExecutionParams {
|
|
|
540
552
|
/** Global cap on simultaneously-running tasks within this chain. Defaults to DEFAULT_GLOBAL_CONCURRENCY_LIMIT. */
|
|
541
553
|
globalConcurrencyLimit?: number;
|
|
542
554
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
555
|
+
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
543
556
|
}
|
|
544
557
|
|
|
545
558
|
interface ChainExecutionResult {
|
|
@@ -876,6 +889,7 @@ ${step.message}` : ""}` }],
|
|
|
876
889
|
configToolBudget: params.configToolBudget,
|
|
877
890
|
globalSemaphore,
|
|
878
891
|
permissions: params.permissions,
|
|
892
|
+
runFanoutBudget: params.runFanoutBudget,
|
|
879
893
|
});
|
|
880
894
|
globalTaskIndex += step.parallel.length;
|
|
881
895
|
|
|
@@ -1002,6 +1016,19 @@ ${step.message}` : ""}` }],
|
|
|
1002
1016
|
return buildChainExecutionErrorResult(message, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
1003
1017
|
}
|
|
1004
1018
|
|
|
1019
|
+
try {
|
|
1020
|
+
if (params.runFanoutBudget) claimRunFanoutBatch(params.runFanoutBudget, materialized.parallel.map((_, itemIndex) => `chain[${stepIndex}].expand[${itemIndex}]`));
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1023
|
+
dynamicGroupStatuses[stepIndex] = { status: "failed", error: message };
|
|
1024
|
+
const result = buildChainExecutionErrorResult(message, makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex }));
|
|
1025
|
+
if (error instanceof RunFanoutLimitError) {
|
|
1026
|
+
result.details.runFanoutBudget = error.snapshot;
|
|
1027
|
+
result.details.runFanoutRejection = error.rejection;
|
|
1028
|
+
}
|
|
1029
|
+
return result;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1005
1032
|
dynamicChildren[stepIndex] = materialized.items.map((item, itemIndex) => ({
|
|
1006
1033
|
agent: step.parallel.agent,
|
|
1007
1034
|
label: materialized.parallel[itemIndex]?.label,
|
|
@@ -1137,6 +1164,7 @@ ${step.message}` : ""}` }],
|
|
|
1137
1164
|
configToolBudget: params.configToolBudget,
|
|
1138
1165
|
globalSemaphore,
|
|
1139
1166
|
permissions: params.permissions,
|
|
1167
|
+
runFanoutBudget: params.runFanoutBudget,
|
|
1140
1168
|
dynamic: true,
|
|
1141
1169
|
});
|
|
1142
1170
|
globalTaskIndex = dynamicStartIndex + reservedDynamicItems;
|
|
@@ -1332,7 +1360,11 @@ ${step.message}` : ""}` }],
|
|
|
1332
1360
|
beginForegroundChild(foregroundControl, {
|
|
1333
1361
|
index: childIndex,
|
|
1334
1362
|
agent: seqStep.agent,
|
|
1335
|
-
|
|
1363
|
+
authoredTask: cleanTask,
|
|
1364
|
+
effectivePrompt: stepTask,
|
|
1365
|
+
cwd,
|
|
1366
|
+
...(outputPath ? { outputPath } : {}),
|
|
1367
|
+
description: `${seqStep.agent} child`,
|
|
1336
1368
|
...(effectiveModel ? { model: effectiveModel } : {}),
|
|
1337
1369
|
...(thinking ? { thinking } : {}),
|
|
1338
1370
|
interrupt: () => {
|
|
@@ -1369,8 +1401,10 @@ ${step.message}` : ""}` }],
|
|
|
1369
1401
|
r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
|
|
1370
1402
|
permissions: params.permissions,
|
|
1371
1403
|
parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
|
|
1404
|
+
llmIntentArbiter: createTaskMutationArbiter(ctx),
|
|
1372
1405
|
...workflowForegroundSteeringLaunchOptions(params.foregroundControl, childIndex),
|
|
1373
1406
|
capabilityCeiling: params.capabilityCeiling,
|
|
1407
|
+
runFanoutBudget: params.runFanoutBudget ? { ...params.runFanoutBudget, parentPath: `${params.runFanoutBudget.parentPath ? `${params.runFanoutBudget.parentPath}/` : ""}chain[${stepIndex}]` } : undefined,
|
|
1374
1408
|
context: params.contextForAgent?.(seqStep.agent),
|
|
1375
1409
|
cwd: resolveChildCwd(cwd ?? ctx.cwd, seqStep.cwd),
|
|
1376
1410
|
signal,
|
|
@@ -1403,6 +1437,7 @@ ${step.message}` : ""}` }],
|
|
|
1403
1437
|
agentContract,
|
|
1404
1438
|
acceptance: seqStep.acceptance,
|
|
1405
1439
|
acceptanceContext: { mode: "chain" },
|
|
1440
|
+
onEffectivePrompt: foregroundControl ? (prompt) => updateLiveEffectivePrompt(foregroundControl, childIndex, prompt) : undefined,
|
|
1406
1441
|
timeoutMs: params.timeoutMs,
|
|
1407
1442
|
deadlineAt,
|
|
1408
1443
|
turnBudget: params.turnBudget,
|