pi-subagents 0.47.1 → 0.49.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 +51 -0
- package/README.md +2 -0
- package/docs/agents.md +1 -0
- package/docs/configuration.md +74 -7
- package/docs/missions.md +4 -2
- package/docs/observability.md +27 -3
- package/docs/tool-reference.md +1 -1
- package/package.json +1 -1
- package/src/agents/agents.ts +36 -15
- package/src/api/preflight.ts +1 -1
- package/src/extension/config.ts +26 -0
- package/src/extension/doctor.ts +40 -0
- package/src/extension/index.ts +39 -8
- package/src/extension/public-execution.ts +35 -4
- package/src/extension/rpc.ts +3 -9
- package/src/extension/schemas.ts +10 -9
- package/src/extension/tool-description.ts +10 -8
- package/src/inspectors/herdr/actions.ts +11 -2
- package/src/inspectors/herdr/inspector-runner.ts +16 -3
- package/src/intercom/intercom-bridge.ts +7 -2
- package/src/missions/lifecycle.ts +4 -7
- package/src/missions/store.ts +12 -7
- package/src/missions/workflow-state.ts +6 -2
- package/src/runs/background/active-async-capacity.ts +431 -0
- package/src/runs/background/active-run-index.ts +9 -5
- package/src/runs/background/async-execution.ts +141 -65
- package/src/runs/background/async-job-tracker.ts +4 -0
- package/src/runs/background/async-resume.ts +18 -2
- package/src/runs/background/async-status.ts +11 -5
- package/src/runs/background/chain-append.ts +33 -15
- package/src/runs/background/fleet-view.ts +18 -5
- package/src/runs/background/owned-process-tree.ts +104 -0
- package/src/runs/background/process-terminal.ts +17 -3
- package/src/runs/background/resume-guidance.ts +27 -7
- package/src/runs/background/retained-children.ts +14 -6
- package/src/runs/background/run-status.ts +101 -5
- package/src/runs/background/stale-run-reconciler.ts +3 -3
- package/src/runs/background/subagent-runner.ts +60 -32
- package/src/runs/foreground/chain-execution.ts +37 -2
- package/src/runs/foreground/execution.ts +90 -19
- package/src/runs/foreground/foreground-control.ts +12 -0
- package/src/runs/foreground/prompt-audit.ts +172 -0
- package/src/runs/foreground/subagent-executor.ts +829 -203
- package/src/runs/shared/acceptance.ts +13 -4
- package/src/runs/shared/completion-guard.ts +17 -1
- package/src/runs/shared/llm-intent-arbiter.ts +302 -0
- package/src/runs/shared/parallel-utils.ts +2 -0
- package/src/runs/shared/pi-args.ts +44 -1
- package/src/runs/shared/run-fanout-budget.ts +280 -0
- package/src/runs/shared/single-output.ts +4 -2
- package/src/runs/shared/task-intent.ts +19 -3
- package/src/runs/shared/worktree.ts +17 -5
- package/src/shared/agent-stream-options.ts +5 -0
- package/src/shared/artifacts.ts +2 -6
- package/src/shared/display-text.ts +50 -0
- package/src/shared/node-executable.ts +21 -0
- package/src/shared/types.ts +115 -4
- package/src/shared/utils.ts +3 -1
- package/src/tui/fleet-status.ts +7 -5
- package/src/tui/fleet-transcript.ts +1 -48
- package/src/tui/fleet.ts +228 -13
- package/src/tui/render.ts +86 -39
- package/src/watchdog/permission-arbiter.ts +2 -1
- package/src/watchdog/review.ts +4 -3
- package/src/workflows/chat-progress.ts +8 -2
- package/src/workflows/scripted-workflow.ts +66 -10
|
@@ -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,13 +71,14 @@ 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
83
|
import { formatModelAttemptNote, isRetryableModelFailure } from "../shared/model-fallback.ts";
|
|
80
84
|
import {
|
|
@@ -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,
|
|
@@ -138,6 +143,8 @@ import {
|
|
|
138
143
|
type ChildWatchdogStateSnapshot,
|
|
139
144
|
} from "../../watchdog/child-status.ts";
|
|
140
145
|
|
|
146
|
+
const INTERCOM_DETACH_RECEIPT = "Detached for intercom coordination before task completion.";
|
|
147
|
+
|
|
141
148
|
interface SubagentRunConfig {
|
|
142
149
|
id: string;
|
|
143
150
|
steps: RunnerStep[];
|
|
@@ -177,6 +184,7 @@ interface SubagentRunConfig {
|
|
|
177
184
|
/** Global cap on simultaneously-running subagent tasks within this run. */
|
|
178
185
|
globalConcurrencyLimit?: number;
|
|
179
186
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
187
|
+
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
180
188
|
launchContractDigest?: string;
|
|
181
189
|
launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
|
|
182
190
|
runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
|
|
@@ -232,7 +240,7 @@ interface StepResult {
|
|
|
232
240
|
structuredOutputSchemaPath?: string;
|
|
233
241
|
acceptance?: import("../../shared/types.ts").AcceptanceLedger;
|
|
234
242
|
watchdog?: import("../../shared/types.ts").ChildWatchdogProgress;
|
|
235
|
-
writerProcesses?:
|
|
243
|
+
writerProcesses?: PiWriterProcessInstanceExitV1[];
|
|
236
244
|
writerAttemptCount?: number;
|
|
237
245
|
runner?: ExternalCliRunnerStatus;
|
|
238
246
|
externalProcess?: ExternalProcessStatus;
|
|
@@ -512,6 +520,7 @@ interface RunPiStreamingResult {
|
|
|
512
520
|
processInstanceId: string;
|
|
513
521
|
processCloseObservedAt?: number;
|
|
514
522
|
processSignal?: string | null;
|
|
523
|
+
processTree: ProcessTreeTerminalV1;
|
|
515
524
|
}
|
|
516
525
|
|
|
517
526
|
function runPiStreaming(
|
|
@@ -548,7 +557,9 @@ function runPiStreaming(
|
|
|
548
557
|
stdio: ["ignore", "pipe", "pipe"],
|
|
549
558
|
env: spawnEnv,
|
|
550
559
|
windowsHide: true,
|
|
560
|
+
detached: process.platform !== "win32",
|
|
551
561
|
});
|
|
562
|
+
let processTreeController: OwnedProcessTreeController | undefined;
|
|
552
563
|
const stderrTail = createBoundedByteTail();
|
|
553
564
|
const rawStdoutTail = createBoundedByteTail();
|
|
554
565
|
const messages: Message[] = [];
|
|
@@ -556,6 +567,7 @@ function runPiStreaming(
|
|
|
556
567
|
let model: string | undefined;
|
|
557
568
|
let writerRegistrationError: string | undefined;
|
|
558
569
|
if (typeof child.pid === "number") {
|
|
570
|
+
processTreeController = createOwnedProcessTreeController(child.pid);
|
|
559
571
|
try {
|
|
560
572
|
onWriterProcess?.({ state: "running", pid: child.pid });
|
|
561
573
|
} catch (writerError) {
|
|
@@ -703,7 +715,6 @@ function runPiStreaming(
|
|
|
703
715
|
// a lingering stdio holder after `exit`, or a child that never exits.
|
|
704
716
|
const FINAL_STOP_GRACE_MS = 1000;
|
|
705
717
|
const HARD_KILL_MS = 3000;
|
|
706
|
-
const TIMEOUT_HARD_KILL_MS = 3000;
|
|
707
718
|
let childExited = false;
|
|
708
719
|
let forcedTerminationSignal = false;
|
|
709
720
|
let cleanTerminalAssistantStopReceived = false;
|
|
@@ -711,7 +722,6 @@ function runPiStreaming(
|
|
|
711
722
|
let finalDrainTimer: NodeJS.Timeout | undefined;
|
|
712
723
|
let finalHardKillTimer: NodeJS.Timeout | undefined;
|
|
713
724
|
let watchdogTailTimer: NodeJS.Timeout | undefined;
|
|
714
|
-
let timeoutHardKillTimer: NodeJS.Timeout | undefined;
|
|
715
725
|
let turnBudgetTerminationTimer: NodeJS.Timeout | undefined;
|
|
716
726
|
let turnBudgetHardKillTimer: NodeJS.Timeout | undefined;
|
|
717
727
|
let protocolHardKillTimer: NodeJS.Timeout | undefined;
|
|
@@ -776,22 +786,16 @@ function runPiStreaming(
|
|
|
776
786
|
timedOut = true;
|
|
777
787
|
interrupted = false;
|
|
778
788
|
error = timeoutMessage ?? "Subagent timed out.";
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
if (!settled) trySignalChild(child, "SIGKILL");
|
|
782
|
-
}, TIMEOUT_HARD_KILL_MS);
|
|
783
|
-
timeoutHardKillTimer.unref?.();
|
|
789
|
+
if (processTreeController) void processTreeController.terminate();
|
|
790
|
+
else trySignalChild(child, "SIGTERM");
|
|
784
791
|
});
|
|
785
792
|
registerStop?.(() => {
|
|
786
793
|
if (settled || timedOut || stopped) return;
|
|
787
794
|
stopped = true;
|
|
788
795
|
interrupted = false;
|
|
789
796
|
error = stopMessage ?? "Subagent stopped by user.";
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
if (!settled) trySignalChild(child, "SIGKILL");
|
|
793
|
-
}, TIMEOUT_HARD_KILL_MS);
|
|
794
|
-
timeoutHardKillTimer.unref?.();
|
|
797
|
+
if (processTreeController) void processTreeController.terminate();
|
|
798
|
+
else trySignalChild(child, "SIGTERM");
|
|
795
799
|
});
|
|
796
800
|
registerTurnBudgetAbort?.((message, state) => {
|
|
797
801
|
if (settled || timedOut || stopped || turnBudgetExceeded) return;
|
|
@@ -820,10 +824,6 @@ function runPiStreaming(
|
|
|
820
824
|
finalHardKillTimer = undefined;
|
|
821
825
|
}
|
|
822
826
|
clearWatchdogTailTimer();
|
|
823
|
-
if (timeoutHardKillTimer) {
|
|
824
|
-
clearTimeout(timeoutHardKillTimer);
|
|
825
|
-
timeoutHardKillTimer = undefined;
|
|
826
|
-
}
|
|
827
827
|
if (turnBudgetTerminationTimer) {
|
|
828
828
|
clearTimeout(turnBudgetTerminationTimer);
|
|
829
829
|
turnBudgetTerminationTimer = undefined;
|
|
@@ -885,9 +885,12 @@ function runPiStreaming(
|
|
|
885
885
|
childExited = true;
|
|
886
886
|
clearDrainTimers();
|
|
887
887
|
});
|
|
888
|
-
child.on("close", (exitCode, signal) => {
|
|
888
|
+
child.on("close", async (exitCode, signal) => {
|
|
889
889
|
settled = true;
|
|
890
890
|
const processCloseObservedAt = Date.now();
|
|
891
|
+
const processTree = processTreeController
|
|
892
|
+
? await processTreeController.finishAfterWriterClose()
|
|
893
|
+
: { state: "unknown" as const, reason: "verification-failed" as const, diagnostic: "Writer PID was unavailable." };
|
|
891
894
|
try {
|
|
892
895
|
onWriterProcess?.({ state: "none" });
|
|
893
896
|
} catch {
|
|
@@ -939,6 +942,7 @@ function runPiStreaming(
|
|
|
939
942
|
processInstanceId,
|
|
940
943
|
processCloseObservedAt,
|
|
941
944
|
processSignal: signal,
|
|
945
|
+
processTree,
|
|
942
946
|
}));
|
|
943
947
|
});
|
|
944
948
|
|
|
@@ -961,7 +965,7 @@ function runPiStreaming(
|
|
|
961
965
|
const stderr = stderrTail.text();
|
|
962
966
|
const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
|
|
963
967
|
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 }));
|
|
968
|
+
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
969
|
});
|
|
966
970
|
});
|
|
967
971
|
}
|
|
@@ -1105,6 +1109,7 @@ interface SingleStepContext {
|
|
|
1105
1109
|
orchestratorIntercomTarget?: string;
|
|
1106
1110
|
nestedRoute?: NestedRouteInfo;
|
|
1107
1111
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1112
|
+
runFanoutBudget?: RunFanoutBudgetDescriptor;
|
|
1108
1113
|
onAttemptStart?: (attempt: { model?: string; thinking?: string }) => void;
|
|
1109
1114
|
onChildEvent?: (event: ChildEvent) => void;
|
|
1110
1115
|
onWriterProcess?: (writer: { state: "none" | "spawning" } | { state: "running"; pid: number }) => void;
|
|
@@ -1206,7 +1211,7 @@ async function runSingleStep(
|
|
|
1206
1211
|
artifactPaths = getArtifactPaths(ctx.artifactsDir, ctx.id, step.agent, index);
|
|
1207
1212
|
fs.mkdirSync(ctx.artifactsDir, { recursive: true });
|
|
1208
1213
|
if (ctx.artifactConfig?.includeInput !== false) {
|
|
1209
|
-
fs.writeFileSync(artifactPaths.inputPath, `# Task for ${step.agent}\n\n${
|
|
1214
|
+
fs.writeFileSync(artifactPaths.inputPath, `# Task for ${step.agent}\n\n${PROMPT_REDACTED}; live Prompt Audit only.\n`, "utf-8");
|
|
1210
1215
|
}
|
|
1211
1216
|
if (ctx.artifactConfig?.includeTranscript !== false) {
|
|
1212
1217
|
transcriptWriter = createChildTranscriptWriter({
|
|
@@ -1219,7 +1224,7 @@ async function runSingleStep(
|
|
|
1219
1224
|
});
|
|
1220
1225
|
}
|
|
1221
1226
|
}
|
|
1222
|
-
transcriptWriter?.writeInitialUserMessage(
|
|
1227
|
+
transcriptWriter?.writeInitialUserMessage(`${PROMPT_REDACTED}; live Prompt Audit only.`);
|
|
1223
1228
|
|
|
1224
1229
|
if (step.runner?.type === "external-cli") {
|
|
1225
1230
|
const runner: ExternalCliRunnerStatus = {
|
|
@@ -1262,7 +1267,7 @@ async function runSingleStep(
|
|
|
1262
1267
|
artifactPaths,
|
|
1263
1268
|
artifactConfig: ctx.artifactConfig,
|
|
1264
1269
|
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() },
|
|
1270
|
+
metadata: { runId: ctx.id, agent: step.agent, task: PROMPT_REDACTED, runner, externalProcess: external.externalProcess, exitCode: external.exitCode, error: external.error, timestamp: Date.now() },
|
|
1266
1271
|
})
|
|
1267
1272
|
: {};
|
|
1268
1273
|
return omitUndefinedProperties({
|
|
@@ -1292,7 +1297,7 @@ async function runSingleStep(
|
|
|
1292
1297
|
let capabilityAudit: import("../shared/capability-ceiling.ts").SubagentCapabilityAudit | undefined;
|
|
1293
1298
|
let launchResolvedExtensions = step.launchResolvedExtensions;
|
|
1294
1299
|
const modelAttempts: ModelAttempt[] = [];
|
|
1295
|
-
const writerProcesses:
|
|
1300
|
+
const writerProcesses: PiWriterProcessInstanceExitV1[] = [];
|
|
1296
1301
|
let writerAttemptCount = 0;
|
|
1297
1302
|
const attemptNotes: string[] = [];
|
|
1298
1303
|
const eventsPath = path.join(path.dirname(ctx.outputFile), "events.jsonl");
|
|
@@ -1306,6 +1311,9 @@ async function runSingleStep(
|
|
|
1306
1311
|
|
|
1307
1312
|
let modelIndex = 0;
|
|
1308
1313
|
let startupAttemptIndex = 0;
|
|
1314
|
+
// Escalated to "file" after an unexplained zero-activity startup failure so
|
|
1315
|
+
// retries keep the task text out of argv (endpoint pre-exec scans may deny it).
|
|
1316
|
+
let taskDeliveryOverride: SubagentTaskDelivery | undefined;
|
|
1309
1317
|
modelAttemptsLoop: while (modelIndex < candidates.length) {
|
|
1310
1318
|
if (ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
|
|
1311
1319
|
const candidate = candidates[modelIndex];
|
|
@@ -1331,6 +1339,7 @@ async function runSingleStep(
|
|
|
1331
1339
|
parentSessionId: step.parentSessionId,
|
|
1332
1340
|
baseArgs: ["--mode", "json", "-p"],
|
|
1333
1341
|
task,
|
|
1342
|
+
taskDelivery: taskDeliveryOverride,
|
|
1334
1343
|
sessionEnabled,
|
|
1335
1344
|
sessionDir,
|
|
1336
1345
|
sessionFile: step.sessionFile,
|
|
@@ -1356,6 +1365,10 @@ async function runSingleStep(
|
|
|
1356
1365
|
parentControlInbox: ctx.nestedRoute?.controlInbox,
|
|
1357
1366
|
parentRootRunId: ctx.nestedRoute?.rootRunId,
|
|
1358
1367
|
parentCapabilityToken: ctx.nestedRoute?.capabilityToken,
|
|
1368
|
+
runFanoutBudget: ctx.runFanoutBudget ? {
|
|
1369
|
+
...ctx.runFanoutBudget,
|
|
1370
|
+
...(step.runFanoutPath ? { parentPath: `${ctx.runFanoutBudget.parentPath ? `${ctx.runFanoutBudget.parentPath}/` : ""}${step.runFanoutPath}` } : {}),
|
|
1371
|
+
} : undefined,
|
|
1359
1372
|
steerInboxDir: ctx.steerInboxDir,
|
|
1360
1373
|
steerCapabilityPath: ctx.steerCapabilityPath,
|
|
1361
1374
|
steerAckDir: ctx.steerAckDir,
|
|
@@ -1429,6 +1442,7 @@ async function runSingleStep(
|
|
|
1429
1442
|
closeObservedAt: run.processCloseObservedAt,
|
|
1430
1443
|
exitCode: run.exitCode,
|
|
1431
1444
|
signal: run.processSignal ?? null,
|
|
1445
|
+
processTree: run.processTree,
|
|
1432
1446
|
});
|
|
1433
1447
|
}
|
|
1434
1448
|
if (run.turnBudget) turnBudget = run.turnBudget;
|
|
@@ -1583,6 +1597,10 @@ async function runSingleStep(
|
|
|
1583
1597
|
});
|
|
1584
1598
|
const shouldRetry = await waitForSubagentStartupRetry(retryDelayMs, [ctx.timeoutSignal, ctx.stopSignal]);
|
|
1585
1599
|
if (!shouldRetry || ctx.skipAcceptance?.()) break modelAttemptsLoop;
|
|
1600
|
+
if (!taskDeliveryOverride && run.processSignal === "SIGKILL") {
|
|
1601
|
+
taskDeliveryOverride = "file";
|
|
1602
|
+
attemptNotes.push("[startup-retry] retrying with file task delivery to keep the task text out of the child process argv.");
|
|
1603
|
+
}
|
|
1586
1604
|
attempt.error = retryNote;
|
|
1587
1605
|
attemptNotes.push(retryNote);
|
|
1588
1606
|
startupAttemptIndex += 1;
|
|
@@ -1677,6 +1695,7 @@ async function runSingleStep(
|
|
|
1677
1695
|
const acceptanceFailure = effectiveAcceptance ? acceptanceFailureMessage(effectiveAcceptance) : undefined;
|
|
1678
1696
|
const acceptanceCanFailRun = acceptanceFailure && effectiveAcceptance?.explicit && (finalResult?.exitCode ?? 1) === 0 && !finalResult?.interrupted && !timedOutAfterAcceptance && !stoppedAfterAcceptance && !turnBudgetExceeded && !isAgentContractV1(step.agentContract);
|
|
1679
1697
|
const effectiveFinalExitCode = timedOutAfterAcceptance || stoppedAfterAcceptance || turnBudgetExceeded ? 1 : acceptanceCanFailRun ? 1 : finalResult?.exitCode ?? 1;
|
|
1698
|
+
const intercomDetachReceipt = finalResult?.finalOutput === INTERCOM_DETACH_RECEIPT;
|
|
1680
1699
|
const effectiveFinalError = stoppedAfterAcceptance
|
|
1681
1700
|
? ctx.stopMessage ?? "Subagent stopped by user."
|
|
1682
1701
|
: timedOutAfterAcceptance
|
|
@@ -1685,7 +1704,7 @@ async function runSingleStep(
|
|
|
1685
1704
|
? finalResult?.error ?? (turnBudget ? turnBudgetExceededMessage(turnBudget, turnBudget.turnCount) : "Subagent exceeded turn budget.")
|
|
1686
1705
|
: acceptanceCanFailRun
|
|
1687
1706
|
? (finalResult?.error ? `${finalResult.error}\n${acceptanceFailure}` : acceptanceFailure)
|
|
1688
|
-
: finalResult?.error;
|
|
1707
|
+
: finalResult?.error ?? (intercomDetachReceipt ? INTERCOM_DETACH_RECEIPT : undefined);
|
|
1689
1708
|
|
|
1690
1709
|
const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
|
|
1691
1710
|
? persistStepArtifacts({
|
|
@@ -1700,7 +1719,7 @@ async function runSingleStep(
|
|
|
1700
1719
|
metadata: {
|
|
1701
1720
|
runId: ctx.id,
|
|
1702
1721
|
agent: step.agent,
|
|
1703
|
-
task,
|
|
1722
|
+
task: PROMPT_REDACTED,
|
|
1704
1723
|
exitCode: effectiveFinalExitCode,
|
|
1705
1724
|
model: finalResult?.model,
|
|
1706
1725
|
attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
|
|
@@ -2171,6 +2190,7 @@ async function runSubagent(
|
|
|
2171
2190
|
...(config.launchContractDigest ? { launchContractDigest: config.launchContractDigest } : {}),
|
|
2172
2191
|
...(config.launchResolvedExtensions ? { launchResolvedExtensions: config.launchResolvedExtensions } : {}),
|
|
2173
2192
|
...(config.capabilityCeiling ? { capabilityCeiling: config.capabilityCeiling } : {}),
|
|
2193
|
+
...(config.runFanoutBudget ? { runFanoutBudget: getRunFanoutBudgetSnapshot(config.runFanoutBudget) } : {}),
|
|
2174
2194
|
...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
|
|
2175
2195
|
...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
|
|
2176
2196
|
...(config.runnerProcessInstanceId ? { processTerminal: { version: 1 as const, state: "pending" as const, runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId } } : {}),
|
|
@@ -2260,10 +2280,10 @@ async function runSubagent(
|
|
|
2260
2280
|
refreshWorkflowGraph();
|
|
2261
2281
|
writeAtomicJson(statusPath, statusPayload);
|
|
2262
2282
|
const activeState = isActiveAsyncState(statusPayload.state);
|
|
2263
|
-
if (activeState !== lastIndexedActiveState) {
|
|
2283
|
+
if (activeState && activeState !== lastIndexedActiveState) {
|
|
2264
2284
|
updateActiveRunIndex(asyncDir, statusPayload.state);
|
|
2265
|
-
lastIndexedActiveState = activeState;
|
|
2266
2285
|
}
|
|
2286
|
+
lastIndexedActiveState = activeState;
|
|
2267
2287
|
emitNestedSelfEvent(statusPayload.state === "running" || statusPayload.state === "queued" ? "subagent.nested.updated" : "subagent.nested.completed");
|
|
2268
2288
|
};
|
|
2269
2289
|
const statusWriteCoalescer = createFileCoalescer(writeStatusPayloadNow, 100);
|
|
@@ -3035,7 +3055,6 @@ async function runSubagent(
|
|
|
3035
3055
|
if (stopped || timedOut || interrupted || statusPayload.state !== "running") return;
|
|
3036
3056
|
stopped = true;
|
|
3037
3057
|
const now = Date.now();
|
|
3038
|
-
statusPayload.state = "stopped";
|
|
3039
3058
|
statusPayload.stopped = true;
|
|
3040
3059
|
statusPayload.error = stopMessage;
|
|
3041
3060
|
currentActivityState = undefined;
|
|
@@ -3068,7 +3087,6 @@ async function runSubagent(
|
|
|
3068
3087
|
timedOut = true;
|
|
3069
3088
|
const now = Date.now();
|
|
3070
3089
|
const message = timeoutMessage ?? "Subagent timed out.";
|
|
3071
|
-
statusPayload.state = "failed";
|
|
3072
3090
|
statusPayload.timedOut = true;
|
|
3073
3091
|
statusPayload.error = message;
|
|
3074
3092
|
currentActivityState = undefined;
|
|
@@ -3258,6 +3276,9 @@ async function runSubagent(
|
|
|
3258
3276
|
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
3277
|
}
|
|
3260
3278
|
if (materialized.collectedOnEmpty) await validateDynamicCollection(step.collect.outputSchema, materialized.collectedOnEmpty);
|
|
3279
|
+
if (!config.runFanoutBudget) throw new Error("Async runner is missing its run fan-out budget identity.");
|
|
3280
|
+
const runFanoutBudget = claimRunFanoutBatch(config.runFanoutBudget, materialized.parallel.map((_, itemIndex) => `chain[${stepIndex}].expand[${itemIndex}]`));
|
|
3281
|
+
statusPayload.runFanoutBudget = runFanoutBudget;
|
|
3261
3282
|
} catch (error) {
|
|
3262
3283
|
const now = Date.now();
|
|
3263
3284
|
const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
|
|
@@ -3364,6 +3385,7 @@ async function runSubagent(
|
|
|
3364
3385
|
const materializedTask = step.parallel.namespaceOutputPath ? injectSingleOutputInstruction(taskText, outputPath, step.parallel) : taskText;
|
|
3365
3386
|
return omitUndefinedProperties({
|
|
3366
3387
|
...step.parallel,
|
|
3388
|
+
runFanoutPath: `chain[${stepIndex}].expand[${itemIndex}]`,
|
|
3367
3389
|
task: materializedTask,
|
|
3368
3390
|
effectiveAcceptance: resolveEffectiveAcceptance(omitUndefinedProperties({
|
|
3369
3391
|
explicit: step.parallel.acceptanceInput,
|
|
@@ -3523,6 +3545,7 @@ async function runSubagent(
|
|
|
3523
3545
|
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
3524
3546
|
nestedRoute: config.nestedRoute,
|
|
3525
3547
|
capabilityCeiling: config.capabilityCeiling,
|
|
3548
|
+
runFanoutBudget: config.runFanoutBudget,
|
|
3526
3549
|
registerInterrupt: (interrupt) => registerStepInterrupt(fi, interrupt),
|
|
3527
3550
|
registerTimeout: (interrupt) => registerStepTimeout(fi, interrupt),
|
|
3528
3551
|
registerStop: (stop) => registerStepStop(fi, stop),
|
|
@@ -3905,6 +3928,7 @@ async function runSubagent(
|
|
|
3905
3928
|
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
3906
3929
|
nestedRoute: config.nestedRoute,
|
|
3907
3930
|
capabilityCeiling: config.capabilityCeiling,
|
|
3931
|
+
runFanoutBudget: config.runFanoutBudget,
|
|
3908
3932
|
registerInterrupt: (interrupt) => registerStepInterrupt(fi, interrupt),
|
|
3909
3933
|
registerTimeout: (interrupt) => registerStepTimeout(fi, interrupt),
|
|
3910
3934
|
registerStop: (stop) => registerStepStop(fi, stop),
|
|
@@ -4194,6 +4218,7 @@ async function runSubagent(
|
|
|
4194
4218
|
orchestratorIntercomTarget: config.controlIntercomTarget,
|
|
4195
4219
|
nestedRoute: config.nestedRoute,
|
|
4196
4220
|
capabilityCeiling: config.capabilityCeiling,
|
|
4221
|
+
runFanoutBudget: config.runFanoutBudget,
|
|
4197
4222
|
registerInterrupt: (interrupt) => registerStepInterrupt(flatIndex, interrupt),
|
|
4198
4223
|
registerTimeout: (interrupt) => registerStepTimeout(flatIndex, interrupt),
|
|
4199
4224
|
registerStop: (stop) => registerStepStop(flatIndex, stop),
|
|
@@ -4438,6 +4463,9 @@ async function runSubagent(
|
|
|
4438
4463
|
clearTimeout(timeoutTimer);
|
|
4439
4464
|
timeoutTimer = undefined;
|
|
4440
4465
|
}
|
|
4466
|
+
if (!timedOut && !stopped && !interrupted && config.timeoutMs !== undefined && results.some((result) => result.timedOut === true && result.error === timeoutMessage)) {
|
|
4467
|
+
timedOut = true;
|
|
4468
|
+
}
|
|
4441
4469
|
const signalTerminated = !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
|
|
4442
4470
|
processSignal: result.processSignal,
|
|
4443
4471
|
interrupted: result.interrupted,
|
|
@@ -4630,7 +4658,7 @@ async function runSubagent(
|
|
|
4630
4658
|
shareError,
|
|
4631
4659
|
}));
|
|
4632
4660
|
if (config.runnerProcessInstanceId) {
|
|
4633
|
-
const writers: Record<string,
|
|
4661
|
+
const writers: Record<string, PiWriterProcessInstanceExitV1[]> = {};
|
|
4634
4662
|
const expectedWriters: Record<string, number> = {};
|
|
4635
4663
|
for (const [index, result] of results.entries()) {
|
|
4636
4664
|
writers[String(index)] = result.writerProcesses ?? [];
|
|
@@ -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,
|