@tangle-network/agent-runtime 0.175.0 → 0.177.1
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/README.md +4 -0
- package/dist/{activation-CsdJWRXX.js → activation-XVI_z1g3.js} +3 -3
- package/dist/{activation-CsdJWRXX.js.map → activation-XVI_z1g3.js.map} +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +2 -2
- package/dist/{authoring-DsLNInAz.js → authoring-bXmPNfCI.js} +2 -2
- package/dist/{authoring-DsLNInAz.js.map → authoring-bXmPNfCI.js.map} +1 -1
- package/dist/candidate-execution/index.js +4 -4
- package/dist/{candidate-execution-BbMbyhgC.js → candidate-execution-fBNUyWyE.js} +10 -4
- package/dist/candidate-execution-fBNUyWyE.js.map +1 -0
- package/dist/{conversation-7XGKoDM6.js → conversation-BREx2hi-.js} +3 -3
- package/dist/{conversation-7XGKoDM6.js.map → conversation-BREx2hi-.js.map} +1 -1
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.js +1 -1
- package/dist/coordination-driver-xO1tkxy-.js +3063 -0
- package/dist/coordination-driver-xO1tkxy-.js.map +1 -0
- package/dist/durable-file-g3YdfEh4.js +131 -0
- package/dist/durable-file-g3YdfEh4.js.map +1 -0
- package/dist/durable.d.ts +2 -2
- package/dist/durable.js +1 -1
- package/dist/{environment-provider-DWjbGH8W.d.ts → environment-provider-5E82esWE.d.ts} +6 -3
- package/dist/{environment-provider-Bn3652YU.js → environment-provider-DKyMWQJd.js} +121 -17
- package/dist/environment-provider-DKyMWQJd.js.map +1 -0
- package/dist/environment-provider.d.ts +1 -1
- package/dist/environment-provider.js +1 -1
- package/dist/{graph-BbeHgLXH.js → graph-DwJXa1Ph.js} +3 -3
- package/dist/graph-DwJXa1Ph.js.map +1 -0
- package/dist/graph.d.ts +3 -3
- package/dist/graph.js +4 -4
- package/dist/{improvement-cycle-DKGDCukL.js → improvement-cycle-eiSv6aH4.js} +5 -5
- package/dist/{improvement-cycle-DKGDCukL.js.map → improvement-cycle-eiSv6aH4.js.map} +1 -1
- package/dist/{index-CIhkH7mq.d.ts → index-BnAiQVLD.d.ts} +290 -29
- package/dist/{index-CFMB9ux3.d.ts → index-Bs0uhf-y.d.ts} +2 -2
- package/dist/{index-Dk5X9eKg.d.ts → index-C9XTLVP1.d.ts} +4 -4
- package/dist/index.d.ts +7 -7
- package/dist/index.js +13 -13
- package/dist/intelligence.d.ts +4 -4
- package/dist/intelligence.js +6 -6
- package/dist/kernel.d.ts +6 -6
- package/dist/kernel.js +13 -11
- package/dist/{knowledge-BaAX0HVu.js → knowledge-Bmtj_7u7.js} +5 -5
- package/dist/{knowledge-BaAX0HVu.js.map → knowledge-Bmtj_7u7.js.map} +1 -1
- package/dist/knowledge.d.ts +1 -1
- package/dist/knowledge.js +1 -1
- package/dist/{loop-runner-bin-DRYApMiu.d.ts → loop-runner-bin-ChS5deJ0.d.ts} +3 -3
- package/dist/{loop-runner-bin-D63Tytdk.js → loop-runner-bin-GTN5wqCt.js} +3 -3
- package/dist/{loop-runner-bin-D63Tytdk.js.map → loop-runner-bin-GTN5wqCt.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/{materialization-Ct3I4wu3.js → materialization-CekWK6OO.js} +5 -3
- package/dist/materialization-CekWK6OO.js.map +1 -0
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +3 -3
- package/dist/mcp/index.js +5 -4
- package/dist/mcp/index.js.map +1 -1
- package/dist/{openai-tools-BBgjWYNw.js → openai-tools-BBj1QGJp.js} +2 -2
- package/dist/{openai-tools-BBgjWYNw.js.map → openai-tools-BBj1QGJp.js.map} +1 -1
- package/dist/{prepare-BAyaNoZu.js → prepare-Tip-2ZoZ.js} +2 -2
- package/dist/{prepare-BAyaNoZu.js.map → prepare-Tip-2ZoZ.js.map} +1 -1
- package/dist/primeintellect/index.d.ts +1 -1
- package/dist/{protected-model-port-T2UWrDNQ.js → protected-model-port-Dd3a1SRm.js} +2 -2
- package/dist/{protected-model-port-T2UWrDNQ.js.map → protected-model-port-Dd3a1SRm.js.map} +1 -1
- package/dist/provision-supervisor-zA__ayUX.js +1020 -0
- package/dist/provision-supervisor-zA__ayUX.js.map +1 -0
- package/dist/{redact-DvLf4x1m.d.ts → redact-DkRLcSiE.d.ts} +3 -3
- package/dist/run-layout-Cd_l2XWV.js +645 -0
- package/dist/run-layout-Cd_l2XWV.js.map +1 -0
- package/dist/{runtime-D5u1M6T5.d.ts → runtime-B2eZ76kG.d.ts} +3 -3
- package/dist/{runtime-CojgP-hr.js → runtime-CJNlF5wM.js} +16 -1095
- package/dist/runtime-CJNlF5wM.js.map +1 -0
- package/dist/{spawn-journal-Tgvp5VS5.js → spawn-journal--N8Ten1q.js} +3 -1
- package/dist/{spawn-journal-Tgvp5VS5.js.map → spawn-journal--N8Ten1q.js.map} +1 -1
- package/dist/{stream-agent-turn-DxQ3GOuR.d.ts → stream-agent-turn-ByY8po9W.d.ts} +2 -2
- package/dist/{stream-agent-turn-CKIpCbSq.js → stream-agent-turn-CPj9SqVm.js} +2 -2
- package/dist/{stream-agent-turn-CKIpCbSq.js.map → stream-agent-turn-CPj9SqVm.js.map} +1 -1
- package/dist/{structural-rollout-BUYA61iV.js → structural-rollout-BeAUK7Ta.js} +4 -4
- package/dist/{structural-rollout-BUYA61iV.js.map → structural-rollout-BeAUK7Ta.js.map} +1 -1
- package/dist/{supervise-Ci0RfWQF.js → supervise-HsRKOlKY.js} +405 -3374
- package/dist/supervise-HsRKOlKY.js.map +1 -0
- package/dist/{supervisor-Bt1XLCVq.js → supervisor-ChLgoYhG.js} +1620 -33
- package/dist/supervisor-ChLgoYhG.js.map +1 -0
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +13 -12
- package/dist/testing.js.map +1 -1
- package/dist/{top-app-3rYfFPTW.js → top-app-DIBApkt1.js} +25 -9
- package/dist/top-app-DIBApkt1.js.map +1 -0
- package/dist/tui/bin.js +1 -1
- package/dist/tui/index.d.ts +9 -1
- package/dist/tui/index.js +3 -2
- package/dist/{types-DjVO-p7R.d.ts → types-a2ZZUl80.d.ts} +25 -2
- package/dist/{workspace-archive-B0Hqp2eJ.js → workspace-archive-DOZAeeKU.js} +2 -2
- package/dist/{workspace-archive-B0Hqp2eJ.js.map → workspace-archive-DOZAeeKU.js.map} +1 -1
- package/package.json +6 -4
- package/dist/candidate-execution-BbMbyhgC.js.map +0 -1
- package/dist/environment-provider-Bn3652YU.js.map +0 -1
- package/dist/graph-BbeHgLXH.js.map +0 -1
- package/dist/materialization-Ct3I4wu3.js.map +0 -1
- package/dist/run-layout-C2jgwsCq.js +0 -393
- package/dist/run-layout-C2jgwsCq.js.map +0 -1
- package/dist/runtime-CojgP-hr.js.map +0 -1
- package/dist/supervise-Ci0RfWQF.js.map +0 -1
- package/dist/supervisor-Bt1XLCVq.js.map +0 -1
- package/dist/top-app-3rYfFPTW.js.map +0 -1
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { C as runtimeOwnedScopeOwnerRuntime, S as runtimeOwnedPendingExecutorMaterialization, T as unknownMaterializationReceipt, _ as runtimeOwnedDeferredExecutorRuntime, a as authoredProfileDigest, b as runtimeOwnedExecutorMaterialization, c as knownExecutionBindingReceipt, g as recordRuntimeOwnedProviderModel, h as recordRuntimeOwnedProviderIdentityConflict, l as knownMaterializationReceipt, m as recordRuntimeOwnedProviderDispatchNotStarted, n as attestRuntimeOwnedExecutor, o as finalizeRuntimeOwnedPendingExecutor, p as recordRuntimeOwnedProviderAttemptStart, r as attestRuntimeOwnedPendingExecutor, s as inheritRuntimeOwnedExecutorAttestation, t as attestRuntimeOwnedDeferredExecutor, u as newExecutionAttemptId, w as unknownExecutionBindingReceipt, x as runtimeOwnedExecutorProviderEvidence, y as runtimeOwnedExecutorExecutionBinding } from "./materialization-
|
|
2
|
-
import { f as RuntimeRunStateError, m as ValidationError, r as BackendTransportError } from "./errors-CDZ8XsVj.js";
|
|
1
|
+
import { A as assertEventBinding, B as exactContinuedControlRef, C as runtimeOwnedScopeOwnerRuntime, D as abortError, E as RetainedRunProviderContractError, F as assertWaitDuration, G as freezeControlRef, H as exactSession, I as awaitAbortable$1, J as sameControlCoordinates, K as hasDurableCancel, L as cancellationRequest, M as assertResultBinding, N as assertSequence, O as assertBoundaryBinding, P as assertStableText, R as copyControlRef, S as runtimeOwnedPendingExecutorMaterialization, T as unknownMaterializationReceipt, U as exactSessionCancel, V as exactControlRef, W as exactSessionResult, Y as freshTurnInput, _ as runtimeOwnedDeferredExecutorRuntime, a as authoredProfileDigest, b as runtimeOwnedExecutorMaterialization, c as knownExecutionBindingReceipt, g as recordRuntimeOwnedProviderModel, h as recordRuntimeOwnedProviderIdentityConflict, j as assertInteractionBinding, k as assertCanonicalEventBinding, l as knownMaterializationReceipt, m as recordRuntimeOwnedProviderDispatchNotStarted, n as attestRuntimeOwnedExecutor, o as finalizeRuntimeOwnedPendingExecutor, p as recordRuntimeOwnedProviderAttemptStart, q as isTerminalSessionStatus, r as attestRuntimeOwnedPendingExecutor, s as inheritRuntimeOwnedExecutorAttestation, t as attestRuntimeOwnedDeferredExecutor, u as newExecutionAttemptId, w as unknownExecutionBindingReceipt, x as runtimeOwnedExecutorProviderEvidence, y as runtimeOwnedExecutorExecutionBinding, z as delay } from "./materialization-CekWK6OO.js";
|
|
2
|
+
import { c as RetainedInteractiveAdmissionError, d as RetainedRunDispatchBindingError, f as RuntimeRunStateError, l as RetainedInteractiveBindingError, m as ValidationError, r as BackendTransportError, u as RetainedRunAdmissionError } from "./errors-CDZ8XsVj.js";
|
|
3
3
|
import { n as detachedSnapshot } from "./snapshot-CTAf4uuA.js";
|
|
4
|
-
import { _ as captureWorkerTraceEvidence, a as aggregateProviderModelEvidence, c as loadSpawnForest, d as replaySpawnTree, f as attestNestedDriverTreeOwner, h as runtimeOwnedNestedDriverTreeRoot, l as materializeTreeView, m as nestedDriverTreeRoot, o as closesCursorSlot, p as driverRuntime, u as pendingWaits, x as contentAddress } from "./spawn-journal
|
|
4
|
+
import { _ as captureWorkerTraceEvidence, a as aggregateProviderModelEvidence, c as loadSpawnForest, d as replaySpawnTree, f as attestNestedDriverTreeOwner, h as runtimeOwnedNestedDriverTreeRoot, l as materializeTreeView, m as nestedDriverTreeRoot, n as FileSpawnJournal, o as closesCursorSlot, p as driverRuntime, u as pendingWaits, x as contentAddress } from "./spawn-journal--N8Ten1q.js";
|
|
5
5
|
import { _ as unmeteredSpend, a as cloneTokenUsage, b as zeroTokenUsage, d as randomSuffix, f as randomUuid, g as throwIfAborted, h as throwAbort, l as mapWithConcurrency, m as stringifySafe, n as addTokenUsage, o as deleteBoxSafe, p as sleep, r as chargedTokens, s as hasCompleteCacheBreakdown, t as addSpend, u as promptCacheTokenClasses, v as withTimeout, y as zeroSpend } from "./util-D6ZEuBMi.js";
|
|
6
|
-
import { c as notifySandboxEventObserver, i as extractLlmCallEvent, l as sandboxEventServedBackend, r as createSandboxToolPartState, s as mapSandboxToolEvent, t as assertSandboxServedModel, u as sandboxProgressEvents } from "./sandbox-events-BVjstFgb.js";
|
|
6
|
+
import { c as notifySandboxEventObserver, i as extractLlmCallEvent, l as sandboxEventServedBackend, m as parseCanonicalTransportEvent, p as extractTransportEventIdentity, r as createSandboxToolPartState, s as mapSandboxToolEvent, t as assertSandboxServedModel, u as sandboxProgressEvents } from "./sandbox-events-BVjstFgb.js";
|
|
7
7
|
import { n as executableAgentSpecSnapshot, r as projectSandboxOutcome, t as executableAgentProfileSnapshot } from "./executable-spec-CkGvdPds.js";
|
|
8
8
|
import { a as concreteProfileModel, c as profileModelExecutionSettings, d as agentHarness, o as enforceTokenLimits, s as profileBridgeWireModel, t as assertExecutableAgentProfile, u as resolveRouterRetryPolicy } from "./model-policy-Sw4ywhtL.js";
|
|
9
|
-
import { c as linkAbort, i as resolveAgentEnvironmentProvider, l as runAbortable, n as providerAsExecutor, r as providerAsSandboxClient, s as abortError } from "./environment-provider-
|
|
9
|
+
import { c as linkAbort, i as resolveAgentEnvironmentProvider, l as runAbortable, n as providerAsExecutor, r as providerAsSandboxClient, s as abortError$1 } from "./environment-provider-DKyMWQJd.js";
|
|
10
10
|
import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
|
|
11
|
-
import {
|
|
11
|
+
import { n as assertNoSymlinkDescendant, r as publishExclusiveDurableFile } from "./durable-file-g3YdfEh4.js";
|
|
12
|
+
import { AGENT_PROFILE_MATERIALIZATION_AXES, AgentEnvironmentCapabilitiesSchema, AgentExactRunControlRefSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStatusSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentNativeContextContinuationResultSchema, AgentTurnInputSchema, AgentTurnResultSchema, InteractionAcknowledgementSchema, InteractionResponseCommandSchema, NativeContextBoundaryProofSchema, NativeContextContinuationRequestSchema, REASONING_EFFORTS, RuntimeEventEnvelopeSchema, TerminalReplayWindowSchema, TerminalSessionRefSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionRunRef, agentInteractiveSessionStatusMatchesRef, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentNativeContextContinuationResultMatchesRequest, agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, exactAgentInteractiveSessionStart, harnessTypeSchema, nativeContextContinuationTurnDigest, nativeReasoningControl, profileMaterializationAxes, profileMaterializationAxes as profileMaterializationAxes$1, renderInputPartsAsText, sha256DigestSchema } from "@tangle-network/agent-interface";
|
|
12
13
|
import { estimateCost, isModelPriced } from "@tangle-network/agent-eval";
|
|
13
14
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
14
15
|
import { basename, delimiter, dirname, isAbsolute, join, resolve, sep, win32 } from "node:path";
|
|
15
16
|
import { applyWorkspacePlan, hashWorkspacePlan, materializeProfile, resolveAgentProfileResources } from "@tangle-network/agent-profile-materialize";
|
|
16
17
|
import { access, chmod, copyFile, mkdir, mkdtemp, open, readFile, realpath, rm, rmdir, stat, symlink, writeFile } from "node:fs/promises";
|
|
17
|
-
import { appendFileSync, constants, createReadStream } from "node:fs";
|
|
18
|
+
import { appendFileSync, constants, createReadStream, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
18
19
|
import { spawn } from "node:child_process";
|
|
19
20
|
import { homedir, tmpdir } from "node:os";
|
|
20
21
|
import { stripVTControlCharacters } from "node:util";
|
|
@@ -10821,6 +10822,1531 @@ function queueOf(units, budget) {
|
|
|
10821
10822
|
};
|
|
10822
10823
|
}
|
|
10823
10824
|
//#endregion
|
|
10825
|
+
//#region src/runtime/retained-interactive-handle.ts
|
|
10826
|
+
function createRetainedInteractiveRunHandle(environment, inputRef, capabilities, requestedStart) {
|
|
10827
|
+
const ref = freezeInteractiveRef(inputRef);
|
|
10828
|
+
const source = environment.interactive(ref);
|
|
10829
|
+
if (!sameInteractiveRef(source.ref, ref)) throw new Error("provider reconstructed a different interactive process");
|
|
10830
|
+
if (!source.sendPrompt) throw new Error("provider declared interactive prompt support but exposed no prompt method");
|
|
10831
|
+
return Object.freeze({
|
|
10832
|
+
ref,
|
|
10833
|
+
capabilities,
|
|
10834
|
+
claimControl: async (request, options) => exactClaim(ref, request, await awaitAbortable$1(Promise.resolve().then(() => source.claimControl(request, options)), options?.signal)),
|
|
10835
|
+
status: async (options) => exactStatus(ref, await awaitAbortable$1(Promise.resolve().then(() => source.status(options)), options?.signal), requestedStart),
|
|
10836
|
+
attach: async (request, options) => exactTerminal(ref, request, await awaitAbortable$1(Promise.resolve().then(() => source.attach(request, options)), options?.signal)),
|
|
10837
|
+
sendPrompt: async (command, options) => exactPrompt(ref, await awaitAbortable$1(Promise.resolve().then(() => source.sendPrompt(command, options)), options?.signal), command),
|
|
10838
|
+
stop: async (command, options) => exactStop(ref, await awaitAbortable$1(Promise.resolve().then(() => source.stop(command, options)), options?.signal), command)
|
|
10839
|
+
});
|
|
10840
|
+
}
|
|
10841
|
+
function freezeInteractiveRef(value) {
|
|
10842
|
+
return detachedSnapshot(AgentInteractiveSessionRefSchema.parse(value), "interactive session ref");
|
|
10843
|
+
}
|
|
10844
|
+
function exactClaim(ref, request, value) {
|
|
10845
|
+
const acknowledgement = parseProviderAcknowledgement(AgentInteractiveSessionControlClaimAcknowledgementSchema, value, "control claim");
|
|
10846
|
+
if (!agentInteractiveSessionControlClaimAcknowledgementMatchesRequest(request, acknowledgement)) throw new RetainedRunProviderContractError("provider returned a control claim acknowledgement for another request");
|
|
10847
|
+
if (acknowledgement.control && !agentInteractiveSessionControlClaimMatchesRef(ref, acknowledgement.control)) throw new RetainedRunProviderContractError("provider returned a control claim for another interactive process");
|
|
10848
|
+
return acknowledgement;
|
|
10849
|
+
}
|
|
10850
|
+
function exactPrompt(ref, value, command) {
|
|
10851
|
+
const acknowledgement = parseProviderAcknowledgement(AgentInteractiveSessionPromptAcknowledgementSchema, value, "prompt");
|
|
10852
|
+
if (!agentInteractiveSessionPromptAcknowledgementMatchesCommand(command, acknowledgement)) throw new RetainedRunProviderContractError("provider returned a prompt acknowledgement for another request");
|
|
10853
|
+
if (!agentInteractiveSessionControlClaimMatchesRef(ref, acknowledgement.control)) throw new RetainedRunProviderContractError("provider returned a prompt acknowledgement for another interactive process");
|
|
10854
|
+
return acknowledgement;
|
|
10855
|
+
}
|
|
10856
|
+
function exactStop(ref, value, command) {
|
|
10857
|
+
const acknowledgement = parseProviderAcknowledgement(AgentInteractiveSessionStopAcknowledgementSchema, value, "stop");
|
|
10858
|
+
if (!agentInteractiveSessionStopAcknowledgementMatchesCommand(command, acknowledgement)) throw new RetainedRunProviderContractError("provider returned a stop acknowledgement for another request");
|
|
10859
|
+
if (!agentInteractiveSessionControlClaimMatchesRef(ref, acknowledgement.control)) throw new RetainedRunProviderContractError("provider returned a stop acknowledgement for another interactive process");
|
|
10860
|
+
return acknowledgement;
|
|
10861
|
+
}
|
|
10862
|
+
function parseProviderAcknowledgement(schema, value, operation) {
|
|
10863
|
+
try {
|
|
10864
|
+
return schema.parse(value);
|
|
10865
|
+
} catch {
|
|
10866
|
+
throw new RetainedRunProviderContractError(`provider returned an invalid interactive ${operation} acknowledgement`);
|
|
10867
|
+
}
|
|
10868
|
+
}
|
|
10869
|
+
function exactStatus(ref, value, requestedStart) {
|
|
10870
|
+
let status;
|
|
10871
|
+
try {
|
|
10872
|
+
status = AgentInteractiveSessionStatusSchema.parse(value);
|
|
10873
|
+
} catch (error) {
|
|
10874
|
+
if (requestedStart === void 0) throw error;
|
|
10875
|
+
throw new RetainedInteractiveBindingError(detachedSnapshot(requestedStart, "interactive status binding request"), {}, { cause: error });
|
|
10876
|
+
}
|
|
10877
|
+
if (!agentInteractiveSessionStatusMatchesRef(ref, status)) {
|
|
10878
|
+
if (requestedStart !== void 0) throw new RetainedInteractiveBindingError(detachedSnapshot(requestedStart, "interactive status binding request"), detachedSnapshot({ status: detachedSnapshot(status, "interactive provider status") }, "interactive provider status result"), { cause: /* @__PURE__ */ new Error("provider returned status for another interactive process") });
|
|
10879
|
+
throw new Error("provider returned status for another interactive process");
|
|
10880
|
+
}
|
|
10881
|
+
return status;
|
|
10882
|
+
}
|
|
10883
|
+
function exactTerminal(ref, request, terminal) {
|
|
10884
|
+
const terminalRef = TerminalSessionRefSchema.parse(terminal.ref);
|
|
10885
|
+
TerminalReplayWindowSchema.parse(terminal.cursors);
|
|
10886
|
+
if (terminalRef.parentExecutionId !== ref.run.executionId) throw new Error("provider attached a terminal from another interactive run");
|
|
10887
|
+
AgentInteractiveSessionControlClaimSchema.parse(terminal.control);
|
|
10888
|
+
if (!agentInteractiveSessionControlClaimMatchesRef(ref, terminal.control)) throw new Error("provider attached a terminal with a claim for another interactive process");
|
|
10889
|
+
if (canonicalCandidateDigest(terminal.control) !== canonicalCandidateDigest(request.control)) throw new Error("provider attached a terminal with a different interactive control claim");
|
|
10890
|
+
return terminal;
|
|
10891
|
+
}
|
|
10892
|
+
function sameInteractiveRef(left, right) {
|
|
10893
|
+
return canonicalCandidateDigest(left) === canonicalCandidateDigest(right);
|
|
10894
|
+
}
|
|
10895
|
+
//#endregion
|
|
10896
|
+
//#region src/runtime/retained-interactive-lifecycle.ts
|
|
10897
|
+
const INTERACTIVE_CLEANUP_TIMEOUT_MS = 3e4;
|
|
10898
|
+
/** Create one environment while retaining ownership if cancellation wins the race. */
|
|
10899
|
+
async function createInteractiveEnvironment(create, signal) {
|
|
10900
|
+
if (signal?.aborted) throw abortError(signal.reason);
|
|
10901
|
+
const creation = Promise.resolve().then(create);
|
|
10902
|
+
if (signal === void 0) return creation;
|
|
10903
|
+
return new Promise((resolve, reject) => {
|
|
10904
|
+
let owner = "pending";
|
|
10905
|
+
const removeAbortListener = () => signal.removeEventListener("abort", onAbort);
|
|
10906
|
+
const onAbort = () => {
|
|
10907
|
+
if (owner !== "pending") return;
|
|
10908
|
+
owner = "runtime";
|
|
10909
|
+
removeAbortListener();
|
|
10910
|
+
disposeInteractiveEnvironment(creation, signal.reason);
|
|
10911
|
+
reject(abortError(signal.reason));
|
|
10912
|
+
};
|
|
10913
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
10914
|
+
creation.then((environment) => {
|
|
10915
|
+
if (owner !== "pending") return;
|
|
10916
|
+
owner = "caller";
|
|
10917
|
+
removeAbortListener();
|
|
10918
|
+
resolve(environment);
|
|
10919
|
+
}, (error) => {
|
|
10920
|
+
if (owner !== "pending") return;
|
|
10921
|
+
owner = "runtime";
|
|
10922
|
+
removeAbortListener();
|
|
10923
|
+
reject(error);
|
|
10924
|
+
});
|
|
10925
|
+
});
|
|
10926
|
+
}
|
|
10927
|
+
/** Start one process while destroying its unreturned environment on cancellation. */
|
|
10928
|
+
async function startInteractiveProcess(environment, start, signal) {
|
|
10929
|
+
if (signal?.aborted) {
|
|
10930
|
+
disposeInteractiveEnvironment(Promise.resolve(environment), signal.reason);
|
|
10931
|
+
throw abortError(signal.reason);
|
|
10932
|
+
}
|
|
10933
|
+
const pending = Promise.resolve().then(start);
|
|
10934
|
+
if (signal === void 0) return pending;
|
|
10935
|
+
return new Promise((resolve, reject) => {
|
|
10936
|
+
let owner = "pending";
|
|
10937
|
+
const removeAbortListener = () => signal.removeEventListener("abort", onAbort);
|
|
10938
|
+
const onAbort = () => {
|
|
10939
|
+
if (owner !== "pending") return;
|
|
10940
|
+
owner = "runtime";
|
|
10941
|
+
removeAbortListener();
|
|
10942
|
+
disposeInteractiveEnvironment(Promise.resolve(environment), signal.reason);
|
|
10943
|
+
reject(abortError(signal.reason));
|
|
10944
|
+
};
|
|
10945
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
10946
|
+
pending.then((result) => {
|
|
10947
|
+
if (owner !== "pending") return;
|
|
10948
|
+
owner = "caller";
|
|
10949
|
+
removeAbortListener();
|
|
10950
|
+
resolve(result);
|
|
10951
|
+
}, (error) => {
|
|
10952
|
+
if (owner !== "pending") return;
|
|
10953
|
+
owner = "runtime";
|
|
10954
|
+
removeAbortListener();
|
|
10955
|
+
reject(error);
|
|
10956
|
+
});
|
|
10957
|
+
});
|
|
10958
|
+
}
|
|
10959
|
+
/** Destroy an environment with fresh, bounded cleanup authority. */
|
|
10960
|
+
async function destroyInteractiveEnvironment(environment) {
|
|
10961
|
+
if (!environment.destroy) throw new Error(`provider environment "${environment.id}" does not expose destroy()`);
|
|
10962
|
+
const controller = new AbortController();
|
|
10963
|
+
const timeout = /* @__PURE__ */ new Error("interactive environment cleanup timed out");
|
|
10964
|
+
let timer;
|
|
10965
|
+
const destruction = Promise.resolve().then(() => environment.destroy?.({ signal: controller.signal }));
|
|
10966
|
+
destruction.catch(() => void 0);
|
|
10967
|
+
try {
|
|
10968
|
+
await Promise.race([destruction, new Promise((_resolve, reject) => {
|
|
10969
|
+
timer = setTimeout(() => {
|
|
10970
|
+
controller.abort(timeout);
|
|
10971
|
+
reject(timeout);
|
|
10972
|
+
}, INTERACTIVE_CLEANUP_TIMEOUT_MS);
|
|
10973
|
+
})]);
|
|
10974
|
+
} finally {
|
|
10975
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
10976
|
+
}
|
|
10977
|
+
}
|
|
10978
|
+
function disposeInteractiveEnvironment(environment, abortReason) {
|
|
10979
|
+
environment.then(destroyInteractiveEnvironment, () => void 0).catch((cleanupError) => {
|
|
10980
|
+
const reason = abortReason instanceof Error ? abortReason : new Error(String(abortReason));
|
|
10981
|
+
const failure = new AggregateError([reason, cleanupError], "cancelled interactive environment cleanup failed");
|
|
10982
|
+
process.emitWarning(failure, { code: "AGENT_RUNTIME_INTERACTIVE_CLEANUP_FAILED" });
|
|
10983
|
+
});
|
|
10984
|
+
}
|
|
10985
|
+
//#endregion
|
|
10986
|
+
//#region src/runtime/retained-run-intent.ts
|
|
10987
|
+
/**
|
|
10988
|
+
* Project environment creation input into public digest material.
|
|
10989
|
+
*
|
|
10990
|
+
* Opaque values never enter the material or its digest. Public scalar fields
|
|
10991
|
+
* remain bound directly, while opaque records retain only their key names.
|
|
10992
|
+
* Secret names remain public binding data, so changing requested credentials
|
|
10993
|
+
* still conflicts before provider effects begin.
|
|
10994
|
+
*/
|
|
10995
|
+
function retainedCreateMaterial(environment) {
|
|
10996
|
+
return {
|
|
10997
|
+
...environment.backend === void 0 ? {} : { backend: environment.backend },
|
|
10998
|
+
...environment.workspace === void 0 ? {} : { workspaceDigest: canonicalCandidateDigest(publicWorkspaceMaterial(environment.workspace)) },
|
|
10999
|
+
...environment.resources === void 0 ? {} : { resourcesDigest: canonicalCandidateDigest(publicResourceMaterial(environment.resources)) },
|
|
11000
|
+
...environment.name === void 0 ? {} : { name: environment.name },
|
|
11001
|
+
...environment.env === void 0 ? {} : { environmentVariableNames: retainedObjectNames(environment.env) },
|
|
11002
|
+
...environment.secrets === void 0 ? {} : { secretNames: retainedSecretNames(environment.secrets) },
|
|
11003
|
+
...environment.metadata === void 0 ? {} : { metadataKeys: retainedObjectNames(environment.metadata) },
|
|
11004
|
+
...environment.providerOptions === void 0 ? {} : { providerOptionNames: retainedObjectNames(environment.providerOptions) }
|
|
11005
|
+
};
|
|
11006
|
+
}
|
|
11007
|
+
/** Add the retained ownership marker without attaching turn identity. */
|
|
11008
|
+
function retainedEnvironmentMetadata(metadata, idempotencyKey) {
|
|
11009
|
+
return {
|
|
11010
|
+
...metadata,
|
|
11011
|
+
retainedIdempotencyKey: idempotencyKey
|
|
11012
|
+
};
|
|
11013
|
+
}
|
|
11014
|
+
function publicWorkspaceMaterial(workspace) {
|
|
11015
|
+
return {
|
|
11016
|
+
...workspace.environment === void 0 ? {} : { environment: workspace.environment },
|
|
11017
|
+
...workspace.image === void 0 ? {} : { image: workspace.image },
|
|
11018
|
+
...workspace.repoUrl === void 0 ? {} : { repoUrl: workspace.repoUrl },
|
|
11019
|
+
...workspace.gitRef === void 0 ? {} : { gitRef: workspace.gitRef },
|
|
11020
|
+
...workspace.cwd === void 0 ? {} : { cwd: workspace.cwd },
|
|
11021
|
+
...workspace.providerOptions === void 0 ? {} : { providerOptionNames: retainedObjectNames(workspace.providerOptions) }
|
|
11022
|
+
};
|
|
11023
|
+
}
|
|
11024
|
+
function publicResourceMaterial(resources) {
|
|
11025
|
+
return {
|
|
11026
|
+
...resources.cpu === void 0 ? {} : { cpu: resources.cpu },
|
|
11027
|
+
...resources.memoryMb === void 0 ? {} : { memoryMb: resources.memoryMb },
|
|
11028
|
+
...resources.diskMb === void 0 ? {} : { diskMb: resources.diskMb },
|
|
11029
|
+
...resources.gpu === void 0 ? {} : { gpu: resources.gpu },
|
|
11030
|
+
...resources.providerOptions === void 0 ? {} : { providerOptionNames: retainedObjectNames(resources.providerOptions) }
|
|
11031
|
+
};
|
|
11032
|
+
}
|
|
11033
|
+
function retainedObjectNames(value) {
|
|
11034
|
+
return Object.keys(value).sort();
|
|
11035
|
+
}
|
|
11036
|
+
function retainedSecretNames(secrets) {
|
|
11037
|
+
return Array.isArray(secrets) ? [...secrets].sort() : Object.keys(secrets).sort();
|
|
11038
|
+
}
|
|
11039
|
+
/** Project one headless turn into the material that `freshTurnInput` forwards. */
|
|
11040
|
+
function retainedTurnMaterial(input) {
|
|
11041
|
+
return {
|
|
11042
|
+
...input.prompt === void 0 ? {} : { prompt: input.prompt },
|
|
11043
|
+
...input.parts === void 0 ? {} : { parts: input.parts },
|
|
11044
|
+
...input.model === void 0 ? {} : { model: input.model },
|
|
11045
|
+
...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs },
|
|
11046
|
+
...input.context === void 0 ? {} : { context: input.context },
|
|
11047
|
+
...input.interactions === void 0 ? {} : { interactions: input.interactions },
|
|
11048
|
+
...input.providerOptions === void 0 ? {} : { providerOptions: input.providerOptions }
|
|
11049
|
+
};
|
|
11050
|
+
}
|
|
11051
|
+
//#endregion
|
|
11052
|
+
//#region src/runtime/interaction-capabilities.ts
|
|
11053
|
+
/**
|
|
11054
|
+
* Check one turn's interaction request before the provider can dispatch it.
|
|
11055
|
+
*
|
|
11056
|
+
* A requested interaction is durable only when the provider can replay its
|
|
11057
|
+
* event and safely replay the response command. An unsupported request fails
|
|
11058
|
+
* before environment creation or dispatch begins.
|
|
11059
|
+
*/
|
|
11060
|
+
function assertRequestedInteractionCapabilities(providerName, requested, capabilities) {
|
|
11061
|
+
const requestedKinds = Object.entries(requested ?? {}).filter(([, enabled]) => enabled === true).map(([kind]) => kind);
|
|
11062
|
+
if (requestedKinds.length === 0) return;
|
|
11063
|
+
const interactions = capabilities.interactions;
|
|
11064
|
+
if (!interactions) throw new Error(`provider "${providerName}" does not support requested interactions: ${requestedKinds.join(", ")}`);
|
|
11065
|
+
const unsupportedKinds = requestedKinds.filter((kind) => !interactions.kinds.includes(kind));
|
|
11066
|
+
if (unsupportedKinds.length > 0) throw new Error(`provider "${providerName}" does not support requested interaction kinds: ${unsupportedKinds.join(", ")}`);
|
|
11067
|
+
if (interactions.replay !== true || interactions.responseIdempotency !== true) throw new Error(`provider "${providerName}" cannot safely dispatch requested interactions without replay and response idempotency`);
|
|
11068
|
+
}
|
|
11069
|
+
//#endregion
|
|
11070
|
+
//#region src/runtime/retained-run-events.ts
|
|
11071
|
+
async function* retainedRunEvents(session, controlRef, options, now) {
|
|
11072
|
+
const after = options?.after;
|
|
11073
|
+
if (after) {
|
|
11074
|
+
assertStableText(after.cursor, "replay cursor");
|
|
11075
|
+
assertSequence(after.sequence, "replay sequence");
|
|
11076
|
+
}
|
|
11077
|
+
let nextSequence = after === void 0 ? 1 : after.sequence + 1;
|
|
11078
|
+
let lastSequence = after?.sequence ?? -1;
|
|
11079
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11080
|
+
let firstAfterEvent = after !== void 0;
|
|
11081
|
+
const iterator = session.events({
|
|
11082
|
+
...after === void 0 ? {} : { since: after.cursor },
|
|
11083
|
+
...controlRef.executionId === void 0 ? {} : { executionId: controlRef.executionId },
|
|
11084
|
+
...options?.signal === void 0 ? {} : { signal: options.signal }
|
|
11085
|
+
})[Symbol.asyncIterator]();
|
|
11086
|
+
try {
|
|
11087
|
+
for (;;) {
|
|
11088
|
+
const next = await awaitAbortable$1(Promise.resolve().then(() => iterator.next()), options?.signal);
|
|
11089
|
+
if (next.done) break;
|
|
11090
|
+
const source = next.value;
|
|
11091
|
+
const identity = extractTransportEventIdentity(source);
|
|
11092
|
+
const sourceCursor = identity.cursor ?? identity.eventId;
|
|
11093
|
+
assertEventBinding(source, controlRef);
|
|
11094
|
+
if (sourceCursor === after?.cursor) continue;
|
|
11095
|
+
const event = canonicalEvent(source);
|
|
11096
|
+
if (!event) continue;
|
|
11097
|
+
assertCanonicalEventBinding(controlRef, event);
|
|
11098
|
+
if (firstAfterEvent && after !== void 0) {
|
|
11099
|
+
if (identity.sequence !== void 0 && identity.sequence <= after.sequence) throw new Error("provider replay did not prove that the first event follows the requested cursor");
|
|
11100
|
+
firstAfterEvent = false;
|
|
11101
|
+
}
|
|
11102
|
+
const eventId = identity.eventId ?? identity.cursor;
|
|
11103
|
+
if (!eventId) throw new Error("replayable canonical event has no stable provider event id or cursor");
|
|
11104
|
+
assertStableText(eventId, "provider event id");
|
|
11105
|
+
if (seen.has(eventId)) throw new Error(`provider replay repeated event id "${eventId}"`);
|
|
11106
|
+
seen.add(eventId);
|
|
11107
|
+
const sequence = identity.sequence ?? nextSequence;
|
|
11108
|
+
if (sequence <= lastSequence) throw new Error(`provider event sequence is not monotonic: ${sequence} follows ${lastSequence}`);
|
|
11109
|
+
const occurredAt = identity.occurredAt;
|
|
11110
|
+
yield RuntimeEventEnvelopeSchema.parse({
|
|
11111
|
+
runId: controlRef.runId,
|
|
11112
|
+
eventId,
|
|
11113
|
+
sequence,
|
|
11114
|
+
cursor: identity.cursor ?? eventId,
|
|
11115
|
+
...occurredAt === void 0 ? {} : { occurredAt },
|
|
11116
|
+
receivedAt: new Date(now()).toISOString(),
|
|
11117
|
+
event
|
|
11118
|
+
});
|
|
11119
|
+
lastSequence = sequence;
|
|
11120
|
+
nextSequence = sequence + 1;
|
|
11121
|
+
}
|
|
11122
|
+
} catch (error) {
|
|
11123
|
+
if (options?.signal?.aborted) {
|
|
11124
|
+
try {
|
|
11125
|
+
Promise.resolve(iterator.return?.()).catch(() => void 0);
|
|
11126
|
+
} catch {}
|
|
11127
|
+
throw abortError(options.signal.reason);
|
|
11128
|
+
}
|
|
11129
|
+
if (error instanceof RetainedRunProviderContractError) throw error;
|
|
11130
|
+
throw new RetainedRunProviderContractError(error instanceof Error ? error.message : "provider retained event stream failed", {
|
|
11131
|
+
code: "RETAINED_EVENT_STREAM_INVALID",
|
|
11132
|
+
cause: error
|
|
11133
|
+
});
|
|
11134
|
+
} finally {
|
|
11135
|
+
if (!options?.signal?.aborted) await iterator.return?.();
|
|
11136
|
+
}
|
|
11137
|
+
}
|
|
11138
|
+
function canonicalEvent(source) {
|
|
11139
|
+
return parseCanonicalTransportEvent(source.type, source.data, source.normalized ?? source.data.normalized, "provider");
|
|
11140
|
+
}
|
|
11141
|
+
//#endregion
|
|
11142
|
+
//#region src/runtime/retained-run-handle.ts
|
|
11143
|
+
function createRetainedRunHandle(environment, session, initialControlRef, capabilities, now) {
|
|
11144
|
+
const clock = now ?? Date.now;
|
|
11145
|
+
const measuredCapabilities = structuredClone(capabilities);
|
|
11146
|
+
let activeControlRef = freezeControlRef(initialControlRef);
|
|
11147
|
+
const snapshot = async (reason, signal) => {
|
|
11148
|
+
if (signal?.aborted) throw abortError(signal.reason);
|
|
11149
|
+
let status;
|
|
11150
|
+
try {
|
|
11151
|
+
status = await awaitAbortable$1(Promise.resolve().then(() => session.status({ signal })), signal);
|
|
11152
|
+
} catch {
|
|
11153
|
+
if (signal?.aborted) throw abortError(signal.reason);
|
|
11154
|
+
status = "unknown";
|
|
11155
|
+
}
|
|
11156
|
+
const effect = status === "cancelled" ? "cancelled" : status === "completed" || status === "failed" || status === "expired" ? "not_live" : "unknown";
|
|
11157
|
+
return {
|
|
11158
|
+
runId: activeControlRef.runId,
|
|
11159
|
+
controlRef: copyControlRef(activeControlRef),
|
|
11160
|
+
status,
|
|
11161
|
+
effect,
|
|
11162
|
+
observedAt: new Date(clock()).toISOString(),
|
|
11163
|
+
...reason === void 0 ? {} : { reason },
|
|
11164
|
+
...signal?.aborted ? { signal: String(signal.reason ?? "aborted") } : {}
|
|
11165
|
+
};
|
|
11166
|
+
};
|
|
11167
|
+
return {
|
|
11168
|
+
get controlRef() {
|
|
11169
|
+
return copyControlRef(activeControlRef);
|
|
11170
|
+
},
|
|
11171
|
+
get capabilities() {
|
|
11172
|
+
return structuredClone(measuredCapabilities);
|
|
11173
|
+
},
|
|
11174
|
+
status: async (options) => {
|
|
11175
|
+
const waitMs = options?.waitMs ?? 0;
|
|
11176
|
+
assertWaitDuration(waitMs, "retained status wait");
|
|
11177
|
+
const initial = await snapshot(void 0, options?.signal);
|
|
11178
|
+
if (waitMs === 0 || isTerminalSessionStatus(initial.status)) return initial;
|
|
11179
|
+
const deadline = Date.now() + waitMs;
|
|
11180
|
+
let current = initial;
|
|
11181
|
+
while (Date.now() < deadline) {
|
|
11182
|
+
await delay(Math.min(25, Math.max(1, deadline - Date.now())), options?.signal);
|
|
11183
|
+
current = await snapshot(void 0, options?.signal);
|
|
11184
|
+
if (current.status !== initial.status || isTerminalSessionStatus(current.status)) return current;
|
|
11185
|
+
}
|
|
11186
|
+
return current;
|
|
11187
|
+
},
|
|
11188
|
+
events: (options) => retainedRunEvents(session, copyControlRef(activeControlRef), options, clock),
|
|
11189
|
+
result: async () => {
|
|
11190
|
+
let candidate;
|
|
11191
|
+
try {
|
|
11192
|
+
candidate = await exactSessionResult(session);
|
|
11193
|
+
} catch (error) {
|
|
11194
|
+
if (error instanceof RetainedRunProviderContractError) throw error;
|
|
11195
|
+
throw new RetainedRunProviderContractError(error instanceof Error ? error.message : "provider retained result read failed", {
|
|
11196
|
+
code: "RETAINED_RESULT_READ_FAILED",
|
|
11197
|
+
cause: error
|
|
11198
|
+
});
|
|
11199
|
+
}
|
|
11200
|
+
const parsed = AgentTurnResultSchema.safeParse(candidate);
|
|
11201
|
+
if (!parsed.success) throw new RetainedRunProviderContractError("provider returned an invalid retained result", {
|
|
11202
|
+
code: "RETAINED_RESULT_SCHEMA_INVALID",
|
|
11203
|
+
cause: parsed.error
|
|
11204
|
+
});
|
|
11205
|
+
try {
|
|
11206
|
+
assertResultBinding(activeControlRef, parsed.data);
|
|
11207
|
+
} catch (error) {
|
|
11208
|
+
throw new RetainedRunProviderContractError(error instanceof Error ? error.message : "provider returned an unbound retained result", {
|
|
11209
|
+
code: "RETAINED_RESULT_BINDING_INVALID",
|
|
11210
|
+
cause: error
|
|
11211
|
+
});
|
|
11212
|
+
}
|
|
11213
|
+
return structuredClone(parsed.data);
|
|
11214
|
+
},
|
|
11215
|
+
async respondToInteraction(command, options) {
|
|
11216
|
+
const exactCommand = InteractionResponseCommandSchema.parse(command);
|
|
11217
|
+
assertInteractionBinding(activeControlRef, exactCommand);
|
|
11218
|
+
if (measuredCapabilities.interactions?.replay !== true || measuredCapabilities.interactions.responseIdempotency !== true) throw new Error(`provider "${activeControlRef.provider}" does not promise retry-safe interaction responses`);
|
|
11219
|
+
const respond = session.respondToInteraction ?? environment.respondToInteraction;
|
|
11220
|
+
if (!respond) throw new Error(`provider "${activeControlRef.provider}" does not support interaction responses`);
|
|
11221
|
+
const acknowledgement = InteractionAcknowledgementSchema.parse(await awaitAbortable$1(Promise.resolve().then(() => respond.call(session.respondToInteraction ? session : environment, exactCommand, options)), options?.signal));
|
|
11222
|
+
if (acknowledgement.operationId !== exactCommand.operationId || acknowledgement.commandDigest !== exactCommand.commandDigest || canonicalCandidateDigest(acknowledgement.binding) !== canonicalCandidateDigest(exactCommand.binding)) throw new Error("provider returned an interaction acknowledgement for another command");
|
|
11223
|
+
return structuredClone(acknowledgement);
|
|
11224
|
+
},
|
|
11225
|
+
async contextBoundary(options) {
|
|
11226
|
+
if (!session.contextBoundary) return null;
|
|
11227
|
+
const proof = await awaitAbortable$1(Promise.resolve().then(() => session.contextBoundary(options)), options?.signal);
|
|
11228
|
+
if (proof === null) return null;
|
|
11229
|
+
const exactProof = NativeContextBoundaryProofSchema.parse(proof);
|
|
11230
|
+
assertBoundaryBinding(activeControlRef, exactProof);
|
|
11231
|
+
return structuredClone(exactProof);
|
|
11232
|
+
},
|
|
11233
|
+
async continueNative(request, turn) {
|
|
11234
|
+
const exactRequest = NativeContextContinuationRequestSchema.parse(request);
|
|
11235
|
+
if (!sameControlCoordinates(exactRequest.run, activeControlRef)) throw new Error("native continuation request targets another retained run");
|
|
11236
|
+
const { timeoutMs, signal, ...semanticTurn } = turn;
|
|
11237
|
+
if (nativeContextContinuationTurnDigest(semanticTurn) !== exactRequest.turnDigest) throw new Error("native continuation request targets another user turn");
|
|
11238
|
+
if (measuredCapabilities.nativeContinuation?.atomicBoundary !== true || measuredCapabilities.nativeContinuation.requestIdempotency !== true || !session.continueNative) throw new Error(`provider "${activeControlRef.provider}" does not support retry-safe native continuation`);
|
|
11239
|
+
const outcome = AgentNativeContextContinuationResultSchema.parse(await awaitAbortable$1(Promise.resolve().then(() => session.continueNative(exactRequest, {
|
|
11240
|
+
turn: semanticTurn,
|
|
11241
|
+
...timeoutMs === void 0 ? {} : { timeoutMs },
|
|
11242
|
+
...signal === void 0 ? {} : { signal }
|
|
11243
|
+
})), signal));
|
|
11244
|
+
if (outcome.acknowledgement.operationId !== exactRequest.operationId || outcome.acknowledgement.requestDigest !== exactRequest.requestDigest) throw new Error("provider returned a native continuation result for another request");
|
|
11245
|
+
if (outcome.acknowledgement.actualBoundary !== void 0) {
|
|
11246
|
+
const actualBoundary = NativeContextBoundaryProofSchema.parse(outcome.acknowledgement.actualBoundary);
|
|
11247
|
+
assertBoundaryBinding(exactRequest.run, actualBoundary);
|
|
11248
|
+
}
|
|
11249
|
+
if (outcome.acknowledgement.status !== "accepted" && outcome.acknowledgement.status !== "replayed") return structuredClone(outcome);
|
|
11250
|
+
if (!("result" in outcome) || !("controlRef" in outcome)) throw new Error("provider omitted the successful native continuation result");
|
|
11251
|
+
if (!agentNativeContextContinuationResultMatchesRequest(exactRequest, outcome)) throw new Error("provider returned a native continuation result for another request");
|
|
11252
|
+
const nextControlRef = exactContinuedControlRef(outcome.controlRef, activeControlRef);
|
|
11253
|
+
assertResultBinding(nextControlRef, outcome.result);
|
|
11254
|
+
activeControlRef = freezeControlRef(nextControlRef);
|
|
11255
|
+
return structuredClone({
|
|
11256
|
+
...outcome,
|
|
11257
|
+
controlRef: copyControlRef(activeControlRef)
|
|
11258
|
+
});
|
|
11259
|
+
},
|
|
11260
|
+
async cancel(options) {
|
|
11261
|
+
assertStableText(options.operationId, "retained cancellation operation id");
|
|
11262
|
+
if (options.reason !== void 0) assertStableText(options.reason, "retained cancellation reason");
|
|
11263
|
+
if (options.signal?.aborted) throw abortError(options.signal.reason);
|
|
11264
|
+
if (!hasDurableCancel(session)) throw new Error(`provider "${activeControlRef.provider}" does not expose durable cancellation operations`);
|
|
11265
|
+
const request = cancellationRequest(activeControlRef, options.operationId, options.reason);
|
|
11266
|
+
let effect = "unknown";
|
|
11267
|
+
let providerStatus;
|
|
11268
|
+
try {
|
|
11269
|
+
const acknowledgement = await exactSessionCancel(session, request, { signal: options.signal });
|
|
11270
|
+
effect = acknowledgement.effect;
|
|
11271
|
+
providerStatus = acknowledgement.status;
|
|
11272
|
+
} catch (error) {
|
|
11273
|
+
if (error instanceof RetainedRunProviderContractError) throw error;
|
|
11274
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
11275
|
+
effect = "unknown";
|
|
11276
|
+
}
|
|
11277
|
+
const current = await snapshot(options.reason, options.signal);
|
|
11278
|
+
const observedEffect = effect === "unknown" && providerStatus === void 0 && current.status === "cancelled" ? "cancelled" : effect;
|
|
11279
|
+
const acknowledgement = {
|
|
11280
|
+
operationId: options.operationId,
|
|
11281
|
+
requestDigest: request.requestDigest,
|
|
11282
|
+
status: providerStatus ?? (observedEffect === "unknown" ? "unknown" : "accepted"),
|
|
11283
|
+
effect: observedEffect,
|
|
11284
|
+
snapshot: {
|
|
11285
|
+
...current,
|
|
11286
|
+
effect: observedEffect
|
|
11287
|
+
},
|
|
11288
|
+
...options.reason === void 0 ? {} : { reason: options.reason },
|
|
11289
|
+
...options.signal?.aborted ? { signal: String(options.signal.reason ?? "aborted") } : {}
|
|
11290
|
+
};
|
|
11291
|
+
return structuredClone(acknowledgement);
|
|
11292
|
+
}
|
|
11293
|
+
};
|
|
11294
|
+
}
|
|
11295
|
+
//#endregion
|
|
11296
|
+
//#region src/runtime/retained-run-start.ts
|
|
11297
|
+
/**
|
|
11298
|
+
* Mint deterministic dispatch coordinates from the two caller-supplied keys.
|
|
11299
|
+
* The same `(idempotencyKey, turnId)` pair yields the same coordinates in
|
|
11300
|
+
* every process, so a pre-dispatch admission record always names the exact
|
|
11301
|
+
* session and execution the dispatch will request. Format is readable, not
|
|
11302
|
+
* hashed, following `deriveExecutionId`: components are URL-encoded so
|
|
11303
|
+
* delimiters inside caller keys cannot collapse distinct pairs, and the
|
|
11304
|
+
* result stays inside the 256-byte identifier bound.
|
|
11305
|
+
*/
|
|
11306
|
+
function mintRetainedIdentity(idempotencyKey, turnId) {
|
|
11307
|
+
const base = `${encodeURIComponent(idempotencyKey)}:${encodeURIComponent(turnId)}`;
|
|
11308
|
+
const sessionId = `retained-session:${base}`;
|
|
11309
|
+
const executionId = `retained-execution:${base}`;
|
|
11310
|
+
if (executionId.length > 256) throw new RangeError("minted retained identity must not exceed 256 bytes");
|
|
11311
|
+
return {
|
|
11312
|
+
sessionId,
|
|
11313
|
+
executionId
|
|
11314
|
+
};
|
|
11315
|
+
}
|
|
11316
|
+
/**
|
|
11317
|
+
* Dispatch one detached, replayable run and return only after exact durable
|
|
11318
|
+
* coordinates are confirmed by the provider and persisted by the caller.
|
|
11319
|
+
*
|
|
11320
|
+
* The required `onAdmission` hook first records a digest-only intent before
|
|
11321
|
+
* creation, then records recovery coordinates and the verified exact control
|
|
11322
|
+
* reference. The returned promise resolves only after the dispatched admission
|
|
11323
|
+
* is durable, so a crash cannot lose a successful start's exact reference.
|
|
11324
|
+
*
|
|
11325
|
+
* @stable
|
|
11326
|
+
*/
|
|
11327
|
+
async function startRetainedRun(options) {
|
|
11328
|
+
assertStableText(options.environment.idempotencyKey, "environment idempotency key");
|
|
11329
|
+
assertStableText(options.turn.turnId, "turn idempotency key");
|
|
11330
|
+
if (options.identity !== void 0) {
|
|
11331
|
+
assertStableText(options.identity.sessionId, "retained session id");
|
|
11332
|
+
assertStableText(options.identity.executionId, "retained execution id");
|
|
11333
|
+
}
|
|
11334
|
+
if (typeof options.onAdmission !== "function") throw new Error("startRetainedRun requires an awaited onAdmission durability hook");
|
|
11335
|
+
const identity = options.identity ?? mintRetainedIdentity(options.environment.idempotencyKey, options.turn.turnId);
|
|
11336
|
+
if (!options.provider.get) throw new Error(`provider "${options.provider.name}" cannot reconstruct an environment by id`);
|
|
11337
|
+
const intent = retainedRunIntent(options, identity);
|
|
11338
|
+
if (options.intent === void 0) await admitDurably(options.onAdmission, intent);
|
|
11339
|
+
else assertExactRetainedRunIntent(options.intent, intent);
|
|
11340
|
+
const providerCapabilities = await assertRetainedCapabilities(options.provider);
|
|
11341
|
+
assertRequestedInteractionCapabilities(options.provider.name, options.turn.interactions, providerCapabilities);
|
|
11342
|
+
const environment = await options.provider.create({
|
|
11343
|
+
...options.environment,
|
|
11344
|
+
metadata: retainedEnvironmentMetadata(options.environment.metadata, options.environment.idempotencyKey)
|
|
11345
|
+
});
|
|
11346
|
+
let capabilities;
|
|
11347
|
+
try {
|
|
11348
|
+
capabilities = retainedCapabilitiesForEnvironment(options.provider.name, providerCapabilities, environment);
|
|
11349
|
+
assertRequestedInteractionCapabilities(options.provider.name, options.turn.interactions, capabilities);
|
|
11350
|
+
} catch (error) {
|
|
11351
|
+
try {
|
|
11352
|
+
await environment.destroy?.();
|
|
11353
|
+
} catch (cleanupError) {
|
|
11354
|
+
throw new AggregateError([error, cleanupError], "retained run environment published invalid capabilities and could not be destroyed");
|
|
11355
|
+
}
|
|
11356
|
+
throw error;
|
|
11357
|
+
}
|
|
11358
|
+
if (!environment.dispatch || !environment.session) {
|
|
11359
|
+
try {
|
|
11360
|
+
await environment.destroy?.();
|
|
11361
|
+
} catch (cleanupError) {
|
|
11362
|
+
throw new AggregateError([/* @__PURE__ */ new Error(`provider "${options.provider.name}" does not expose detached session control`), cleanupError], "retained run could not start and its unused environment could not be destroyed");
|
|
11363
|
+
}
|
|
11364
|
+
throw new Error(`provider "${options.provider.name}" does not expose detached session control`);
|
|
11365
|
+
}
|
|
11366
|
+
return dispatchRetainedRun({
|
|
11367
|
+
provider: options.provider,
|
|
11368
|
+
environment,
|
|
11369
|
+
environmentIdempotencyKey: options.environment.idempotencyKey,
|
|
11370
|
+
turn: options.turn,
|
|
11371
|
+
identity,
|
|
11372
|
+
onAdmission: options.onAdmission,
|
|
11373
|
+
capabilities,
|
|
11374
|
+
now: options.now
|
|
11375
|
+
});
|
|
11376
|
+
}
|
|
11377
|
+
/**
|
|
11378
|
+
* Dispatch a fresh retained session inside an existing provider environment.
|
|
11379
|
+
*
|
|
11380
|
+
* This operation reuses only the environment. It does not append to a prior
|
|
11381
|
+
* harness chat and does not claim native conversation continuity. The caller
|
|
11382
|
+
* must use `RetainedRunHandle.continueNative` for a verified same-chat turn.
|
|
11383
|
+
*
|
|
11384
|
+
* @stable
|
|
11385
|
+
*/
|
|
11386
|
+
async function startRetainedRunInEnvironment(options) {
|
|
11387
|
+
assertStableText(options.environment.id, "retained environment id");
|
|
11388
|
+
assertStableText(options.environment.idempotencyKey, "environment idempotency key");
|
|
11389
|
+
assertStableText(options.turn.turnId, "turn idempotency key");
|
|
11390
|
+
if (options.identity !== void 0) {
|
|
11391
|
+
assertStableText(options.identity.sessionId, "retained session id");
|
|
11392
|
+
assertStableText(options.identity.executionId, "retained execution id");
|
|
11393
|
+
}
|
|
11394
|
+
if (typeof options.onAdmission !== "function") throw new Error("startRetainedRunInEnvironment requires an awaited onAdmission durability hook");
|
|
11395
|
+
const identity = options.identity ?? mintRetainedIdentity(options.environment.idempotencyKey, options.turn.turnId);
|
|
11396
|
+
const providerCapabilities = await assertRetainedCapabilities(options.provider);
|
|
11397
|
+
if (!options.provider.get) throw new Error(`provider "${options.provider.name}" cannot reconstruct an environment by id`);
|
|
11398
|
+
const environment = await options.provider.get(options.environment.id);
|
|
11399
|
+
if (!environment) throw new Error(`provider "${options.provider.name}" no longer holds environment "${options.environment.id}"`);
|
|
11400
|
+
if (environment.id !== options.environment.id || environment.provider !== options.provider.name) throw new Error("provider reconstructed a different retained environment");
|
|
11401
|
+
const capabilities = retainedCapabilitiesForEnvironment(options.provider.name, providerCapabilities, environment);
|
|
11402
|
+
assertRequestedInteractionCapabilities(options.provider.name, options.turn.interactions, capabilities);
|
|
11403
|
+
if (!environment.dispatch || !environment.session) throw new Error(`provider "${options.provider.name}" does not expose detached session control`);
|
|
11404
|
+
await assertRetainedEnvironmentOwnership(options.provider, environment.id, options.environment.idempotencyKey);
|
|
11405
|
+
return dispatchRetainedRun({
|
|
11406
|
+
provider: options.provider,
|
|
11407
|
+
environment,
|
|
11408
|
+
environmentIdempotencyKey: options.environment.idempotencyKey,
|
|
11409
|
+
turn: options.turn,
|
|
11410
|
+
identity,
|
|
11411
|
+
onAdmission: options.onAdmission,
|
|
11412
|
+
capabilities,
|
|
11413
|
+
now: options.now
|
|
11414
|
+
});
|
|
11415
|
+
}
|
|
11416
|
+
async function assertRetainedEnvironmentOwnership(provider, environmentId, idempotencyKey) {
|
|
11417
|
+
if (!provider.list) throw new Error(`provider "${provider.name}" cannot prove retained environment ownership by metadata`);
|
|
11418
|
+
const matches = (await provider.list({ metadata: { retainedIdempotencyKey: idempotencyKey } })).filter((summary) => summary.id === environmentId && summary.provider === provider.name);
|
|
11419
|
+
if (matches.length !== 1 || matches[0]?.metadata?.retainedIdempotencyKey !== idempotencyKey) throw new Error(`provider "${provider.name}" could not bind environment "${environmentId}" to its retained idempotency key`);
|
|
11420
|
+
}
|
|
11421
|
+
async function dispatchRetainedRun(options) {
|
|
11422
|
+
const { environment, identity } = options;
|
|
11423
|
+
assertRequestedInteractionCapabilities(options.provider.name, options.turn.interactions, options.capabilities);
|
|
11424
|
+
await admitDurably(options.onAdmission, {
|
|
11425
|
+
phase: "environment",
|
|
11426
|
+
provider: options.provider.name,
|
|
11427
|
+
environmentId: environment.id,
|
|
11428
|
+
idempotencyKey: options.environmentIdempotencyKey,
|
|
11429
|
+
turnId: options.turn.turnId,
|
|
11430
|
+
sessionId: identity.sessionId,
|
|
11431
|
+
executionId: identity.executionId
|
|
11432
|
+
});
|
|
11433
|
+
const destroyIfCreated = async (cause) => {
|
|
11434
|
+
if (environment.creation !== "created") throw cause;
|
|
11435
|
+
try {
|
|
11436
|
+
await environment.destroy?.();
|
|
11437
|
+
} catch (cleanupError) {
|
|
11438
|
+
throw new AggregateError([cause, cleanupError], "retained run dispatch failed and the environment it created could not be destroyed");
|
|
11439
|
+
}
|
|
11440
|
+
throw cause;
|
|
11441
|
+
};
|
|
11442
|
+
let reference;
|
|
11443
|
+
try {
|
|
11444
|
+
reference = await environment.dispatch(freshTurnInput(options.turn, {
|
|
11445
|
+
turnId: options.turn.turnId,
|
|
11446
|
+
detach: true,
|
|
11447
|
+
...identity
|
|
11448
|
+
}));
|
|
11449
|
+
} catch (error) {
|
|
11450
|
+
await destroyIfCreated(error);
|
|
11451
|
+
throw error;
|
|
11452
|
+
}
|
|
11453
|
+
let exact;
|
|
11454
|
+
try {
|
|
11455
|
+
if (reference.provider !== void 0 && reference.provider !== options.provider.name) throw new Error("provider dispatch returned a session reference for another provider");
|
|
11456
|
+
if (reference.id !== identity.sessionId) throw new Error("provider dispatched into another session than the requested identity");
|
|
11457
|
+
const controlRef = exactControlRef(reference.controlRef, {
|
|
11458
|
+
provider: options.provider.name,
|
|
11459
|
+
environmentId: environment.id,
|
|
11460
|
+
sessionId: identity.sessionId
|
|
11461
|
+
});
|
|
11462
|
+
if (controlRef.executionId !== identity.executionId) throw new Error("provider bound another execution than the requested identity");
|
|
11463
|
+
exact = exactSession(environment, controlRef);
|
|
11464
|
+
} catch (error) {
|
|
11465
|
+
const bindingError = new RetainedRunDispatchBindingError({
|
|
11466
|
+
provider: options.provider.name,
|
|
11467
|
+
environmentId: environment.id,
|
|
11468
|
+
sessionId: identity.sessionId,
|
|
11469
|
+
executionId: identity.executionId
|
|
11470
|
+
}, {
|
|
11471
|
+
...reference.id === void 0 ? {} : { id: reference.id },
|
|
11472
|
+
...reference.provider === void 0 ? {} : { provider: reference.provider },
|
|
11473
|
+
...reference.controlRef === void 0 ? {} : { controlRef: reference.controlRef }
|
|
11474
|
+
}, { cause: error });
|
|
11475
|
+
await destroyIfCreated(bindingError);
|
|
11476
|
+
throw bindingError;
|
|
11477
|
+
}
|
|
11478
|
+
await admitDurably(options.onAdmission, {
|
|
11479
|
+
phase: "dispatched",
|
|
11480
|
+
controlRef: freezeControlRef(exact.controlRef),
|
|
11481
|
+
idempotencyKey: options.environmentIdempotencyKey,
|
|
11482
|
+
turnId: options.turn.turnId
|
|
11483
|
+
});
|
|
11484
|
+
return createRetainedRunHandle(environment, exact.session, exact.controlRef, options.capabilities, options.now);
|
|
11485
|
+
}
|
|
11486
|
+
/**
|
|
11487
|
+
* Await one admission record through the caller's durability hook. A rejection
|
|
11488
|
+
* keeps the environment alive — the provider state plus any partial admission
|
|
11489
|
+
* record is the recovery path — and surfaces as `RetainedRunAdmissionError` so
|
|
11490
|
+
* callers can distinguish a persistence failure from a provider failure.
|
|
11491
|
+
*/
|
|
11492
|
+
async function admitDurably(onAdmission, admission) {
|
|
11493
|
+
const stableAdmission = detachedSnapshot(admission, "retained run admission");
|
|
11494
|
+
try {
|
|
11495
|
+
await onAdmission(stableAdmission);
|
|
11496
|
+
} catch (error) {
|
|
11497
|
+
if (isInteractiveAdmission(stableAdmission)) throw new RetainedInteractiveAdmissionError(stableAdmission, { cause: error });
|
|
11498
|
+
throw new RetainedRunAdmissionError(stableAdmission, { cause: error });
|
|
11499
|
+
}
|
|
11500
|
+
}
|
|
11501
|
+
function isInteractiveAdmission(admission) {
|
|
11502
|
+
return admission.phase === "interactive_intent" || admission.phase === "interactive_environment" || admission.phase === "interactive_started";
|
|
11503
|
+
}
|
|
11504
|
+
async function recoverRetainedRun(options) {
|
|
11505
|
+
if ("admission" in options) {
|
|
11506
|
+
if (options.admission.provider !== options.provider.name) throw new Error("retained run intent belongs to another provider");
|
|
11507
|
+
return {
|
|
11508
|
+
outcome: "recovered",
|
|
11509
|
+
handle: await startRetainedRun({
|
|
11510
|
+
provider: options.provider,
|
|
11511
|
+
...options.replay,
|
|
11512
|
+
intent: options.admission,
|
|
11513
|
+
onAdmission: options.onAdmission,
|
|
11514
|
+
now: options.now
|
|
11515
|
+
})
|
|
11516
|
+
};
|
|
11517
|
+
}
|
|
11518
|
+
assertStableText(options.environmentId, "retained environment id");
|
|
11519
|
+
assertStableText(options.sessionId, "retained session id");
|
|
11520
|
+
assertStableText(options.executionId, "retained execution id");
|
|
11521
|
+
const providerCapabilities = await assertRetainedCapabilities(options.provider);
|
|
11522
|
+
if (!options.provider.get) throw new Error(`provider "${options.provider.name}" cannot reconstruct an environment by id`);
|
|
11523
|
+
const environment = await options.provider.get(options.environmentId);
|
|
11524
|
+
if (!environment) return { outcome: "not_found" };
|
|
11525
|
+
const capabilities = retainedCapabilitiesForEnvironment(options.provider.name, providerCapabilities, environment);
|
|
11526
|
+
if (!environment.session) return {
|
|
11527
|
+
outcome: "unverifiable",
|
|
11528
|
+
environment
|
|
11529
|
+
};
|
|
11530
|
+
let session;
|
|
11531
|
+
try {
|
|
11532
|
+
session = environment.session(options.sessionId);
|
|
11533
|
+
} catch {
|
|
11534
|
+
return {
|
|
11535
|
+
outcome: "unverifiable",
|
|
11536
|
+
environment
|
|
11537
|
+
};
|
|
11538
|
+
}
|
|
11539
|
+
const parsed = AgentExactRunControlRefSchema.safeParse(session.controlRef);
|
|
11540
|
+
if (!parsed.success) return {
|
|
11541
|
+
outcome: "unverifiable",
|
|
11542
|
+
environment
|
|
11543
|
+
};
|
|
11544
|
+
const controlRef = parsed.data;
|
|
11545
|
+
if (controlRef.provider !== options.provider.name || controlRef.environmentId !== options.environmentId || controlRef.sessionId !== options.sessionId || controlRef.executionId !== options.executionId) throw new Error("provider session is bound to other retained run coordinates");
|
|
11546
|
+
const exact = exactSession(environment, controlRef);
|
|
11547
|
+
return {
|
|
11548
|
+
outcome: "recovered",
|
|
11549
|
+
handle: createRetainedRunHandle(environment, exact.session, exact.controlRef, capabilities, options.now)
|
|
11550
|
+
};
|
|
11551
|
+
}
|
|
11552
|
+
function retainedRunIntent(options, identity) {
|
|
11553
|
+
const requestedProfileDigest = canonicalCandidateDigest(options.environment.profile);
|
|
11554
|
+
const requestDigest = canonicalCandidateDigest({
|
|
11555
|
+
kind: "retained-run-intent.v1",
|
|
11556
|
+
provider: options.provider.name,
|
|
11557
|
+
idempotencyKey: options.environment.idempotencyKey,
|
|
11558
|
+
turnId: options.turn.turnId,
|
|
11559
|
+
sessionId: identity.sessionId,
|
|
11560
|
+
executionId: identity.executionId,
|
|
11561
|
+
requestedProfileDigest,
|
|
11562
|
+
create: retainedCreateMaterial(options.environment),
|
|
11563
|
+
turn: retainedTurnMaterial(options.turn)
|
|
11564
|
+
});
|
|
11565
|
+
return {
|
|
11566
|
+
phase: "intent",
|
|
11567
|
+
provider: options.provider.name,
|
|
11568
|
+
idempotencyKey: options.environment.idempotencyKey,
|
|
11569
|
+
turnId: options.turn.turnId,
|
|
11570
|
+
sessionId: identity.sessionId,
|
|
11571
|
+
executionId: identity.executionId,
|
|
11572
|
+
runId: `retained-intent-run:${requestDigest.slice(7)}`,
|
|
11573
|
+
requestedProfileDigest,
|
|
11574
|
+
requestDigest
|
|
11575
|
+
};
|
|
11576
|
+
}
|
|
11577
|
+
function assertExactRetainedRunIntent(received, expected) {
|
|
11578
|
+
if (canonicalCandidateDigest(parseRetainedRunIntent(received)) !== canonicalCandidateDigest(expected)) throw new Error("retained run intent conflicts with replay material");
|
|
11579
|
+
}
|
|
11580
|
+
function parseRetainedRunIntent(value) {
|
|
11581
|
+
const stable = detachedSnapshot(value, "retained run intent");
|
|
11582
|
+
if (stable === null || typeof stable !== "object" || Array.isArray(stable)) throw new Error("retained run intent is malformed");
|
|
11583
|
+
const record = stable;
|
|
11584
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
11585
|
+
"phase",
|
|
11586
|
+
"provider",
|
|
11587
|
+
"idempotencyKey",
|
|
11588
|
+
"turnId",
|
|
11589
|
+
"sessionId",
|
|
11590
|
+
"executionId",
|
|
11591
|
+
"runId",
|
|
11592
|
+
"requestedProfileDigest",
|
|
11593
|
+
"requestDigest"
|
|
11594
|
+
]);
|
|
11595
|
+
if (Object.keys(record).some((key) => !allowed.has(key))) throw new Error("retained run intent contains unsupported material");
|
|
11596
|
+
if (record.phase !== "intent") throw new Error("retained run intent has an invalid phase");
|
|
11597
|
+
for (const [key, value] of Object.entries(record)) {
|
|
11598
|
+
if (key === "phase") continue;
|
|
11599
|
+
if (typeof value !== "string" || value.length === 0) throw new Error(`retained run intent field "${key}" is invalid`);
|
|
11600
|
+
}
|
|
11601
|
+
assertDigest$2(record.requestedProfileDigest, "retained run intent profile digest");
|
|
11602
|
+
assertDigest$2(record.requestDigest, "retained run intent request digest");
|
|
11603
|
+
return stable;
|
|
11604
|
+
}
|
|
11605
|
+
function assertDigest$2(value, label) {
|
|
11606
|
+
if (typeof value !== "string" || !/^sha256:[a-f0-9]{64}$/u.test(value)) throw new Error(`${label} is invalid`);
|
|
11607
|
+
}
|
|
11608
|
+
/** Rebuild a retained-run client without retaining any object from the starter. @stable */
|
|
11609
|
+
async function reconnectRetainedRun(options) {
|
|
11610
|
+
const controlRef = AgentExactRunControlRefSchema.parse(options.controlRef);
|
|
11611
|
+
if (controlRef.provider !== options.provider.name) throw new Error(`run provider "${controlRef.provider}" does not match "${options.provider.name}"`);
|
|
11612
|
+
const providerCapabilities = await assertRetainedCapabilities(options.provider);
|
|
11613
|
+
if (!options.provider.get) throw new Error(`provider "${options.provider.name}" cannot reconstruct an environment by id`);
|
|
11614
|
+
const environment = await options.provider.get(controlRef.environmentId);
|
|
11615
|
+
if (!environment) return null;
|
|
11616
|
+
const capabilities = retainedCapabilitiesForEnvironment(options.provider.name, providerCapabilities, environment);
|
|
11617
|
+
const exact = exactSession(environment, controlRef);
|
|
11618
|
+
return createRetainedRunHandle(environment, exact.session, exact.controlRef, capabilities, options.now);
|
|
11619
|
+
}
|
|
11620
|
+
async function assertRetainedCapabilities(provider) {
|
|
11621
|
+
const capabilities = AgentEnvironmentCapabilitiesSchema.parse(await provider.capabilities());
|
|
11622
|
+
assertRetainedCapabilityRequirements(provider.name, capabilities);
|
|
11623
|
+
return capabilities;
|
|
11624
|
+
}
|
|
11625
|
+
/**
|
|
11626
|
+
* Select the capability document for one concrete environment.
|
|
11627
|
+
*
|
|
11628
|
+
* A measured environment document is authoritative. An absent document uses
|
|
11629
|
+
* the provider document because that provider claims the same guarantee for
|
|
11630
|
+
* every environment it creates.
|
|
11631
|
+
*/
|
|
11632
|
+
function retainedCapabilitiesForEnvironment(providerName, providerCapabilities, environment) {
|
|
11633
|
+
if (environment.capabilities === void 0) return providerCapabilities;
|
|
11634
|
+
const measured = AgentEnvironmentCapabilitiesSchema.parse(environment.capabilities);
|
|
11635
|
+
assertRetainedCapabilityRequirements(providerName, measured);
|
|
11636
|
+
return measured;
|
|
11637
|
+
}
|
|
11638
|
+
function assertRetainedCapabilityRequirements(providerName, capabilities) {
|
|
11639
|
+
const retained = capabilities.retainedControl;
|
|
11640
|
+
if (retained?.exactRunIdentity !== true || retained.resultIdentity !== true || retained.eventIdentity !== true || retained.cancellationIdempotency !== true || !capabilities.streaming.detach || !capabilities.streaming.replay || !capabilities.streaming.turnIdempotency) throw new Error(`provider "${providerName}" cannot control a retry-safe retained run`);
|
|
11641
|
+
}
|
|
11642
|
+
//#endregion
|
|
11643
|
+
//#region src/runtime/retained-interactive.ts
|
|
11644
|
+
/**
|
|
11645
|
+
* Start one retry-safe native coding-agent TUI without dispatching a headless turn.
|
|
11646
|
+
* The intent admission is durable before provider.create; the environment and
|
|
11647
|
+
* process admissions follow only after their exact provider coordinates exist.
|
|
11648
|
+
* @stable
|
|
11649
|
+
*/
|
|
11650
|
+
async function startRetainedInteractiveRun(options) {
|
|
11651
|
+
options.signal?.throwIfAborted();
|
|
11652
|
+
assertStableText(options.environment.idempotencyKey, "environment idempotency key");
|
|
11653
|
+
assertStableText(options.interactiveIdempotencyKey, "interactive idempotency key");
|
|
11654
|
+
if (typeof options.onAdmission !== "function") throw new Error("startRetainedInteractiveRun requires an awaited onAdmission durability hook");
|
|
11655
|
+
if (!options.provider.get) throw new Error(`provider "${options.provider.name}" cannot reconstruct an environment by id`);
|
|
11656
|
+
const profile = agentProfileSchema.parse(options.environment.profile);
|
|
11657
|
+
if (profile.harness === void 0) throw new Error("retained interactive runs require AgentProfile.harness");
|
|
11658
|
+
const requestedProfileDigest = canonicalAgentProfileDigest(profile);
|
|
11659
|
+
const identity = mintRetainedIdentity(options.environment.idempotencyKey, options.interactiveIdempotencyKey);
|
|
11660
|
+
const intent = interactiveIntent(options, profile, identity);
|
|
11661
|
+
if (options.intent === void 0) await admitDurably(options.onAdmission, intent);
|
|
11662
|
+
else assertExactInteractiveIntent(options.intent, intent);
|
|
11663
|
+
const providerCapabilities = AgentEnvironmentCapabilitiesSchema.parse(await awaitAbortable$1(Promise.resolve().then(() => options.provider.capabilities()), options.signal));
|
|
11664
|
+
assertInteractiveCapabilities(options.provider.name, providerCapabilities);
|
|
11665
|
+
const environment = await createInteractiveEnvironment(() => options.provider.create({
|
|
11666
|
+
...options.environment,
|
|
11667
|
+
profile,
|
|
11668
|
+
signal: options.signal,
|
|
11669
|
+
metadata: retainedEnvironmentMetadata(options.environment.metadata, options.environment.idempotencyKey)
|
|
11670
|
+
}), options.signal);
|
|
11671
|
+
let capabilities;
|
|
11672
|
+
try {
|
|
11673
|
+
assertExactEnvironment(options.provider.name, environment);
|
|
11674
|
+
options.signal?.throwIfAborted();
|
|
11675
|
+
capabilities = interactiveCapabilitiesForEnvironment(options.provider.name, providerCapabilities, environment);
|
|
11676
|
+
assertInteractiveMethods(options.provider.name, environment);
|
|
11677
|
+
} catch (error) {
|
|
11678
|
+
await destroyUnusedEnvironment(environment, error);
|
|
11679
|
+
throw error;
|
|
11680
|
+
}
|
|
11681
|
+
const request = interactiveRequest(options, environment, profile, requestedProfileDigest, identity);
|
|
11682
|
+
await admitDurably(options.onAdmission, {
|
|
11683
|
+
phase: "interactive_environment",
|
|
11684
|
+
provider: options.provider.name,
|
|
11685
|
+
environmentId: environment.id,
|
|
11686
|
+
idempotencyKey: options.environment.idempotencyKey,
|
|
11687
|
+
interactiveIdempotencyKey: options.interactiveIdempotencyKey,
|
|
11688
|
+
request
|
|
11689
|
+
});
|
|
11690
|
+
const ref = exactStartedRef(request, await startInteractiveProcess(environment, () => environment.startInteractive(request, { signal: options.signal }), options.signal));
|
|
11691
|
+
await admitDurably(options.onAdmission, {
|
|
11692
|
+
phase: "interactive_started",
|
|
11693
|
+
idempotencyKey: options.environment.idempotencyKey,
|
|
11694
|
+
interactiveIdempotencyKey: options.interactiveIdempotencyKey,
|
|
11695
|
+
ref
|
|
11696
|
+
});
|
|
11697
|
+
return createRetainedInteractiveRunHandle(environment, ref, capabilities, request);
|
|
11698
|
+
}
|
|
11699
|
+
/** Retry one exact start after its provider response may have been lost. @stable */
|
|
11700
|
+
async function recoverRetainedInteractiveRun(options) {
|
|
11701
|
+
options.signal?.throwIfAborted();
|
|
11702
|
+
if (typeof options.onAdmission !== "function") throw new Error("recoverRetainedInteractiveRun requires an awaited onAdmission durability hook");
|
|
11703
|
+
const admission = options.admission;
|
|
11704
|
+
if (admission.provider !== options.provider.name) throw new Error("interactive admission belongs to another provider");
|
|
11705
|
+
if (admission.phase === "interactive_intent") {
|
|
11706
|
+
if (options.replay === void 0) throw new Error("recoverRetainedInteractiveRun requires the original start material for an interactive intent");
|
|
11707
|
+
return startRetainedInteractiveRun({
|
|
11708
|
+
provider: options.provider,
|
|
11709
|
+
...options.replay,
|
|
11710
|
+
intent: admission,
|
|
11711
|
+
onAdmission: options.onAdmission,
|
|
11712
|
+
signal: options.signal
|
|
11713
|
+
});
|
|
11714
|
+
}
|
|
11715
|
+
const request = exactRecoveryRequest(admission);
|
|
11716
|
+
const { environment, capabilities } = await reconstructEnvironment(options.provider, admission.environmentId, options.signal);
|
|
11717
|
+
if (!environment || !capabilities) return null;
|
|
11718
|
+
const ref = exactStartedRef(request, await awaitAbortable$1(Promise.resolve().then(() => environment.startInteractive(request, { signal: options.signal })), options.signal));
|
|
11719
|
+
await admitDurably(options.onAdmission, {
|
|
11720
|
+
phase: "interactive_started",
|
|
11721
|
+
idempotencyKey: admission.idempotencyKey,
|
|
11722
|
+
interactiveIdempotencyKey: admission.interactiveIdempotencyKey,
|
|
11723
|
+
ref
|
|
11724
|
+
});
|
|
11725
|
+
return createRetainedInteractiveRunHandle(environment, ref, capabilities, request);
|
|
11726
|
+
}
|
|
11727
|
+
function exactRecoveryRequest(admission) {
|
|
11728
|
+
assertStableText(admission.environmentId, "interactive environment id");
|
|
11729
|
+
assertStableText(admission.idempotencyKey, "environment idempotency key");
|
|
11730
|
+
assertStableText(admission.interactiveIdempotencyKey, "interactive idempotency key");
|
|
11731
|
+
const request = exactAgentInteractiveSessionStart(admission.request);
|
|
11732
|
+
const identity = mintRetainedIdentity(admission.idempotencyKey, admission.interactiveIdempotencyKey);
|
|
11733
|
+
if (request.run.provider !== admission.provider || request.run.environmentId !== admission.environmentId || request.run.sessionId !== identity.sessionId || request.run.executionId !== identity.executionId) throw new Error("interactive admission does not match its recovery coordinates");
|
|
11734
|
+
return request;
|
|
11735
|
+
}
|
|
11736
|
+
/** Rebuild controls for one exact provider-owned coding-agent process. @stable */
|
|
11737
|
+
async function reconnectRetainedInteractiveRun(options) {
|
|
11738
|
+
options.signal?.throwIfAborted();
|
|
11739
|
+
const ref = AgentInteractiveSessionRefSchema.parse(options.ref);
|
|
11740
|
+
if (ref.run.provider !== options.provider.name) throw new Error("interactive session reference belongs to another provider");
|
|
11741
|
+
const { environment, capabilities } = await reconstructEnvironment(options.provider, ref.run.environmentId, options.signal);
|
|
11742
|
+
if (!environment || !capabilities) return null;
|
|
11743
|
+
const handle = createRetainedInteractiveRunHandle(environment, ref, capabilities);
|
|
11744
|
+
await handle.status({ signal: options.signal });
|
|
11745
|
+
return handle;
|
|
11746
|
+
}
|
|
11747
|
+
function interactiveRequest(options, environment, profile, requestedProfileDigest, identity) {
|
|
11748
|
+
const start = {
|
|
11749
|
+
profile,
|
|
11750
|
+
requestedProfileDigest,
|
|
11751
|
+
...options.initialPrompt === void 0 ? {} : { initialPrompt: options.initialPrompt },
|
|
11752
|
+
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
11753
|
+
...options.cols === void 0 ? {} : { cols: options.cols },
|
|
11754
|
+
...options.rows === void 0 ? {} : { rows: options.rows }
|
|
11755
|
+
};
|
|
11756
|
+
return exactAgentInteractiveSessionStart({
|
|
11757
|
+
run: agentInteractiveSessionRunRef({
|
|
11758
|
+
provider: options.provider.name,
|
|
11759
|
+
environmentId: environment.id,
|
|
11760
|
+
...identity
|
|
11761
|
+
}, start),
|
|
11762
|
+
...start
|
|
11763
|
+
});
|
|
11764
|
+
}
|
|
11765
|
+
function interactiveIntent(options, profile, identity) {
|
|
11766
|
+
const requestedProfileDigest = canonicalAgentProfileDigest(profile);
|
|
11767
|
+
const requestDigest = canonicalCandidateDigest({
|
|
11768
|
+
kind: "retained-interactive-intent.v1",
|
|
11769
|
+
provider: options.provider.name,
|
|
11770
|
+
idempotencyKey: options.environment.idempotencyKey,
|
|
11771
|
+
interactiveIdempotencyKey: options.interactiveIdempotencyKey,
|
|
11772
|
+
sessionId: identity.sessionId,
|
|
11773
|
+
executionId: identity.executionId,
|
|
11774
|
+
requestedProfileDigest,
|
|
11775
|
+
create: retainedCreateMaterial(options.environment),
|
|
11776
|
+
start: sanitizedStartMaterial(options)
|
|
11777
|
+
});
|
|
11778
|
+
return {
|
|
11779
|
+
phase: "interactive_intent",
|
|
11780
|
+
provider: options.provider.name,
|
|
11781
|
+
idempotencyKey: options.environment.idempotencyKey,
|
|
11782
|
+
interactiveIdempotencyKey: options.interactiveIdempotencyKey,
|
|
11783
|
+
sessionId: identity.sessionId,
|
|
11784
|
+
executionId: identity.executionId,
|
|
11785
|
+
runId: `interactive-intent-run:${requestDigest.slice(7)}`,
|
|
11786
|
+
requestedProfileDigest,
|
|
11787
|
+
requestDigest
|
|
11788
|
+
};
|
|
11789
|
+
}
|
|
11790
|
+
function sanitizedStartMaterial(options) {
|
|
11791
|
+
return {
|
|
11792
|
+
...options.initialPrompt === void 0 ? {} : { initialPrompt: options.initialPrompt },
|
|
11793
|
+
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
11794
|
+
...options.cols === void 0 ? {} : { cols: options.cols },
|
|
11795
|
+
...options.rows === void 0 ? {} : { rows: options.rows }
|
|
11796
|
+
};
|
|
11797
|
+
}
|
|
11798
|
+
function assertExactInteractiveIntent(received, expected) {
|
|
11799
|
+
if (canonicalCandidateDigest(parseInteractiveIntent(received)) !== canonicalCandidateDigest(expected)) throw new Error("interactive intent conflicts with replay material");
|
|
11800
|
+
}
|
|
11801
|
+
function parseInteractiveIntent(value) {
|
|
11802
|
+
const stable = detachedSnapshot(value, "interactive intent");
|
|
11803
|
+
if (stable === null || typeof stable !== "object" || Array.isArray(stable)) throw new Error("interactive intent is malformed");
|
|
11804
|
+
const record = stable;
|
|
11805
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
11806
|
+
"phase",
|
|
11807
|
+
"provider",
|
|
11808
|
+
"idempotencyKey",
|
|
11809
|
+
"interactiveIdempotencyKey",
|
|
11810
|
+
"sessionId",
|
|
11811
|
+
"executionId",
|
|
11812
|
+
"runId",
|
|
11813
|
+
"requestedProfileDigest",
|
|
11814
|
+
"requestDigest"
|
|
11815
|
+
]);
|
|
11816
|
+
if (Object.keys(record).some((key) => !allowed.has(key))) throw new Error("interactive intent contains unsupported material");
|
|
11817
|
+
if (record.phase !== "interactive_intent") throw new Error("interactive intent has an invalid phase");
|
|
11818
|
+
for (const [key, value] of Object.entries(record)) {
|
|
11819
|
+
if (key === "phase") continue;
|
|
11820
|
+
if (typeof value !== "string" || value.length === 0) throw new Error(`interactive intent field "${key}" is invalid`);
|
|
11821
|
+
}
|
|
11822
|
+
assertDigest$1(record.requestedProfileDigest, "interactive intent profile digest");
|
|
11823
|
+
assertDigest$1(record.requestDigest, "interactive intent request digest");
|
|
11824
|
+
return stable;
|
|
11825
|
+
}
|
|
11826
|
+
function assertDigest$1(value, label) {
|
|
11827
|
+
if (typeof value !== "string" || !/^sha256:[a-f0-9]{64}$/u.test(value)) throw new Error(`${label} is invalid`);
|
|
11828
|
+
}
|
|
11829
|
+
async function reconstructEnvironment(provider, environmentId, signal) {
|
|
11830
|
+
if (!provider.get) throw new Error(`provider "${provider.name}" cannot reconstruct an environment by id`);
|
|
11831
|
+
const providerCapabilities = AgentEnvironmentCapabilitiesSchema.parse(await awaitAbortable$1(Promise.resolve().then(() => provider.capabilities()), signal));
|
|
11832
|
+
assertInteractiveCapabilities(provider.name, providerCapabilities);
|
|
11833
|
+
const environment = await awaitAbortable$1(Promise.resolve().then(() => provider.get(environmentId, { signal })), signal);
|
|
11834
|
+
if (!environment) return {
|
|
11835
|
+
environment: null,
|
|
11836
|
+
capabilities: null
|
|
11837
|
+
};
|
|
11838
|
+
assertExactEnvironment(provider.name, environment, environmentId);
|
|
11839
|
+
const capabilities = interactiveCapabilitiesForEnvironment(provider.name, providerCapabilities, environment);
|
|
11840
|
+
assertInteractiveMethods(provider.name, environment);
|
|
11841
|
+
return {
|
|
11842
|
+
environment,
|
|
11843
|
+
capabilities
|
|
11844
|
+
};
|
|
11845
|
+
}
|
|
11846
|
+
function exactStartedRef(request, value) {
|
|
11847
|
+
const stableRequest = detachedSnapshot(request, "interactive start binding request");
|
|
11848
|
+
let ref;
|
|
11849
|
+
try {
|
|
11850
|
+
ref = AgentInteractiveSessionRefSchema.parse(value);
|
|
11851
|
+
} catch (error) {
|
|
11852
|
+
throw new RetainedInteractiveBindingError(stableRequest, {}, { cause: error });
|
|
11853
|
+
}
|
|
11854
|
+
if (!agentInteractiveSessionRefMatchesStart(request, ref)) throw new RetainedInteractiveBindingError(stableRequest, detachedSnapshot({ ref: detachedSnapshot(ref, "interactive provider start reference") }, "interactive provider start result"), { cause: /* @__PURE__ */ new Error("provider started another interactive run than requested") });
|
|
11855
|
+
return freezeInteractiveRef(ref);
|
|
11856
|
+
}
|
|
11857
|
+
function assertExactEnvironment(providerName, environment, environmentId) {
|
|
11858
|
+
if (environment.provider !== providerName || environmentId && environment.id !== environmentId) throw new Error("provider returned another interactive environment");
|
|
11859
|
+
assertStableText(environment.id, "interactive environment id");
|
|
11860
|
+
}
|
|
11861
|
+
function interactiveCapabilitiesForEnvironment(providerName, providerCapabilities, environment) {
|
|
11862
|
+
const capabilities = environment.capabilities === void 0 ? providerCapabilities : AgentEnvironmentCapabilitiesSchema.parse(environment.capabilities);
|
|
11863
|
+
assertInteractiveCapabilities(providerName, capabilities);
|
|
11864
|
+
return capabilities;
|
|
11865
|
+
}
|
|
11866
|
+
function assertInteractiveCapabilities(providerName, capabilities) {
|
|
11867
|
+
const interactive = capabilities.interactiveAgent;
|
|
11868
|
+
if (!interactive?.start || !interactive.control || !interactive.status || !interactive.attach || !interactive.reattach || !interactive.sendPrompt || !interactive.input || !interactive.resize || !interactive.stop) throw new Error(`provider "${providerName}" cannot control an exact interactive agent`);
|
|
11869
|
+
}
|
|
11870
|
+
function assertInteractiveMethods(providerName, environment) {
|
|
11871
|
+
if (!environment.startInteractive || !environment.interactive) throw new Error(`provider "${providerName}" exposes incomplete interactive agent controls`);
|
|
11872
|
+
}
|
|
11873
|
+
async function destroyUnusedEnvironment(environment, cause) {
|
|
11874
|
+
try {
|
|
11875
|
+
await destroyInteractiveEnvironment(environment);
|
|
11876
|
+
} catch (cleanupError) {
|
|
11877
|
+
throw new AggregateError([cause, cleanupError], "interactive environment was invalid and could not be destroyed");
|
|
11878
|
+
}
|
|
11879
|
+
}
|
|
11880
|
+
//#endregion
|
|
11881
|
+
//#region src/runtime/supervise/worker-interactive.ts
|
|
11882
|
+
const WORKER_BINDING_SCHEMA_VERSION = 1;
|
|
11883
|
+
const SPAWN_JOURNAL_FILE = "spawn-journal.jsonl";
|
|
11884
|
+
/** Directory containing exact per-worker interactive binding records. @stable */
|
|
11885
|
+
function workerInteractiveBindingsDir(eventDir) {
|
|
11886
|
+
return join(eventDir, "interactive-workers");
|
|
11887
|
+
}
|
|
11888
|
+
/** Exact durable binding file for one worker id. @stable */
|
|
11889
|
+
function workerInteractiveBindingFile(eventDir, workerId) {
|
|
11890
|
+
const id = stableText$1(workerId, "worker id");
|
|
11891
|
+
const stem = createHash("sha256").update(id).digest("hex");
|
|
11892
|
+
return join(workerInteractiveBindingsDir(eventDir), `${stem}.json`);
|
|
11893
|
+
}
|
|
11894
|
+
/** Read and validate one exact durable worker binding. @stable */
|
|
11895
|
+
function readWorkerInteractiveBinding(eventDir, workerId) {
|
|
11896
|
+
const id = stableText$1(workerId, "worker id");
|
|
11897
|
+
const file = workerInteractiveBindingFile(eventDir, id);
|
|
11898
|
+
assertNoSymlinkDescendant(eventDir, file, "worker interactive");
|
|
11899
|
+
if (!existsSync(file)) return void 0;
|
|
11900
|
+
const binding = parseBinding(JSON.parse(readFileSync(file, "utf8")));
|
|
11901
|
+
if (binding.workerId !== id) throw new Error(`worker interactive binding collision: '${file}' holds '${binding.workerId}', not '${id}'`);
|
|
11902
|
+
return binding;
|
|
11903
|
+
}
|
|
11904
|
+
/**
|
|
11905
|
+
* Publish the exact interactive capability of one worker after its spawn record commits.
|
|
11906
|
+
* Replays of the same binding are no-ops; a different binding for one worker fails loud.
|
|
11907
|
+
* @internal
|
|
11908
|
+
*/
|
|
11909
|
+
function writeWorkerInteractiveBinding(eventDir, workerId, label, journalRoot, session, now = Date.now) {
|
|
11910
|
+
const id = stableText$1(workerId, "worker id");
|
|
11911
|
+
const workerLabel = stableText$1(label, "worker label");
|
|
11912
|
+
const root = stableText$1(journalRoot, "journal root");
|
|
11913
|
+
const binding = session.status === "available" ? (() => {
|
|
11914
|
+
const ref = AgentInteractiveSessionRefSchema.parse(session.handle.ref);
|
|
11915
|
+
return {
|
|
11916
|
+
schemaVersion: WORKER_BINDING_SCHEMA_VERSION,
|
|
11917
|
+
workerId: id,
|
|
11918
|
+
label: workerLabel,
|
|
11919
|
+
journalRoot: root,
|
|
11920
|
+
recordedAt: new Date(now()).toISOString(),
|
|
11921
|
+
status: "available",
|
|
11922
|
+
ref,
|
|
11923
|
+
refDigest: canonicalCandidateDigest(ref)
|
|
11924
|
+
};
|
|
11925
|
+
})() : {
|
|
11926
|
+
schemaVersion: WORKER_BINDING_SCHEMA_VERSION,
|
|
11927
|
+
workerId: id,
|
|
11928
|
+
label: workerLabel,
|
|
11929
|
+
journalRoot: root,
|
|
11930
|
+
recordedAt: new Date(now()).toISOString(),
|
|
11931
|
+
status: "unavailable",
|
|
11932
|
+
reason: session.reason
|
|
11933
|
+
};
|
|
11934
|
+
const file = workerInteractiveBindingFile(eventDir, id);
|
|
11935
|
+
assertNoSymlinkDescendant(eventDir, file, "worker interactive");
|
|
11936
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
11937
|
+
assertNoSymlinkDescendant(eventDir, file, "worker interactive");
|
|
11938
|
+
const existing = readWorkerInteractiveBinding(eventDir, id);
|
|
11939
|
+
if (existing !== void 0) {
|
|
11940
|
+
assertSameBinding(existing, binding);
|
|
11941
|
+
return existing;
|
|
11942
|
+
}
|
|
11943
|
+
if (publishExclusiveDurableFile(file, `${JSON.stringify(binding, null, 2)}\n`)) return binding;
|
|
11944
|
+
const winner = readWorkerInteractiveBinding(eventDir, id);
|
|
11945
|
+
if (winner === void 0) throw new Error(`worker interactive binding publication lost its winner`);
|
|
11946
|
+
assertSameBinding(winner, binding);
|
|
11947
|
+
return winner;
|
|
11948
|
+
}
|
|
11949
|
+
/**
|
|
11950
|
+
* Reconstruct the exact provider-owned interactive process bound to one supervised worker.
|
|
11951
|
+
* Unknown, headless, unsupported, settled, stale, and unregistered-provider cases fail closed.
|
|
11952
|
+
* @stable
|
|
11953
|
+
*/
|
|
11954
|
+
async function attachWorker(eventDir, workerId, options) {
|
|
11955
|
+
const id = stableText$1(workerId, "worker id");
|
|
11956
|
+
options.signal?.throwIfAborted();
|
|
11957
|
+
const binding = readWorkerInteractiveBinding(eventDir, id);
|
|
11958
|
+
if (binding === void 0) {
|
|
11959
|
+
const lifecycle = workerLifecycle(eventDir, id);
|
|
11960
|
+
return unavailable(lifecycle.terminal ? "not-live" : lifecycle.spawned ? "interactive-binding-not-found" : "unknown-node");
|
|
11961
|
+
}
|
|
11962
|
+
try {
|
|
11963
|
+
const node = (await loadSpawnForest(new FileSpawnJournal(join(eventDir, SPAWN_JOURNAL_FILE)), binding.journalRoot)).nodes.find((candidate) => candidate.id === id);
|
|
11964
|
+
if (node === void 0) return unavailable("unknown-node");
|
|
11965
|
+
if (node.status === "done" || node.status === "failed" || node.status === "cancelled") return unavailable("not-live");
|
|
11966
|
+
} catch {
|
|
11967
|
+
return unavailable("interactive-binding-stale");
|
|
11968
|
+
}
|
|
11969
|
+
if (binding.status === "unavailable") return unavailable(binding.reason);
|
|
11970
|
+
const provider = resolveProvider(options.providers, binding.ref.run.provider);
|
|
11971
|
+
if (provider === void 0) return unavailable("interactive-provider-not-registered");
|
|
11972
|
+
let handle;
|
|
11973
|
+
try {
|
|
11974
|
+
handle = await reconnectRetainedInteractiveRun({
|
|
11975
|
+
provider,
|
|
11976
|
+
ref: binding.ref,
|
|
11977
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
11978
|
+
});
|
|
11979
|
+
} catch (error) {
|
|
11980
|
+
options.signal?.throwIfAborted();
|
|
11981
|
+
if (isUnsupportedProvider(error)) return unavailable("provider-has-no-interactive-contract");
|
|
11982
|
+
return unavailable("interactive-binding-stale");
|
|
11983
|
+
}
|
|
11984
|
+
if (handle === null) return unavailable("interactive-binding-stale");
|
|
11985
|
+
let status;
|
|
11986
|
+
try {
|
|
11987
|
+
status = await handle.status(options.signal === void 0 ? void 0 : { signal: options.signal });
|
|
11988
|
+
} catch {
|
|
11989
|
+
options.signal?.throwIfAborted();
|
|
11990
|
+
return unavailable("interactive-binding-stale");
|
|
11991
|
+
}
|
|
11992
|
+
if (status.state !== "running") return unavailable("interactive-binding-stale");
|
|
11993
|
+
return {
|
|
11994
|
+
status: "available",
|
|
11995
|
+
handle
|
|
11996
|
+
};
|
|
11997
|
+
}
|
|
11998
|
+
function parseBinding(value) {
|
|
11999
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("worker interactive binding is malformed");
|
|
12000
|
+
const record = value;
|
|
12001
|
+
if (record.schemaVersion !== WORKER_BINDING_SCHEMA_VERSION || typeof record.workerId !== "string" || record.workerId.length === 0 || typeof record.label !== "string" || record.label.length === 0 || typeof record.journalRoot !== "string" || record.journalRoot.length === 0 || typeof record.recordedAt !== "string") throw new Error("worker interactive binding is malformed");
|
|
12002
|
+
if (record.status === "available") {
|
|
12003
|
+
const ref = AgentInteractiveSessionRefSchema.parse(record.ref);
|
|
12004
|
+
const refDigest = canonicalCandidateDigest(ref);
|
|
12005
|
+
if (record.refDigest !== refDigest) throw new Error("worker interactive binding ref digest does not match its exact ref");
|
|
12006
|
+
return {
|
|
12007
|
+
schemaVersion: WORKER_BINDING_SCHEMA_VERSION,
|
|
12008
|
+
workerId: record.workerId,
|
|
12009
|
+
label: record.label,
|
|
12010
|
+
journalRoot: record.journalRoot,
|
|
12011
|
+
recordedAt: record.recordedAt,
|
|
12012
|
+
status: "available",
|
|
12013
|
+
ref,
|
|
12014
|
+
refDigest
|
|
12015
|
+
};
|
|
12016
|
+
}
|
|
12017
|
+
if (record.status !== "unavailable" || !isUnavailableReason(record.reason)) throw new Error("worker interactive binding is malformed");
|
|
12018
|
+
return {
|
|
12019
|
+
schemaVersion: WORKER_BINDING_SCHEMA_VERSION,
|
|
12020
|
+
workerId: record.workerId,
|
|
12021
|
+
label: record.label,
|
|
12022
|
+
journalRoot: record.journalRoot,
|
|
12023
|
+
recordedAt: record.recordedAt,
|
|
12024
|
+
status: "unavailable",
|
|
12025
|
+
reason: record.reason
|
|
12026
|
+
};
|
|
12027
|
+
}
|
|
12028
|
+
function assertSameBinding(current, candidate) {
|
|
12029
|
+
const currentMaterial = bindingMaterial(current);
|
|
12030
|
+
const candidateMaterial = bindingMaterial(candidate);
|
|
12031
|
+
if (canonicalCandidateDigest(currentMaterial) !== canonicalCandidateDigest(candidateMaterial)) throw new Error(`worker '${candidate.workerId}' already has a different interactive binding`);
|
|
12032
|
+
}
|
|
12033
|
+
function bindingMaterial(binding) {
|
|
12034
|
+
return binding.status === "available" ? {
|
|
12035
|
+
schemaVersion: binding.schemaVersion,
|
|
12036
|
+
workerId: binding.workerId,
|
|
12037
|
+
label: binding.label,
|
|
12038
|
+
journalRoot: binding.journalRoot,
|
|
12039
|
+
status: binding.status,
|
|
12040
|
+
ref: binding.ref,
|
|
12041
|
+
refDigest: binding.refDigest
|
|
12042
|
+
} : {
|
|
12043
|
+
schemaVersion: binding.schemaVersion,
|
|
12044
|
+
workerId: binding.workerId,
|
|
12045
|
+
label: binding.label,
|
|
12046
|
+
journalRoot: binding.journalRoot,
|
|
12047
|
+
status: binding.status,
|
|
12048
|
+
reason: binding.reason
|
|
12049
|
+
};
|
|
12050
|
+
}
|
|
12051
|
+
function workerLifecycle(eventDir, workerId) {
|
|
12052
|
+
let raw;
|
|
12053
|
+
try {
|
|
12054
|
+
raw = readFileSync(join(eventDir, SPAWN_JOURNAL_FILE), "utf8");
|
|
12055
|
+
} catch {
|
|
12056
|
+
return {
|
|
12057
|
+
spawned: false,
|
|
12058
|
+
terminal: false
|
|
12059
|
+
};
|
|
12060
|
+
}
|
|
12061
|
+
let spawned = false;
|
|
12062
|
+
let terminal = false;
|
|
12063
|
+
for (const line of raw.split("\n")) {
|
|
12064
|
+
const text = line.trim();
|
|
12065
|
+
if (!text) continue;
|
|
12066
|
+
try {
|
|
12067
|
+
const record = JSON.parse(text);
|
|
12068
|
+
if (record.kind !== "event" || record.event?.id !== workerId) continue;
|
|
12069
|
+
if (record.event.kind === "spawned") spawned = true;
|
|
12070
|
+
if (record.event.kind === "settled" || record.event.kind === "cancelled") terminal = true;
|
|
12071
|
+
} catch {}
|
|
12072
|
+
}
|
|
12073
|
+
return {
|
|
12074
|
+
spawned,
|
|
12075
|
+
terminal
|
|
12076
|
+
};
|
|
12077
|
+
}
|
|
12078
|
+
function resolveProvider(source, name) {
|
|
12079
|
+
if ("register" in source) return source.get(name);
|
|
12080
|
+
return source.name === name ? source : void 0;
|
|
12081
|
+
}
|
|
12082
|
+
function unavailable(reason) {
|
|
12083
|
+
return {
|
|
12084
|
+
status: "unavailable",
|
|
12085
|
+
reason
|
|
12086
|
+
};
|
|
12087
|
+
}
|
|
12088
|
+
function stableText$1(value, label) {
|
|
12089
|
+
const text = value.trim();
|
|
12090
|
+
if (!text) throw new Error(`${label} is empty`);
|
|
12091
|
+
return text;
|
|
12092
|
+
}
|
|
12093
|
+
function isUnsupportedProvider(error) {
|
|
12094
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12095
|
+
return message.includes("cannot reconstruct an environment") || message.includes("cannot control an exact interactive agent") || message.includes("incomplete interactive agent controls");
|
|
12096
|
+
}
|
|
12097
|
+
function isUnavailableReason(value) {
|
|
12098
|
+
return value === "unknown-node" || value === "not-live" || value === "executor-exposes-no-interactive-session" || value === "provider-has-no-interactive-contract" || value === "interactive-session-not-started" || value === "interactive-binding-not-found" || value === "interactive-binding-stale" || value === "interactive-provider-not-registered";
|
|
12099
|
+
}
|
|
12100
|
+
//#endregion
|
|
12101
|
+
//#region src/runtime/supervise/interactive-admission.ts
|
|
12102
|
+
/**
|
|
12103
|
+
* Durable, credential-free admissions for Runtime-owned interactive workers.
|
|
12104
|
+
*
|
|
12105
|
+
* `startRetainedInteractiveRun` deliberately asks its caller to persist each admission before it
|
|
12106
|
+
* advances. A supervised worker supplies this hook through `Scope`; the hook stores only recovery
|
|
12107
|
+
* coordinates and digests, never the profile, prompt, environment variables, or other private
|
|
12108
|
+
* create material.
|
|
12109
|
+
*/
|
|
12110
|
+
/** The Scope seam key used by `workerFromInteractiveProvider`. */
|
|
12111
|
+
const interactiveAdmissionSeamKey = "runtime.interactiveAdmission";
|
|
12112
|
+
/** Return the exact credential-free admission file for one worker and phase. */
|
|
12113
|
+
function workerInteractiveAdmissionFile(eventDir, workerId, phase) {
|
|
12114
|
+
const dir = workerInteractiveBindingsDir(eventDir);
|
|
12115
|
+
const id = stableText(workerId, "worker id");
|
|
12116
|
+
assertNoSymlinkDescendant(eventDir, dir, "interactive admission");
|
|
12117
|
+
return join(dir, `${canonicalCandidateDigest({ workerId: id }).slice(7).slice(0, 32)}.${phase}.admission.json`);
|
|
12118
|
+
}
|
|
12119
|
+
/** Read all durable admissions for one worker, oldest phase first. */
|
|
12120
|
+
function readWorkerInteractiveAdmissions(eventDir, workerId) {
|
|
12121
|
+
const phases = [
|
|
12122
|
+
"interactive_intent",
|
|
12123
|
+
"interactive_environment",
|
|
12124
|
+
"interactive_started"
|
|
12125
|
+
];
|
|
12126
|
+
const admissions = [];
|
|
12127
|
+
let missingPhase = false;
|
|
12128
|
+
for (const phase of phases) {
|
|
12129
|
+
const file = workerInteractiveAdmissionFile(eventDir, workerId, phase);
|
|
12130
|
+
if (!existsSync(file)) {
|
|
12131
|
+
missingPhase = true;
|
|
12132
|
+
continue;
|
|
12133
|
+
}
|
|
12134
|
+
if (missingPhase) throw new Error(`interactive admission phase '${phase}' exists after a missing earlier phase`);
|
|
12135
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
12136
|
+
admissions.push(parseAdmission(parsed, workerId, phase));
|
|
12137
|
+
}
|
|
12138
|
+
return admissions;
|
|
12139
|
+
}
|
|
12140
|
+
/**
|
|
12141
|
+
* Persist one retained-interactive admission without retaining sensitive start material.
|
|
12142
|
+
*
|
|
12143
|
+
* The phase file is an idempotency key. A retry with the same exact admission is a no-op; a
|
|
12144
|
+
* different admission for the same phase fails closed rather than overwriting recovery evidence.
|
|
12145
|
+
*/
|
|
12146
|
+
function writeWorkerInteractiveAdmission(eventDir, workerId, admission, now = Date.now) {
|
|
12147
|
+
const id = stableText(workerId, "worker id");
|
|
12148
|
+
const record = credentialFreeAdmission(id, admission, now);
|
|
12149
|
+
const file = workerInteractiveAdmissionFile(eventDir, id, record.phase);
|
|
12150
|
+
assertNoSymlinkDescendant(eventDir, file, "interactive admission");
|
|
12151
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
12152
|
+
assertNoSymlinkDescendant(eventDir, file, "interactive admission");
|
|
12153
|
+
const existing = readWorkerInteractiveAdmission(eventDir, id, record.phase);
|
|
12154
|
+
if (existing !== void 0) {
|
|
12155
|
+
assertSameAdmission(existing, record);
|
|
12156
|
+
return existing;
|
|
12157
|
+
}
|
|
12158
|
+
if (publishExclusiveDurableFile(file, `${JSON.stringify(record, null, 2)}\n`)) return record;
|
|
12159
|
+
const winner = readWorkerInteractiveAdmission(eventDir, id, record.phase);
|
|
12160
|
+
if (winner === void 0) throw new Error(`interactive admission publication for '${record.phase}' lost its winner`);
|
|
12161
|
+
assertSameAdmission(winner, record);
|
|
12162
|
+
return winner;
|
|
12163
|
+
}
|
|
12164
|
+
function credentialFreeAdmission(workerId, admission, now) {
|
|
12165
|
+
const recordedAt = new Date(now()).toISOString();
|
|
12166
|
+
switch (admission.phase) {
|
|
12167
|
+
case "interactive_intent": return {
|
|
12168
|
+
schemaVersion: 1,
|
|
12169
|
+
workerId,
|
|
12170
|
+
recordedAt,
|
|
12171
|
+
phase: admission.phase,
|
|
12172
|
+
provider: admission.provider,
|
|
12173
|
+
idempotencyKey: admission.idempotencyKey,
|
|
12174
|
+
interactiveIdempotencyKey: admission.interactiveIdempotencyKey,
|
|
12175
|
+
sessionId: admission.sessionId,
|
|
12176
|
+
executionId: admission.executionId,
|
|
12177
|
+
runId: admission.runId,
|
|
12178
|
+
requestedProfileDigest: admission.requestedProfileDigest,
|
|
12179
|
+
requestDigest: admission.requestDigest
|
|
12180
|
+
};
|
|
12181
|
+
case "interactive_environment": return {
|
|
12182
|
+
schemaVersion: 1,
|
|
12183
|
+
workerId,
|
|
12184
|
+
recordedAt,
|
|
12185
|
+
phase: admission.phase,
|
|
12186
|
+
provider: admission.provider,
|
|
12187
|
+
environmentId: admission.environmentId,
|
|
12188
|
+
idempotencyKey: admission.idempotencyKey,
|
|
12189
|
+
interactiveIdempotencyKey: admission.interactiveIdempotencyKey,
|
|
12190
|
+
requestDigest: canonicalCandidateDigest(admission.request)
|
|
12191
|
+
};
|
|
12192
|
+
case "interactive_started": return {
|
|
12193
|
+
schemaVersion: 1,
|
|
12194
|
+
workerId,
|
|
12195
|
+
recordedAt,
|
|
12196
|
+
phase: admission.phase,
|
|
12197
|
+
idempotencyKey: admission.idempotencyKey,
|
|
12198
|
+
interactiveIdempotencyKey: admission.interactiveIdempotencyKey,
|
|
12199
|
+
ref: admission.ref,
|
|
12200
|
+
refDigest: canonicalCandidateDigest(admission.ref)
|
|
12201
|
+
};
|
|
12202
|
+
}
|
|
12203
|
+
}
|
|
12204
|
+
function readWorkerInteractiveAdmission(eventDir, workerId, phase) {
|
|
12205
|
+
const file = workerInteractiveAdmissionFile(eventDir, workerId, phase);
|
|
12206
|
+
if (!existsSync(file)) return void 0;
|
|
12207
|
+
return parseAdmission(JSON.parse(readFileSync(file, "utf8")), workerId, phase);
|
|
12208
|
+
}
|
|
12209
|
+
function parseAdmission(value, expectedWorkerId, expectedPhase) {
|
|
12210
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("interactive admission is malformed");
|
|
12211
|
+
const record = value;
|
|
12212
|
+
if (record.schemaVersion !== 1 || typeof record.workerId !== "string" || record.workerId.length === 0 || typeof record.recordedAt !== "string" || !Number.isFinite(Date.parse(record.recordedAt))) throw new Error("interactive admission is malformed");
|
|
12213
|
+
if (expectedWorkerId !== void 0 && record.workerId !== expectedWorkerId) throw new Error("interactive admission worker id does not match its file");
|
|
12214
|
+
if (record.phase === "interactive_intent") {
|
|
12215
|
+
assertAllowedFields(record, [
|
|
12216
|
+
"schemaVersion",
|
|
12217
|
+
"workerId",
|
|
12218
|
+
"recordedAt",
|
|
12219
|
+
"phase",
|
|
12220
|
+
"provider",
|
|
12221
|
+
"idempotencyKey",
|
|
12222
|
+
"interactiveIdempotencyKey",
|
|
12223
|
+
"sessionId",
|
|
12224
|
+
"executionId",
|
|
12225
|
+
"runId",
|
|
12226
|
+
"requestedProfileDigest",
|
|
12227
|
+
"requestDigest"
|
|
12228
|
+
]);
|
|
12229
|
+
assertStrings(record, [
|
|
12230
|
+
"provider",
|
|
12231
|
+
"idempotencyKey",
|
|
12232
|
+
"interactiveIdempotencyKey",
|
|
12233
|
+
"sessionId",
|
|
12234
|
+
"executionId",
|
|
12235
|
+
"runId",
|
|
12236
|
+
"requestedProfileDigest",
|
|
12237
|
+
"requestDigest"
|
|
12238
|
+
]);
|
|
12239
|
+
assertDigest(record.requestedProfileDigest, "interactive admission profile digest");
|
|
12240
|
+
assertDigest(record.requestDigest, "interactive admission request digest");
|
|
12241
|
+
assertPhase(record.phase, expectedPhase);
|
|
12242
|
+
return {
|
|
12243
|
+
schemaVersion: 1,
|
|
12244
|
+
workerId: record.workerId,
|
|
12245
|
+
recordedAt: record.recordedAt,
|
|
12246
|
+
phase: record.phase,
|
|
12247
|
+
provider: record.provider,
|
|
12248
|
+
idempotencyKey: record.idempotencyKey,
|
|
12249
|
+
interactiveIdempotencyKey: record.interactiveIdempotencyKey,
|
|
12250
|
+
sessionId: record.sessionId,
|
|
12251
|
+
executionId: record.executionId,
|
|
12252
|
+
runId: record.runId,
|
|
12253
|
+
requestedProfileDigest: record.requestedProfileDigest,
|
|
12254
|
+
requestDigest: record.requestDigest
|
|
12255
|
+
};
|
|
12256
|
+
}
|
|
12257
|
+
if (record.phase === "interactive_environment") {
|
|
12258
|
+
assertAllowedFields(record, [
|
|
12259
|
+
"schemaVersion",
|
|
12260
|
+
"workerId",
|
|
12261
|
+
"recordedAt",
|
|
12262
|
+
"phase",
|
|
12263
|
+
"provider",
|
|
12264
|
+
"environmentId",
|
|
12265
|
+
"idempotencyKey",
|
|
12266
|
+
"interactiveIdempotencyKey",
|
|
12267
|
+
"requestDigest"
|
|
12268
|
+
]);
|
|
12269
|
+
assertStrings(record, [
|
|
12270
|
+
"provider",
|
|
12271
|
+
"environmentId",
|
|
12272
|
+
"idempotencyKey",
|
|
12273
|
+
"interactiveIdempotencyKey",
|
|
12274
|
+
"requestDigest"
|
|
12275
|
+
]);
|
|
12276
|
+
assertDigest(record.requestDigest, "interactive admission environment request digest");
|
|
12277
|
+
assertPhase(record.phase, expectedPhase);
|
|
12278
|
+
return {
|
|
12279
|
+
schemaVersion: 1,
|
|
12280
|
+
workerId: record.workerId,
|
|
12281
|
+
recordedAt: record.recordedAt,
|
|
12282
|
+
phase: record.phase,
|
|
12283
|
+
provider: record.provider,
|
|
12284
|
+
environmentId: record.environmentId,
|
|
12285
|
+
idempotencyKey: record.idempotencyKey,
|
|
12286
|
+
interactiveIdempotencyKey: record.interactiveIdempotencyKey,
|
|
12287
|
+
requestDigest: record.requestDigest
|
|
12288
|
+
};
|
|
12289
|
+
}
|
|
12290
|
+
if (record.phase === "interactive_started") {
|
|
12291
|
+
assertAllowedFields(record, [
|
|
12292
|
+
"schemaVersion",
|
|
12293
|
+
"workerId",
|
|
12294
|
+
"recordedAt",
|
|
12295
|
+
"phase",
|
|
12296
|
+
"idempotencyKey",
|
|
12297
|
+
"interactiveIdempotencyKey",
|
|
12298
|
+
"ref",
|
|
12299
|
+
"refDigest"
|
|
12300
|
+
]);
|
|
12301
|
+
assertStrings(record, [
|
|
12302
|
+
"idempotencyKey",
|
|
12303
|
+
"interactiveIdempotencyKey",
|
|
12304
|
+
"refDigest"
|
|
12305
|
+
]);
|
|
12306
|
+
const ref = AgentInteractiveSessionRefSchema.parse(record.ref);
|
|
12307
|
+
const refDigest = canonicalCandidateDigest(ref);
|
|
12308
|
+
if (record.refDigest !== refDigest) throw new Error("interactive admission ref digest does not match its exact ref");
|
|
12309
|
+
assertPhase(record.phase, expectedPhase);
|
|
12310
|
+
return {
|
|
12311
|
+
schemaVersion: 1,
|
|
12312
|
+
workerId: record.workerId,
|
|
12313
|
+
recordedAt: record.recordedAt,
|
|
12314
|
+
phase: record.phase,
|
|
12315
|
+
idempotencyKey: record.idempotencyKey,
|
|
12316
|
+
interactiveIdempotencyKey: record.interactiveIdempotencyKey,
|
|
12317
|
+
ref,
|
|
12318
|
+
refDigest
|
|
12319
|
+
};
|
|
12320
|
+
}
|
|
12321
|
+
throw new Error("interactive admission has an invalid phase");
|
|
12322
|
+
}
|
|
12323
|
+
function assertDigest(value, label) {
|
|
12324
|
+
if (typeof value !== "string" || !/^sha256:[a-f0-9]{64}$/u.test(value)) throw new Error(`${label} is malformed`);
|
|
12325
|
+
}
|
|
12326
|
+
function assertPhase(phase, expected) {
|
|
12327
|
+
if (expected !== void 0 && phase !== expected) throw new Error("interactive admission phase does not match its file");
|
|
12328
|
+
}
|
|
12329
|
+
function assertStrings(record, keys) {
|
|
12330
|
+
for (const key of keys) if (typeof record[key] !== "string" || record[key].length === 0) throw new Error(`interactive admission field '${key}' is invalid`);
|
|
12331
|
+
}
|
|
12332
|
+
function assertAllowedFields(record, allowed) {
|
|
12333
|
+
const fields = new Set(allowed);
|
|
12334
|
+
const unsupported = Object.keys(record).filter((key) => !fields.has(key));
|
|
12335
|
+
if (unsupported.length > 0) throw new Error(`interactive admission contains unsupported fields: ${unsupported.join(", ")}`);
|
|
12336
|
+
}
|
|
12337
|
+
function assertSameAdmission(current, candidate) {
|
|
12338
|
+
const comparable = (value) => {
|
|
12339
|
+
const { recordedAt: _recordedAt, ...stable } = value;
|
|
12340
|
+
return stable;
|
|
12341
|
+
};
|
|
12342
|
+
if (canonicalCandidateDigest(comparable(current)) !== canonicalCandidateDigest(comparable(candidate))) throw new Error(`worker '${candidate.workerId}' already has a different ${candidate.phase} admission`);
|
|
12343
|
+
}
|
|
12344
|
+
function stableText(value, label) {
|
|
12345
|
+
const text = value.trim();
|
|
12346
|
+
if (!text) throw new Error(`${label} is empty`);
|
|
12347
|
+
return text;
|
|
12348
|
+
}
|
|
12349
|
+
//#endregion
|
|
10824
12350
|
//#region src/runtime/supervise/wait.ts
|
|
10825
12351
|
/**
|
|
10826
12352
|
*
|
|
@@ -11070,6 +12596,7 @@ function makeNestedScopeSeam(args, liveWorkerCapacity, childNodeId, childBudget,
|
|
|
11070
12596
|
...args.hooks ? { hooks: args.hooks } : {},
|
|
11071
12597
|
...args.workerTrace ? { workerTrace: args.workerTrace } : {},
|
|
11072
12598
|
...args.workerTraceUnpropagated ? { workerTraceUnpropagated: args.workerTraceUnpropagated } : {},
|
|
12599
|
+
...args.interactiveBindingDir ? { interactiveBindingDir: args.interactiveBindingDir } : {},
|
|
11073
12600
|
...deferredOwner.ownerMaterialization === void 0 ? {} : { ownerMaterialization: deferredOwner.ownerMaterialization }
|
|
11074
12601
|
});
|
|
11075
12602
|
}
|
|
@@ -11078,6 +12605,7 @@ function makeNestedScopeSeam(args, liveWorkerCapacity, childNodeId, childBudget,
|
|
|
11078
12605
|
/** Create the reactive `Scope` a driver's `Agent.act` runs inside: spawn children on an atomically reserved conserved budget, settle via the `next()` cursor, journal for replay. */
|
|
11079
12606
|
function createScope(args) {
|
|
11080
12607
|
const children = /* @__PURE__ */ new Map();
|
|
12608
|
+
const interactiveBindingDir = args.interactiveBindingDir;
|
|
11081
12609
|
const liveWorkerCapacity = args.liveWorkerCapacity ?? {
|
|
11082
12610
|
max: normalizeLiveWorkerLimit(args.maxLiveWorkers),
|
|
11083
12611
|
live: 0
|
|
@@ -11086,6 +12614,7 @@ function createScope(args) {
|
|
|
11086
12614
|
let cursorSeq = args.resumeFrom ? args.resumeFrom.maxCursorSeq + 1 : 0;
|
|
11087
12615
|
let waitOrdinal = args.resumeFrom ? args.resumeFrom.maxWaitOrdinal + 1 : 0;
|
|
11088
12616
|
let meterSeq = 0;
|
|
12617
|
+
let progressSeq = 0;
|
|
11089
12618
|
const now = args.now ?? Date.now;
|
|
11090
12619
|
const unclaimedWaits = new Map((args.resumeFrom?.waits ?? []).map((w) => [w.label, w]));
|
|
11091
12620
|
const keyed = /* @__PURE__ */ new Map();
|
|
@@ -11257,7 +12786,8 @@ function createScope(args) {
|
|
|
11257
12786
|
seams: {
|
|
11258
12787
|
...args.seams,
|
|
11259
12788
|
[nestedScopeSeamKey]: makeNestedScopeSeam(args, liveWorkerCapacity, id, opts.budget, childDeadlineAtMs, deferredOwner),
|
|
11260
|
-
...workerTrace ? { [workerTraceSeamKey]: workerTrace } : {}
|
|
12789
|
+
...workerTrace ? { [workerTraceSeamKey]: workerTrace } : {},
|
|
12790
|
+
...interactiveBindingDir ? { [interactiveAdmissionSeamKey]: (admission) => Promise.resolve(writeWorkerInteractiveAdmission(interactiveBindingDir, id, admission, now)).then(() => void 0) } : {}
|
|
11261
12791
|
}
|
|
11262
12792
|
};
|
|
11263
12793
|
const executor = resolved.value(spec, ctx);
|
|
@@ -11303,6 +12833,7 @@ function createScope(args) {
|
|
|
11303
12833
|
...executor.progress ? { readProgress: executor.progress.bind(executor) } : {},
|
|
11304
12834
|
...executor.traceSource ? { readTraceSource: executor.traceSource.bind(executor) } : {},
|
|
11305
12835
|
...executor.interactive ? { readInteractive: executor.interactive.bind(executor) } : {},
|
|
12836
|
+
...executor.interactiveReady ? { readInteractiveReady: executor.interactiveReady.bind(executor) } : {},
|
|
11306
12837
|
...executor.cancel ? { requestCancel: executor.cancel.bind(executor) } : {},
|
|
11307
12838
|
abortChild: (reason) => controller.abort(reason)
|
|
11308
12839
|
};
|
|
@@ -11465,12 +12996,29 @@ function createScope(args) {
|
|
|
11465
12996
|
startedAt
|
|
11466
12997
|
}
|
|
11467
12998
|
}, { signal: args.signal });
|
|
11468
|
-
|
|
12999
|
+
const childRun = runChild(live, executor, controller, task, opts, args.pool, reservation.ticket, args.blobs, now, args.journal, args.root, () => progressSeq++, materializationCommitted, {
|
|
11469
13000
|
complete: async () => pendingEvidence?.complete(),
|
|
11470
13001
|
fail: async () => pendingEvidence?.fail()
|
|
11471
|
-
}, childDeadlineAtMs)
|
|
11472
|
-
|
|
11473
|
-
return
|
|
13002
|
+
}, childDeadlineAtMs);
|
|
13003
|
+
const interactiveBindingCommitted = spawnCommitted.then(async () => {
|
|
13004
|
+
if (args.interactiveBindingDir === void 0) return;
|
|
13005
|
+
const immediate = readInteractiveSession(live);
|
|
13006
|
+
if (immediate.status === "available" || immediate.reason !== "interactive-session-not-started" || live.readInteractiveReady === void 0) {
|
|
13007
|
+
writeWorkerInteractiveBinding(args.interactiveBindingDir, id, opts.label, args.root, immediate, now);
|
|
13008
|
+
return;
|
|
13009
|
+
}
|
|
13010
|
+
const ready = await readInteractiveReadyUntilWorkerEnds(live.readInteractiveReady, childRun, controller.signal);
|
|
13011
|
+
if (ready !== void 0 && (ready.status === "available" || ready.reason !== "interactive-session-not-started")) writeWorkerInteractiveBinding(args.interactiveBindingDir, id, opts.label, args.root, ready, now);
|
|
13012
|
+
});
|
|
13013
|
+
live.settled = childRun.then(async (s) => {
|
|
13014
|
+
let resolution = s;
|
|
13015
|
+
try {
|
|
13016
|
+
await interactiveBindingCommitted;
|
|
13017
|
+
} catch {
|
|
13018
|
+
resolution = downRecord("interactive worker binding persistence failed", true, s.trace, s.metered, s.providerModel);
|
|
13019
|
+
}
|
|
13020
|
+
live.resolved = resolution;
|
|
13021
|
+
return resolution;
|
|
11474
13022
|
}).finally(() => {
|
|
11475
13023
|
if (live.cleanupConfirmed) permit.release();
|
|
11476
13024
|
clearChildDeadline?.();
|
|
@@ -11732,16 +13280,9 @@ function createScope(args) {
|
|
|
11732
13280
|
const child = children.get(nodeId);
|
|
11733
13281
|
if (!child) return noInteractiveSession("unknown-node");
|
|
11734
13282
|
if (child.wait || child.executorDone || isTerminalNodeStatus(child.status)) return noInteractiveSession("not-live");
|
|
11735
|
-
|
|
11736
|
-
|
|
11737
|
-
|
|
11738
|
-
reported = child.readInteractive();
|
|
11739
|
-
} catch {
|
|
11740
|
-
return noInteractiveSession("executor-exposes-no-interactive-session");
|
|
11741
|
-
}
|
|
11742
|
-
if (reported?.status === "unavailable" && reported.reason) return reported;
|
|
11743
|
-
if (reported?.status === "available" && reported.handle) return reported;
|
|
11744
|
-
return noInteractiveSession("executor-exposes-no-interactive-session");
|
|
13283
|
+
const session = readInteractiveSession(child);
|
|
13284
|
+
if (args.interactiveBindingDir !== void 0 && session.status === "available") writeWorkerInteractiveBinding(args.interactiveBindingDir, child.id, child.label, args.root, session, now);
|
|
13285
|
+
return session;
|
|
11745
13286
|
}
|
|
11746
13287
|
async function meterInternal(spend, detail, providerModel, accountingOnly = false) {
|
|
11747
13288
|
if (args.signal.aborted) throw new ValidationError("scope.meter: cannot record new driver work after scope abort");
|
|
@@ -12213,7 +13754,7 @@ async function finalizeWait(child, settlement, seq, args, now, handle) {
|
|
|
12213
13754
|
* applied per child). The reservation is reconciled on EVERY path (success, abort, throw)
|
|
12214
13755
|
* so the conserved pool can never leak a reservation.
|
|
12215
13756
|
*/
|
|
12216
|
-
async function runChild(live, executor, childAbort, task, opts, pool, ticket, blobs, now, executionReady, executionEvidence, deadlineAtMs) {
|
|
13757
|
+
async function runChild(live, executor, childAbort, task, opts, pool, ticket, blobs, now, journal, journalRoot, nextProgressSeq, executionReady, executionEvidence, deadlineAtMs) {
|
|
12217
13758
|
let reconciled = false;
|
|
12218
13759
|
let started = false;
|
|
12219
13760
|
let terminalTelemetryCaptured = false;
|
|
@@ -12241,15 +13782,22 @@ async function runChild(live, executor, childAbort, task, opts, pool, ticket, bl
|
|
|
12241
13782
|
};
|
|
12242
13783
|
try {
|
|
12243
13784
|
await executionReady;
|
|
12244
|
-
if (childAbort.signal.aborted) throw abortError(childAbort.signal, "execution aborted");
|
|
13785
|
+
if (childAbort.signal.aborted) throw abortError$1(childAbort.signal, "execution aborted");
|
|
12245
13786
|
live.status = "running";
|
|
12246
13787
|
started = true;
|
|
12247
13788
|
const ran = executor.execute(task, childAbort.signal);
|
|
12248
13789
|
let artifact;
|
|
12249
13790
|
if (isAsyncIterable(ran)) {
|
|
12250
|
-
const spend = await foldStream(ran, (running) => {
|
|
13791
|
+
const spend = await foldStream(ran, async (running) => {
|
|
12251
13792
|
live.spent = running;
|
|
12252
13793
|
live.lastActivityAt = now();
|
|
13794
|
+
await journal.appendEvent(journalRoot, {
|
|
13795
|
+
kind: "progress",
|
|
13796
|
+
id: live.id,
|
|
13797
|
+
spend: running,
|
|
13798
|
+
seq: nextProgressSeq(),
|
|
13799
|
+
at: new Date(now()).toISOString()
|
|
13800
|
+
});
|
|
12253
13801
|
}, childAbort.signal);
|
|
12254
13802
|
live.spent = spend;
|
|
12255
13803
|
await executionEvidence.complete();
|
|
@@ -12471,7 +14019,7 @@ async function foldStream(stream, onProgress, signal) {
|
|
|
12471
14019
|
if (next.done) break;
|
|
12472
14020
|
const ev = next.value;
|
|
12473
14021
|
meterUsageEvent(totals, ev);
|
|
12474
|
-
onProgress?.({
|
|
14022
|
+
await onProgress?.({
|
|
12475
14023
|
iterations: totals.iterations,
|
|
12476
14024
|
tokens: cloneTokenUsage(totals.tokens),
|
|
12477
14025
|
...totals.tokensKnown ? {} : { tokensKnown: false },
|
|
@@ -12507,7 +14055,7 @@ function preserveUnknownTelemetry(streamed, terminal) {
|
|
|
12507
14055
|
async function awaitAbortable(work, signal) {
|
|
12508
14056
|
if (signal.aborted) {
|
|
12509
14057
|
work.catch(() => void 0);
|
|
12510
|
-
throw abortError(signal, "execution aborted");
|
|
14058
|
+
throw abortError$1(signal, "execution aborted");
|
|
12511
14059
|
}
|
|
12512
14060
|
return await new Promise((resolve, reject) => {
|
|
12513
14061
|
let settled = false;
|
|
@@ -12516,7 +14064,7 @@ async function awaitAbortable(work, signal) {
|
|
|
12516
14064
|
if (settled) return;
|
|
12517
14065
|
settled = true;
|
|
12518
14066
|
cleanup();
|
|
12519
|
-
reject(abortError(signal, "execution aborted"));
|
|
14067
|
+
reject(abortError$1(signal, "execution aborted"));
|
|
12520
14068
|
});
|
|
12521
14069
|
};
|
|
12522
14070
|
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
@@ -12551,6 +14099,42 @@ function noInteractiveSession(reason) {
|
|
|
12551
14099
|
reason
|
|
12552
14100
|
});
|
|
12553
14101
|
}
|
|
14102
|
+
/** Read one executor's declared interactive capability without letting a malformed port escape. */
|
|
14103
|
+
function readInteractiveSession(child) {
|
|
14104
|
+
if (!child.readInteractive) return noInteractiveSession("executor-exposes-no-interactive-session");
|
|
14105
|
+
let reported;
|
|
14106
|
+
try {
|
|
14107
|
+
reported = child.readInteractive();
|
|
14108
|
+
} catch {
|
|
14109
|
+
return noInteractiveSession("executor-exposes-no-interactive-session");
|
|
14110
|
+
}
|
|
14111
|
+
if (reported?.status === "unavailable" && reported.reason) return reported;
|
|
14112
|
+
if (reported?.status === "available" && reported.handle) return reported;
|
|
14113
|
+
return noInteractiveSession("executor-exposes-no-interactive-session");
|
|
14114
|
+
}
|
|
14115
|
+
/** Stop waiting for optional readiness when the worker settles or its lifetime is cancelled. */
|
|
14116
|
+
async function readInteractiveReadyUntilWorkerEnds(readReady, workerEnded, signal) {
|
|
14117
|
+
if (signal.aborted) return void 0;
|
|
14118
|
+
let resolveAborted;
|
|
14119
|
+
const aborted = new Promise((resolve) => {
|
|
14120
|
+
resolveAborted = resolve;
|
|
14121
|
+
});
|
|
14122
|
+
const onAbort = () => resolveAborted();
|
|
14123
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
14124
|
+
try {
|
|
14125
|
+
const outcome = await Promise.race([
|
|
14126
|
+
Promise.resolve().then(readReady).then((session) => ({
|
|
14127
|
+
kind: "ready",
|
|
14128
|
+
session
|
|
14129
|
+
})),
|
|
14130
|
+
workerEnded.then(() => ({ kind: "ended" }), () => ({ kind: "ended" })),
|
|
14131
|
+
aborted.then(() => ({ kind: "ended" }))
|
|
14132
|
+
]);
|
|
14133
|
+
return outcome.kind === "ready" ? outcome.session : void 0;
|
|
14134
|
+
} finally {
|
|
14135
|
+
signal.removeEventListener("abort", onAbort);
|
|
14136
|
+
}
|
|
14137
|
+
}
|
|
12554
14138
|
function isAsyncIterable(value) {
|
|
12555
14139
|
return typeof value === "object" && value !== null && typeof value[Symbol.asyncIterator] === "function";
|
|
12556
14140
|
}
|
|
@@ -13137,7 +14721,7 @@ function describeRejection(error) {
|
|
|
13137
14721
|
function createSupervisor() {
|
|
13138
14722
|
let attached;
|
|
13139
14723
|
async function run(root, task, opts) {
|
|
13140
|
-
const { budget, rootIdentity, rootMaterialization, runId, journal: journalStore, blobs: blobStore, executors: executorRegistry, probes, maxDepth, maxLiveWorkers, maxRestarts, withinMs, childSettleGraceMs, resume, now: suppliedNow, signal, hooks, workerTrace, workerTraceUnpropagated } = opts;
|
|
14724
|
+
const { budget, rootIdentity, rootMaterialization, runId, journal: journalStore, blobs: blobStore, executors: executorRegistry, probes, maxDepth, maxLiveWorkers, maxRestarts, withinMs, childSettleGraceMs, resume, now: suppliedNow, signal, hooks, workerTrace, workerTraceUnpropagated, interactiveBindingDir } = opts;
|
|
13141
14725
|
const input = detachedSnapshot({
|
|
13142
14726
|
task,
|
|
13143
14727
|
options: {
|
|
@@ -13150,7 +14734,8 @@ function createSupervisor() {
|
|
|
13150
14734
|
...maxRestarts === void 0 ? {} : { maxRestarts },
|
|
13151
14735
|
...withinMs === void 0 ? {} : { withinMs },
|
|
13152
14736
|
...childSettleGraceMs === void 0 ? {} : { childSettleGraceMs },
|
|
13153
|
-
...resume === void 0 ? {} : { resume }
|
|
14737
|
+
...resume === void 0 ? {} : { resume },
|
|
14738
|
+
...interactiveBindingDir === void 0 ? {} : { interactiveBindingDir }
|
|
13154
14739
|
}
|
|
13155
14740
|
}, "supervisor.run");
|
|
13156
14741
|
opts = Object.freeze({
|
|
@@ -13163,7 +14748,8 @@ function createSupervisor() {
|
|
|
13163
14748
|
...signal === void 0 ? {} : { signal },
|
|
13164
14749
|
...hooks === void 0 ? {} : { hooks },
|
|
13165
14750
|
...workerTrace === void 0 ? {} : { workerTrace },
|
|
13166
|
-
...workerTraceUnpropagated === void 0 ? {} : { workerTraceUnpropagated }
|
|
14751
|
+
...workerTraceUnpropagated === void 0 ? {} : { workerTraceUnpropagated },
|
|
14752
|
+
...interactiveBindingDir === void 0 ? {} : { interactiveBindingDir }
|
|
13167
14753
|
});
|
|
13168
14754
|
task = input.task;
|
|
13169
14755
|
const rootAct = root.act.bind(root);
|
|
@@ -13271,6 +14857,7 @@ function createSupervisor() {
|
|
|
13271
14857
|
...opts.probes ? { probes: opts.probes } : {},
|
|
13272
14858
|
...opts.workerTrace ? { workerTrace: opts.workerTrace } : {},
|
|
13273
14859
|
...opts.workerTraceUnpropagated ? { workerTraceUnpropagated: opts.workerTraceUnpropagated } : {},
|
|
14860
|
+
...opts.interactiveBindingDir ? { interactiveBindingDir: opts.interactiveBindingDir } : {},
|
|
13274
14861
|
...resumeFrom ? { resumeFrom } : {}
|
|
13275
14862
|
});
|
|
13276
14863
|
const openScope = scope;
|
|
@@ -13703,6 +15290,6 @@ function isNonEmptySpend(s) {
|
|
|
13703
15290
|
return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0 || s.tokensKnown === false || s.usdKnown === false;
|
|
13704
15291
|
}
|
|
13705
15292
|
//#endregion
|
|
13706
|
-
export {
|
|
15293
|
+
export { bridgeRuntimeAttachmentsKey as $, buildRuntimeEventOtelSpans as $t, readWorkerInteractiveBinding as A, profileMaterializationAxes$1 as An, isLiveNodeStatus as At, retainedCreateMaterial as B, worktreeCliProfileMaterialization as Bn, probeSandboxCapabilities as Bt, timerAt as C, parseCodexTokenUsage as Cn, DEFAULT_PEER_MAIL_LIMITS as Ct, readWorkerInteractiveAdmissions as D, controlProfileMaterialization as Dn, isPeerMailEnvelope as Dt, interactiveAdmissionSeamKey as E, assertProfileMaterialization as En, createPeerMailbox as Et, startRetainedInteractiveRun as F, renderProfileMaterializationIssues as Fn, createSandboxForSpec as Ft, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as G, observedModelMatchesDeclared as Gt, freeSlots as H, routerBrain as Ht, reconnectRetainedRun as I, renderUnsupported as In, defaultSelectWinner as It, createBudgetPool as J, readTraceContextFromEnv as Jt, teardownExecutor as K, createPropagatingTraceEmitter as Kt, recoverRetainedRun as L, sandboxActProfileMaterialization as Ln, isTerminalDecision as Lt, workerInteractiveBindingsDir as M, promptModelProfileMaterialization as Mn, createInPlaceCliExecutor as Mt, reconnectRetainedInteractiveRun as N, promptOnlyProfileMaterialization as Nn, taskToPrompt as Nt, workerInteractiveAdmissionFile as O, defineProfileMaterializationContract as On, peerMailTools as Ot, recoverRetainedInteractiveRun as P, promptResourceProfileMaterialization as Pn, TERMINAL_DECISIONS as Pt, bridgeModelRouteRefusal as Q, buildLoopSpanNodes as Qt, startRetainedRun as R, unsupportedProfileDimensions as Rn, runAgentRounds as Rt, pollFor as S, localHarnessExecutable as Sn, AUTHORITY_MARKERS as St, waitUntil as T, AGENT_PROFILE_MATERIALIZATION_AXES as Tn, claimsAuthority as Tt, queueOf as U, runBrainLoop as Ut, effectiveConcurrency as V, acquireSandbox as Vt, rollingDispatch as W, canonicalObservedModel as Wt, bindReusableExecutorExecutionId as X, INTELLIGENCE_WIRE_VERSION as Xt, spendFromUsageEvents as Y, traceContextToEnv as Yt, bridgeAdmissionRead as Z, buildLoopOtelSpans as Zt, recordScopeOwnerMaterialization as _, createWorktree as _n, sandboxSessionTraceSource as _t, uncertainSpawnBudgets as a, loopEventToOtelSpan as an, createExecutorRegistry as at, createWaitProbes as b, LOCAL_HARNESSES as bn, readWorkerProgress as bt, pickBestDelivered as c, toOtelAttributes as cn, WORKER_TRACE_PROPAGATION as ct, driverChild as d, sanitizeAgentRuntimeEvent as dn, workerTraceHeaders as dt, createOpenInferenceFileExporter as en, bridgeStopSignalKey as et, withDriverExecutor as f, sanitizeKnowledgeReadinessReport as fn, workerTraceSeamKey as ft, meterRuntimeOwnedProviderAttempt as g, captureWorktreeDiff as gn, decodeToolPart as gt, meterRuntimeOwnedAccounting as h, runWorktreeHarness as hn, createPushTraceSource as ht, sumMeasuredSpendFromEvents as i, generateSpanId as in, createExecutor as it, workerInteractiveBindingFile as j, promptControlProfileMaterialization as jn, isTerminalNodeStatus as jt, attachWorker as k, fullProfileMaterialization as kn, peerMailVerbNames as kt, runFinalizer as l, createRuntimeEventCollector as ln, readWorkerTraceContext as lt, deriveNodeExecutionIdentity as m, runSettledCommand as mn, createSteerableSandboxSession as mt, createSupervisor as n, exportEvalRuns as nn, cliInPlaceExecutor as nt, bestDelivered as o, padSpanId as on, snapshotExecutorConfig as ot, createScope as p, sanitizeRuntimeStreamEvent as pn, DEFAULT_SANDBOX_STEERING_MAX_TURNS as pt, assertValidBudget as q, mergeTraceEnv as qt, maxSeqOf as r, flatOtelSpan as rn, cliWorktreeExecutor as rt, collectDelivered as s, padTraceId as sn, createWorktreeCliExecutor as st, createRootHandle as t, createOtelExporter as tn, captureReusableExecutorConfig as tt, runTree as u, createRuntimeStreamEventCollector as un, workerTraceEnv as ut, scopeOwnerExecutorNodeContext as v, removeWorktree as vn, DEFAULT_STALL_AFTER_MS as vt, validateWaitSpec as w, CodexExecutionDiagnosticError as wn, PEER_MAIL_WIRE_KEY as wt, isWaitOutcome as x, harnessSupportsReasoningEffort as xn, createInbox as xt, settledToIteration as y, DEFAULT_LOCAL_HARNESS as yn, createActivityLog as yt, startRetainedRunInEnvironment as z, validateProfileMaterialization as zn, createSandboxLineage as zt };
|
|
13707
15294
|
|
|
13708
|
-
//# sourceMappingURL=supervisor-
|
|
15295
|
+
//# sourceMappingURL=supervisor-ChLgoYhG.js.map
|