@tangle-network/agent-runtime 0.300.0 → 0.301.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{activation-Bhp8dYV5.d.ts → activation-CRgEJutr.d.ts} +3 -3
- package/dist/{activation-DqWmWTyB.js → activation-V6aaOlZV.js} +2 -2
- package/dist/{activation-DqWmWTyB.js.map → activation-V6aaOlZV.js.map} +1 -1
- package/dist/agent.d.ts +2 -2
- package/dist/agent.js +2 -2
- package/dist/{coordination-driver-DzTvehd6.js → coordination-driver-vNrdQBSH.js} +317 -211
- package/dist/coordination-driver-vNrdQBSH.js.map +1 -0
- package/dist/{delegate-vJ2g76r6.js → delegate-B-jFJcbW.js} +5 -5
- package/dist/delegate-B-jFJcbW.js.map +1 -0
- package/dist/durable.d.ts +2 -2
- package/dist/durable.js +2 -2
- package/dist/{graph-BDQh3qry.js → graph-Dwv_hQB_.js} +5 -5
- package/dist/graph-Dwv_hQB_.js.map +1 -0
- package/dist/{improvement-cycle-D6cPLi6k.js → improvement-cycle-Cf37Kexd.js} +3 -3
- package/dist/{improvement-cycle-D6cPLi6k.js.map → improvement-cycle-Cf37Kexd.js.map} +1 -1
- package/dist/{index-sC6sl88d.d.ts → index-CxBVmgqL.d.ts} +149 -71
- package/dist/index.d.ts +6 -6
- package/dist/index.js +7 -7
- package/dist/intelligence.d.ts +3 -3
- package/dist/intelligence.js +4 -4
- package/dist/kernel.d.ts +4 -4
- package/dist/kernel.js +9 -9
- package/dist/{loop-runner-bin-DQIHnCL0.js → loop-runner-bin-C8MI8N1A.js} +3 -3
- package/dist/{loop-runner-bin-DQIHnCL0.js.map → loop-runner-bin-C8MI8N1A.js.map} +1 -1
- package/dist/{loop-runner-bin-DZglq4Cf.d.ts → loop-runner-bin-DiTNiJNs.d.ts} +3 -3
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +6 -6
- package/dist/mcp/index.js +5 -5
- package/dist/{openai-tools-DvR82zEo.d.ts → openai-tools-BeogJ6V8.d.ts} +2 -2
- package/dist/profiles.d.ts +2 -2
- package/dist/{provision-supervisor-IXBlLHE0.js → provision-supervisor-CS0fBIhp.js} +13 -24
- package/dist/provision-supervisor-CS0fBIhp.js.map +1 -0
- package/dist/{runtime-DpEt5v42.js → runtime-6VPSJVeg.js} +28 -36
- package/dist/runtime-6VPSJVeg.js.map +1 -0
- package/dist/{search-method-DvU-fc-f.js → search-method-wTTS7mGG.js} +2 -2
- package/dist/{search-method-DvU-fc-f.js.map → search-method-wTTS7mGG.js.map} +1 -1
- package/dist/{server-CIE8s4AN.js → server-BfHD5iLD.js} +3 -3
- package/dist/{server-CIE8s4AN.js.map → server-BfHD5iLD.js.map} +1 -1
- package/dist/{stream-agent-turn-I3bb0eqF.d.ts → stream-agent-turn-B1ipFtOc.d.ts} +4 -2
- package/dist/{substrate-UjsxukjZ.d.ts → substrate-DKBMd0Dl.d.ts} +2 -2
- package/dist/{supervise-C5mktzrh.js → supervise-BJrEC2Mh.js} +195 -59
- package/dist/supervise-BJrEC2Mh.js.map +1 -0
- package/dist/{supervisor-CQSu5XGl.js → supervisor-DA_nvF-h.js} +563 -181
- package/dist/supervisor-DA_nvF-h.js.map +1 -0
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +12 -12
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +1 -1
- package/dist/{types-C73caP0U.d.ts → types-jD9mNnJM.d.ts} +61 -11
- package/package.json +1 -1
- package/skills/profile-authoring/SKILL.md +3 -3
- package/skills/supervise/SKILL.md +2 -2
- package/dist/coordination-driver-DzTvehd6.js.map +0 -1
- package/dist/delegate-vJ2g76r6.js.map +0 -1
- package/dist/graph-BDQh3qry.js.map +0 -1
- package/dist/provision-supervisor-IXBlLHE0.js.map +0 -1
- package/dist/runtime-DpEt5v42.js.map +0 -1
- package/dist/supervise-C5mktzrh.js.map +0 -1
- package/dist/supervisor-CQSu5XGl.js.map +0 -1
|
@@ -109,6 +109,13 @@ const DEFAULT_SUCCESSFUL_SHUTDOWN_MS = 5e3;
|
|
|
109
109
|
const CHILD_DEADLINE_REASON = "child deadline exceeded";
|
|
110
110
|
/** The abort reason the root's budget deadline cascades to every node. */
|
|
111
111
|
const ROOT_DEADLINE_REASON = "root budget deadline exceeded";
|
|
112
|
+
/**
|
|
113
|
+
* How long an abort waits for a manager whose result was already accepted to end the turn that
|
|
114
|
+
* submitted it. Acceptance asks the turn's harness to stop; what remains is the turn's final
|
|
115
|
+
* session copy (a bounded native capture), metering its usage and committing its result. Its
|
|
116
|
+
* workspace capture is not part of it: the manager's owner runs that after the result.
|
|
117
|
+
*/
|
|
118
|
+
const ACCEPTED_RESULT_GRACE_MS = 5 * 6e4;
|
|
112
119
|
/** Whether an abort reason is a deadline: the child's own or the root budget's. */
|
|
113
120
|
function isDeadlineAbortReason(reason) {
|
|
114
121
|
return reason === "child deadline exceeded" || reason === "root budget deadline exceeded";
|
|
@@ -1809,6 +1816,7 @@ function mapSandboxToolEvent(event, state) {
|
|
|
1809
1816
|
if (String(part.type ?? "") !== "tool") return [];
|
|
1810
1817
|
return projectToolPart(part, state, typeof event.id === "string" ? event.id : void 0);
|
|
1811
1818
|
}
|
|
1819
|
+
if (CANONICAL_STREAM_EVENT_TYPES.has(type)) return [];
|
|
1812
1820
|
if (type.includes("tool")) {
|
|
1813
1821
|
const callId = pickString(data, [
|
|
1814
1822
|
"toolCallId",
|
|
@@ -7335,6 +7343,7 @@ function nativeSlots(port) {
|
|
|
7335
7343
|
}
|
|
7336
7344
|
return key;
|
|
7337
7345
|
}
|
|
7346
|
+
const capturesInFlight = /* @__PURE__ */ new WeakMap();
|
|
7338
7347
|
async function withCaptureSlot(port, signal, capture) {
|
|
7339
7348
|
if (port.maxConcurrentCaptures === void 0) return capture();
|
|
7340
7349
|
let group = captureGroups.get(port);
|
|
@@ -7351,13 +7360,56 @@ async function withCaptureSlot(port, signal, capture) {
|
|
|
7351
7360
|
permit.release();
|
|
7352
7361
|
}
|
|
7353
7362
|
}
|
|
7363
|
+
/** Count one capture of `port` in flight until `work` settles, and say how many were ahead. */
|
|
7364
|
+
function trackCapture(port, work) {
|
|
7365
|
+
const ahead = capturesInFlight.get(port) ?? 0;
|
|
7366
|
+
capturesInFlight.set(port, ahead + 1);
|
|
7367
|
+
return work(ahead).finally(() => {
|
|
7368
|
+
capturesInFlight.set(port, Math.max(0, (capturesInFlight.get(port) ?? 1) - 1));
|
|
7369
|
+
});
|
|
7370
|
+
}
|
|
7354
7371
|
/**
|
|
7355
7372
|
* Capture, require durable refs, and verify every returned manifest/archive byte.
|
|
7356
7373
|
* `native` calls {@link ProviderWorkspaceRetentionPort.captureNative} under its own queue and
|
|
7357
|
-
* bound, and judges coverage by the sessions alone.
|
|
7374
|
+
* bound, and judges coverage by the sessions alone. `onTiming` receives the queue wait and the
|
|
7375
|
+
* capture time of a workspace capture once it settles, whether it succeeded or failed.
|
|
7358
7376
|
*/
|
|
7359
|
-
async function captureProviderWorkspaceSnapshot(port, context, scope = "environment") {
|
|
7377
|
+
async function captureProviderWorkspaceSnapshot(port, context, scope = "environment", onTiming) {
|
|
7360
7378
|
assertProviderWorkspaceRetentionPort(port, "provider workspace retention");
|
|
7379
|
+
if (scope === "native" || onTiming === void 0) return await captureWithinSlot(port, context, scope);
|
|
7380
|
+
return await trackCapture(port, async (ahead) => {
|
|
7381
|
+
const requestedAt = Date.now();
|
|
7382
|
+
let grantedAt;
|
|
7383
|
+
const report = (timing) => {
|
|
7384
|
+
const settledAt = Date.now();
|
|
7385
|
+
try {
|
|
7386
|
+
onTiming({
|
|
7387
|
+
ahead,
|
|
7388
|
+
queuedMs: (grantedAt ?? settledAt) - requestedAt,
|
|
7389
|
+
...grantedAt === void 0 ? {} : { captureMs: settledAt - grantedAt },
|
|
7390
|
+
...timing
|
|
7391
|
+
});
|
|
7392
|
+
} catch {}
|
|
7393
|
+
};
|
|
7394
|
+
try {
|
|
7395
|
+
const captured = await captureWithinSlot(port, context, scope, () => {
|
|
7396
|
+
grantedAt = Date.now();
|
|
7397
|
+
});
|
|
7398
|
+
report({
|
|
7399
|
+
outcome: "captured",
|
|
7400
|
+
archiveBytes: captured.snapshot.archive.byteLength
|
|
7401
|
+
});
|
|
7402
|
+
return captured;
|
|
7403
|
+
} catch (error) {
|
|
7404
|
+
report({
|
|
7405
|
+
outcome: "failed",
|
|
7406
|
+
error: (error instanceof Error ? error.message : String(error)).slice(0, 1e3)
|
|
7407
|
+
});
|
|
7408
|
+
throw error;
|
|
7409
|
+
}
|
|
7410
|
+
});
|
|
7411
|
+
}
|
|
7412
|
+
async function captureWithinSlot(port, context, scope, onGranted) {
|
|
7361
7413
|
const native = scope === "native";
|
|
7362
7414
|
if (native && port.captureNative === void 0) throw new ValidationError$1("provider workspace retention: the port has no captureNative");
|
|
7363
7415
|
const timeoutMs = native ? port.nativeTimeoutMs ?? 12e4 : port.timeoutMs;
|
|
@@ -7367,6 +7419,7 @@ async function captureProviderWorkspaceSnapshot(port, context, scope = "environm
|
|
|
7367
7419
|
const clearDeadline = armDeadlineTimer(timeoutMs, () => controller.abort(/* @__PURE__ */ new Error(`provider workspace retention timed out after ${timeoutMs}ms`)), true);
|
|
7368
7420
|
try {
|
|
7369
7421
|
return await runAbortable(() => withCaptureSlot(native ? nativeSlots(port) : port, controller.signal, async () => {
|
|
7422
|
+
onGranted?.();
|
|
7370
7423
|
const input = {
|
|
7371
7424
|
...context,
|
|
7372
7425
|
...controlRef === void 0 ? {} : { controlRef: Object.freeze({ ...controlRef }) },
|
|
@@ -8652,6 +8705,119 @@ function describeRetainedNativeStops(stops) {
|
|
|
8652
8705
|
}).join("; ");
|
|
8653
8706
|
}
|
|
8654
8707
|
//#endregion
|
|
8708
|
+
//#region src/runtime/supervise/executor-seams.ts
|
|
8709
|
+
function assertExactConfigKeys(value, allowed, context) {
|
|
8710
|
+
const unknown = Object.keys(value).filter((key) => !allowed.has(key));
|
|
8711
|
+
if (unknown.length > 0) throw new ValidationError$1(`${context}: unknown fields ${unknown.sort().join(", ")}; execution behavior belongs in AgentProfile`);
|
|
8712
|
+
}
|
|
8713
|
+
/** Narrow a named seam off the `ExecutorContext`, failing loud when absent — no
|
|
8714
|
+
* silent default for a required external-boundary seam. */
|
|
8715
|
+
function readSeam(ctx, key, who) {
|
|
8716
|
+
const seam = ctx.seams[key];
|
|
8717
|
+
if (seam === void 0 || seam === null) throw new ValidationError$1(`${who} executor: missing required seam "${key}" on ExecutorContext`);
|
|
8718
|
+
return seam;
|
|
8719
|
+
}
|
|
8720
|
+
function readOptionalAbortSignal(ctx, key, who) {
|
|
8721
|
+
const value = ctx.seams[key];
|
|
8722
|
+
if (value === void 0) return void 0;
|
|
8723
|
+
if (value === null || typeof value !== "object" || typeof value.aborted !== "boolean" || typeof value.addEventListener !== "function") throw new ValidationError$1(`${who} executor: seam "${key}" must be an AbortSignal`);
|
|
8724
|
+
return value;
|
|
8725
|
+
}
|
|
8726
|
+
/** Narrow the Runtime-owned MCP attachment seam. Absent means the run mounts nothing; a present
|
|
8727
|
+
* value must be a named map of MCP servers, never an empty one that would silently mount nothing. */
|
|
8728
|
+
function readOptionalMcpAttachments(ctx, key, who) {
|
|
8729
|
+
const value = ctx.seams[key];
|
|
8730
|
+
if (value === void 0) return void 0;
|
|
8731
|
+
const entries = value !== null && typeof value === "object" && !Array.isArray(value) ? Object.entries(value) : void 0;
|
|
8732
|
+
if (entries === void 0 || entries.length === 0 || entries.some(([, server]) => server === null || typeof server !== "object")) throw new ValidationError$1(`${who} executor: seam ${JSON.stringify(key)} must be a non-empty map of MCP servers`);
|
|
8733
|
+
return value;
|
|
8734
|
+
}
|
|
8735
|
+
//#endregion
|
|
8736
|
+
//#region src/runtime/supervise/bridge-config.ts
|
|
8737
|
+
const bridgeSeamKey = "bridge";
|
|
8738
|
+
/** Internal control seam used by Runtime-owned external supervisors. A completion request stops
|
|
8739
|
+
* the next bridge turn; it must not abort the paid request that is already streaming. */
|
|
8740
|
+
const bridgeStopSignalKey = "__bridge_stop_signal";
|
|
8741
|
+
/** Internal attachment seam used by Runtime-owned external supervisors. The named MCP servers ride
|
|
8742
|
+
* beside the AgentProfile as `runtime_attachments`, so the bridge mounts them for the run and keeps
|
|
8743
|
+
* them out of its session profile binding. A rebound coordination port therefore cannot move the
|
|
8744
|
+
* authored profile digest that binds a durable session. */
|
|
8745
|
+
const bridgeRuntimeAttachmentsKey = "__bridge_runtime_attachments";
|
|
8746
|
+
const maxBridgeTimeoutMs = 2147483647;
|
|
8747
|
+
function isLoopbackBridgeHost(hostname) {
|
|
8748
|
+
const host = hostname.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
|
|
8749
|
+
if (host === "localhost" || host === "::1" || host === "0:0:0:0:0:0:0:1") return true;
|
|
8750
|
+
if (host === "::ffff:127.0.0.1") return true;
|
|
8751
|
+
return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/u.test(host);
|
|
8752
|
+
}
|
|
8753
|
+
function isLoopbackBridgeUrl(value) {
|
|
8754
|
+
try {
|
|
8755
|
+
const target = new URL(value);
|
|
8756
|
+
return (target.protocol === "http:" || target.protocol === "https:") && isLoopbackBridgeHost(target.hostname);
|
|
8757
|
+
} catch {
|
|
8758
|
+
return false;
|
|
8759
|
+
}
|
|
8760
|
+
}
|
|
8761
|
+
/** Validate and capture the non-serialisable credential service without reading its value. */
|
|
8762
|
+
function captureBridgeModelCredential(value, context) {
|
|
8763
|
+
if (value === null || typeof value !== "object") throw new ValidationError$1(`${context}: modelCredential must be an object`);
|
|
8764
|
+
assertExactConfigKeys(value, /* @__PURE__ */ new Set([
|
|
8765
|
+
"baseUrlKey",
|
|
8766
|
+
"key",
|
|
8767
|
+
"provider"
|
|
8768
|
+
]), `${context} modelCredential`);
|
|
8769
|
+
if (typeof value.key !== "string" || value.key.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.key must be a non-empty string`);
|
|
8770
|
+
if (typeof value.baseUrlKey !== "string" || value.baseUrlKey.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must be a non-empty string`);
|
|
8771
|
+
if (value.baseUrlKey === value.key) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must differ from key`);
|
|
8772
|
+
if (!value.provider || typeof value.provider.get !== "function") throw new ValidationError$1(`${context}: modelCredential.provider must implement get(name)`);
|
|
8773
|
+
const captured = {
|
|
8774
|
+
key: value.key,
|
|
8775
|
+
baseUrlKey: value.baseUrlKey
|
|
8776
|
+
};
|
|
8777
|
+
Object.defineProperty(captured, "provider", {
|
|
8778
|
+
configurable: false,
|
|
8779
|
+
enumerable: false,
|
|
8780
|
+
value: value.provider,
|
|
8781
|
+
writable: false
|
|
8782
|
+
});
|
|
8783
|
+
return Object.freeze(captured);
|
|
8784
|
+
}
|
|
8785
|
+
function validateBridgeModelCredential(value, bridgeUrl, context) {
|
|
8786
|
+
if (value === void 0) return void 0;
|
|
8787
|
+
if (!isLoopbackBridgeUrl(bridgeUrl)) throw new ValidationError$1(`${context}: modelCredential is allowed only for a loopback bridge URL`);
|
|
8788
|
+
return captureBridgeModelCredential(value, context);
|
|
8789
|
+
}
|
|
8790
|
+
function resolveProtectedModelBaseUrl(value, context) {
|
|
8791
|
+
let target;
|
|
8792
|
+
try {
|
|
8793
|
+
target = new URL(value);
|
|
8794
|
+
} catch {
|
|
8795
|
+
throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an absolute HTTPS URL`);
|
|
8796
|
+
}
|
|
8797
|
+
if (target.protocol !== "https:" || target.username || target.password || target.search || target.hash) throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an HTTPS URL without credentials, query, or fragment`);
|
|
8798
|
+
return target.toString().replace(/\/$/u, "");
|
|
8799
|
+
}
|
|
8800
|
+
/** Resolve only at the outbound boundary. Provider errors are redacted because they may contain
|
|
8801
|
+
* the protected value; diagnostics identify key names, never values or provider errors. */
|
|
8802
|
+
async function resolveBridgeModelCredential(credential, context) {
|
|
8803
|
+
if (credential === void 0) return void 0;
|
|
8804
|
+
const resolveValue = async (key) => {
|
|
8805
|
+
let value;
|
|
8806
|
+
try {
|
|
8807
|
+
value = await credential.provider.get(key);
|
|
8808
|
+
} catch {
|
|
8809
|
+
throw new ValidationError$1(`${context}: modelCredential provider failed for '${key}'`);
|
|
8810
|
+
}
|
|
8811
|
+
if (typeof value !== "string" || value.length === 0 || /[\r\n\0]/u.test(value)) throw new ValidationError$1(`${context}: modelCredential provider has no usable value for '${key}'`);
|
|
8812
|
+
return value;
|
|
8813
|
+
};
|
|
8814
|
+
const [token, baseUrl] = await Promise.all([resolveValue(credential.key), resolveValue(credential.baseUrlKey)]);
|
|
8815
|
+
return {
|
|
8816
|
+
token,
|
|
8817
|
+
baseUrl: resolveProtectedModelBaseUrl(baseUrl, context)
|
|
8818
|
+
};
|
|
8819
|
+
}
|
|
8820
|
+
//#endregion
|
|
8655
8821
|
//#region src/runtime/supervise/cost-estimate.ts
|
|
8656
8822
|
/**
|
|
8657
8823
|
* Pricing for work that arrived without a provider receipt.
|
|
@@ -10204,6 +10370,7 @@ const outsideKinds = /* @__PURE__ */ new Set([
|
|
|
10204
10370
|
"workspace-checkpoint",
|
|
10205
10371
|
"workspace-checkpoint-cleanup",
|
|
10206
10372
|
"workspace-restored",
|
|
10373
|
+
"workspace-capture",
|
|
10207
10374
|
"trace-unpropagated",
|
|
10208
10375
|
"paused",
|
|
10209
10376
|
"driver-attempt",
|
|
@@ -10280,6 +10447,7 @@ async function replaySpawnTree(journal, blobs, root) {
|
|
|
10280
10447
|
if (ev.kind === "workspace-checkpoint") continue;
|
|
10281
10448
|
if (ev.kind === "workspace-checkpoint-cleanup") continue;
|
|
10282
10449
|
if (ev.kind === "workspace-restored") continue;
|
|
10450
|
+
if (ev.kind === "workspace-capture") continue;
|
|
10283
10451
|
if (ev.kind === "trace-unpropagated") continue;
|
|
10284
10452
|
if (ev.kind === "paused") continue;
|
|
10285
10453
|
if (ev.kind === "driver-attempt") continue;
|
|
@@ -10622,6 +10790,18 @@ function executorEvidenceWriter(args) {
|
|
|
10622
10790
|
});
|
|
10623
10791
|
};
|
|
10624
10792
|
}
|
|
10793
|
+
/** @internal The journal writer for `onWorkspaceCapture`; `nextSequence` is the node's own. */
|
|
10794
|
+
function workspaceCaptureWriter(args) {
|
|
10795
|
+
return async (capture) => {
|
|
10796
|
+
await args.journal.appendEvent(args.rootId, {
|
|
10797
|
+
kind: "workspace-capture",
|
|
10798
|
+
id: args.nodeId,
|
|
10799
|
+
...detachedSnapshot(capture, "workspace capture timing"),
|
|
10800
|
+
seq: args.nextSequence(),
|
|
10801
|
+
at: new Date(args.now()).toISOString()
|
|
10802
|
+
});
|
|
10803
|
+
};
|
|
10804
|
+
}
|
|
10625
10805
|
function retainedExecutorContext(ctx) {
|
|
10626
10806
|
return ctx.seams[retainedExecutorSeamKey];
|
|
10627
10807
|
}
|
|
@@ -11286,6 +11466,18 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
|
|
|
11286
11466
|
let pending = false;
|
|
11287
11467
|
let harnessTranscript = harnessTranscriptUnavailable("execution-never-started");
|
|
11288
11468
|
const retention = retainedExecutorContext(ctx);
|
|
11469
|
+
const managerStop = readOptionalAbortSignal(ctx, bridgeStopSignalKey, "provider");
|
|
11470
|
+
const cancelRetainedOnManagerStop = (handle) => {
|
|
11471
|
+
if (managerStop === void 0) return;
|
|
11472
|
+
const cancel = () => {
|
|
11473
|
+
handle.cancel({
|
|
11474
|
+
operationId: `manager-stop:${randomUUID()}`,
|
|
11475
|
+
reason: String(managerStop.reason ?? "the manager stopped")
|
|
11476
|
+
}).catch(() => void 0);
|
|
11477
|
+
};
|
|
11478
|
+
if (managerStop.aborted) cancel();
|
|
11479
|
+
else managerStop.addEventListener("abort", cancel, { once: true });
|
|
11480
|
+
};
|
|
11289
11481
|
let destroyed = false;
|
|
11290
11482
|
let workspaceEnvironmentId;
|
|
11291
11483
|
let workspaceSnapshot;
|
|
@@ -11378,7 +11570,19 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
|
|
|
11378
11570
|
profile: createProfile,
|
|
11379
11571
|
...outcome === void 0 ? {} : { outcome }
|
|
11380
11572
|
};
|
|
11381
|
-
|
|
11573
|
+
const reportTiming = retention?.onWorkspaceCapture;
|
|
11574
|
+
let timing;
|
|
11575
|
+
const capturedExecutionId = workspaceExecutionId;
|
|
11576
|
+
workspaceCapturePromise = (nativeInFlight ?? Promise.resolve()).then(() => captureProviderWorkspaceSnapshot(workspaceRetention, captureContext, "environment", reportTiming === void 0 ? void 0 : (measured) => {
|
|
11577
|
+
timing = measured;
|
|
11578
|
+
})).finally(async () => {
|
|
11579
|
+
if (timing === void 0 || reportTiming === void 0) return;
|
|
11580
|
+
await reportTiming({
|
|
11581
|
+
executionId: capturedExecutionId,
|
|
11582
|
+
environmentId: next.id,
|
|
11583
|
+
...timing
|
|
11584
|
+
}).catch(() => void 0);
|
|
11585
|
+
}).then(({ snapshot, provenance, coverageComplete, incompleteReason }) => {
|
|
11382
11586
|
workspaceSnapshot = snapshot;
|
|
11383
11587
|
workspaceProvenance = provenance;
|
|
11384
11588
|
workspaceCoverageComplete = coverageComplete ?? false;
|
|
@@ -11695,10 +11899,12 @@ function createProviderExecutor(provider, profile, ctx, options, placement) {
|
|
|
11695
11899
|
...carried === void 0 ? {} : { carried },
|
|
11696
11900
|
executionStartedAt,
|
|
11697
11901
|
mayContinue: options.unavailablePause !== false && invocation.retention?.continueInvocation !== void 0,
|
|
11902
|
+
managerStopped: () => managerStop?.aborted === true,
|
|
11698
11903
|
onRetained: (handle) => {
|
|
11699
11904
|
retained = handle;
|
|
11700
11905
|
workspaceControlRef = freezeControlRef(handle.controlRef);
|
|
11701
11906
|
providerSessionId = workspaceControlRef.sessionId;
|
|
11907
|
+
cancelRetainedOnManagerStop(handle);
|
|
11702
11908
|
},
|
|
11703
11909
|
onPending: (value) => {
|
|
11704
11910
|
pending = value;
|
|
@@ -11978,6 +12184,19 @@ async function* streamProviderExecutor(args) {
|
|
|
11978
12184
|
let failure;
|
|
11979
12185
|
let failed = false;
|
|
11980
12186
|
let unavailable;
|
|
12187
|
+
let finalCopyTaken = false;
|
|
12188
|
+
const ownerTakesCapture = () => args.options.workspaceRetention?.captureNative !== void 0 && args.createProfile.harness !== void 0 && source.retained && args.retention?.preserveEnvironment === true && args.retention.onEndOfTurnWork !== void 0;
|
|
12189
|
+
const handCaptureToOwner = (reported, captureOutcome, publish) => {
|
|
12190
|
+
args.retention?.onEndOfTurnWork?.(args.captureWorkspace(environment, captureOutcome).then(async (snapshot) => {
|
|
12191
|
+
if (publish) args.onPublishedSnapshot(snapshot);
|
|
12192
|
+
if (snapshot === void 0) return;
|
|
12193
|
+
await args.retention?.onEvidence?.({
|
|
12194
|
+
...reported,
|
|
12195
|
+
workspaceSnapshot: snapshot,
|
|
12196
|
+
workspaceCapture: providerWorkspaceCaptureReceipt(args, environment, snapshot, turn.sessionId ?? null)
|
|
12197
|
+
});
|
|
12198
|
+
}, () => void 0));
|
|
12199
|
+
};
|
|
11981
12200
|
let harnessStop;
|
|
11982
12201
|
const stopEndedHarness = () => {
|
|
11983
12202
|
if (settled !== void 0 || !linked.aborted) return Promise.resolve();
|
|
@@ -12058,14 +12277,17 @@ async function* streamProviderExecutor(args) {
|
|
|
12058
12277
|
box: environmentAsSandboxInstance(environment, { requireTerminalEvent: args.options.requireTerminalEvent ?? true }),
|
|
12059
12278
|
signal: linked
|
|
12060
12279
|
});
|
|
12280
|
+
const deferCapture = ownerTakesCapture() && args.managerStopped();
|
|
12061
12281
|
let retainedWorkspace;
|
|
12062
12282
|
let workspaceCaptureFailure;
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12283
|
+
if (!deferCapture) {
|
|
12284
|
+
try {
|
|
12285
|
+
retainedWorkspace = await args.captureWorkspace(environment, outcome);
|
|
12286
|
+
} catch (error) {
|
|
12287
|
+
workspaceCaptureFailure = `${errorText(error instanceof Error ? error.message : error)}; source environment preserved`;
|
|
12288
|
+
}
|
|
12289
|
+
args.onPublishedSnapshot(retainedWorkspace);
|
|
12067
12290
|
}
|
|
12068
|
-
args.onPublishedSnapshot(retainedWorkspace);
|
|
12069
12291
|
const settledResult = {
|
|
12070
12292
|
...result,
|
|
12071
12293
|
...workspaceCaptureFailure === void 0 ? {} : { workspaceCaptureFailure },
|
|
@@ -12099,6 +12321,11 @@ async function* streamProviderExecutor(args) {
|
|
|
12099
12321
|
else if (retainedWorkspace !== void 0) await args.retention?.onEvidence?.(settledResult);
|
|
12100
12322
|
args.onPending(false);
|
|
12101
12323
|
args.onArtifact(settled);
|
|
12324
|
+
if (deferCapture) {
|
|
12325
|
+
await args.finishNativeMirror(environment, "settled");
|
|
12326
|
+
finalCopyTaken = true;
|
|
12327
|
+
handCaptureToOwner(settledResult, outcome, true);
|
|
12328
|
+
}
|
|
12102
12329
|
} catch (error) {
|
|
12103
12330
|
failure = source.retained ? new RetainedExecutionPendingError(error) : error;
|
|
12104
12331
|
failed = true;
|
|
@@ -12112,7 +12339,14 @@ async function* streamProviderExecutor(args) {
|
|
|
12112
12339
|
await stopEndedHarness();
|
|
12113
12340
|
if (linked.aborted) await args.finishNativeMirror(environment, "failed");
|
|
12114
12341
|
args.onTranscriptSettled();
|
|
12115
|
-
|
|
12342
|
+
if (ownerTakesCapture()) {
|
|
12343
|
+
if (!linked.aborted) await args.finishNativeMirror(environment, "failed");
|
|
12344
|
+
finalCopyTaken = true;
|
|
12345
|
+
handCaptureToOwner({
|
|
12346
|
+
...resultFromEvents(archive.events(), text),
|
|
12347
|
+
outcome: failureOutcome
|
|
12348
|
+
}, failureOutcome, false);
|
|
12349
|
+
} else try {
|
|
12116
12350
|
const retainedWorkspace = await args.captureWorkspace(environment, failureOutcome);
|
|
12117
12351
|
if (retainedWorkspace !== void 0 && args.retention?.onEvidence !== void 0) await args.retention.onEvidence({
|
|
12118
12352
|
...resultFromEvents(archive.events(), text),
|
|
@@ -12127,7 +12361,7 @@ async function* streamProviderExecutor(args) {
|
|
|
12127
12361
|
if (args.options.workspaceRetention === void 0) args.onHarnessTranscript(await captureHarnessTranscript(environment, args.profile.harness, linked));
|
|
12128
12362
|
} finally {
|
|
12129
12363
|
await stopEndedHarness();
|
|
12130
|
-
await args.finishNativeMirror(environment, failed ? "failed" : settled !== void 0 ? "settled" : "interrupted");
|
|
12364
|
+
if (!finalCopyTaken) await args.finishNativeMirror(environment, failed ? "failed" : settled !== void 0 ? "settled" : "interrupted");
|
|
12131
12365
|
if ((!source.retained || settled !== void 0 && !failed) && !(source.retained && args.retention?.preserveEnvironment) && !(unavailable !== void 0 && !failed) && (args.options.destroyOnSettle ?? true)) {
|
|
12132
12366
|
const cleanup = await args.destroyEnvironment();
|
|
12133
12367
|
if (!cleanup.destroyed) {
|
|
@@ -13277,6 +13511,14 @@ async function runBrainLoop(opts) {
|
|
|
13277
13511
|
role: "assistant",
|
|
13278
13512
|
content: r.content
|
|
13279
13513
|
});
|
|
13514
|
+
const next = maxTurns === 0 || turn < maxTurns ? await opts.hooks?.afterFinal?.(turn) : void 0;
|
|
13515
|
+
if (next !== void 0) {
|
|
13516
|
+
messages.push({
|
|
13517
|
+
role: "user",
|
|
13518
|
+
content: next
|
|
13519
|
+
});
|
|
13520
|
+
continue;
|
|
13521
|
+
}
|
|
13280
13522
|
return {
|
|
13281
13523
|
final: lastText,
|
|
13282
13524
|
turns: turn,
|
|
@@ -15617,119 +15859,6 @@ function sandboxToolCalls(events) {
|
|
|
15617
15859
|
}] : []));
|
|
15618
15860
|
}
|
|
15619
15861
|
//#endregion
|
|
15620
|
-
//#region src/runtime/supervise/executor-seams.ts
|
|
15621
|
-
function assertExactConfigKeys(value, allowed, context) {
|
|
15622
|
-
const unknown = Object.keys(value).filter((key) => !allowed.has(key));
|
|
15623
|
-
if (unknown.length > 0) throw new ValidationError$1(`${context}: unknown fields ${unknown.sort().join(", ")}; execution behavior belongs in AgentProfile`);
|
|
15624
|
-
}
|
|
15625
|
-
/** Narrow a named seam off the `ExecutorContext`, failing loud when absent — no
|
|
15626
|
-
* silent default for a required external-boundary seam. */
|
|
15627
|
-
function readSeam(ctx, key, who) {
|
|
15628
|
-
const seam = ctx.seams[key];
|
|
15629
|
-
if (seam === void 0 || seam === null) throw new ValidationError$1(`${who} executor: missing required seam "${key}" on ExecutorContext`);
|
|
15630
|
-
return seam;
|
|
15631
|
-
}
|
|
15632
|
-
function readOptionalAbortSignal(ctx, key, who) {
|
|
15633
|
-
const value = ctx.seams[key];
|
|
15634
|
-
if (value === void 0) return void 0;
|
|
15635
|
-
if (value === null || typeof value !== "object" || typeof value.aborted !== "boolean" || typeof value.addEventListener !== "function") throw new ValidationError$1(`${who} executor: seam "${key}" must be an AbortSignal`);
|
|
15636
|
-
return value;
|
|
15637
|
-
}
|
|
15638
|
-
/** Narrow the Runtime-owned MCP attachment seam. Absent means the run mounts nothing; a present
|
|
15639
|
-
* value must be a named map of MCP servers, never an empty one that would silently mount nothing. */
|
|
15640
|
-
function readOptionalMcpAttachments(ctx, key, who) {
|
|
15641
|
-
const value = ctx.seams[key];
|
|
15642
|
-
if (value === void 0) return void 0;
|
|
15643
|
-
const entries = value !== null && typeof value === "object" && !Array.isArray(value) ? Object.entries(value) : void 0;
|
|
15644
|
-
if (entries === void 0 || entries.length === 0 || entries.some(([, server]) => server === null || typeof server !== "object")) throw new ValidationError$1(`${who} executor: seam ${JSON.stringify(key)} must be a non-empty map of MCP servers`);
|
|
15645
|
-
return value;
|
|
15646
|
-
}
|
|
15647
|
-
//#endregion
|
|
15648
|
-
//#region src/runtime/supervise/bridge-config.ts
|
|
15649
|
-
const bridgeSeamKey = "bridge";
|
|
15650
|
-
/** Internal control seam used by Runtime-owned external supervisors. A completion request stops
|
|
15651
|
-
* the next bridge turn; it must not abort the paid request that is already streaming. */
|
|
15652
|
-
const bridgeStopSignalKey = "__bridge_stop_signal";
|
|
15653
|
-
/** Internal attachment seam used by Runtime-owned external supervisors. The named MCP servers ride
|
|
15654
|
-
* beside the AgentProfile as `runtime_attachments`, so the bridge mounts them for the run and keeps
|
|
15655
|
-
* them out of its session profile binding. A rebound coordination port therefore cannot move the
|
|
15656
|
-
* authored profile digest that binds a durable session. */
|
|
15657
|
-
const bridgeRuntimeAttachmentsKey = "__bridge_runtime_attachments";
|
|
15658
|
-
const maxBridgeTimeoutMs = 2147483647;
|
|
15659
|
-
function isLoopbackBridgeHost(hostname) {
|
|
15660
|
-
const host = hostname.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
|
|
15661
|
-
if (host === "localhost" || host === "::1" || host === "0:0:0:0:0:0:0:1") return true;
|
|
15662
|
-
if (host === "::ffff:127.0.0.1") return true;
|
|
15663
|
-
return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/u.test(host);
|
|
15664
|
-
}
|
|
15665
|
-
function isLoopbackBridgeUrl(value) {
|
|
15666
|
-
try {
|
|
15667
|
-
const target = new URL(value);
|
|
15668
|
-
return (target.protocol === "http:" || target.protocol === "https:") && isLoopbackBridgeHost(target.hostname);
|
|
15669
|
-
} catch {
|
|
15670
|
-
return false;
|
|
15671
|
-
}
|
|
15672
|
-
}
|
|
15673
|
-
/** Validate and capture the non-serialisable credential service without reading its value. */
|
|
15674
|
-
function captureBridgeModelCredential(value, context) {
|
|
15675
|
-
if (value === null || typeof value !== "object") throw new ValidationError$1(`${context}: modelCredential must be an object`);
|
|
15676
|
-
assertExactConfigKeys(value, /* @__PURE__ */ new Set([
|
|
15677
|
-
"baseUrlKey",
|
|
15678
|
-
"key",
|
|
15679
|
-
"provider"
|
|
15680
|
-
]), `${context} modelCredential`);
|
|
15681
|
-
if (typeof value.key !== "string" || value.key.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.key must be a non-empty string`);
|
|
15682
|
-
if (typeof value.baseUrlKey !== "string" || value.baseUrlKey.trim().length === 0) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must be a non-empty string`);
|
|
15683
|
-
if (value.baseUrlKey === value.key) throw new ValidationError$1(`${context}: modelCredential.baseUrlKey must differ from key`);
|
|
15684
|
-
if (!value.provider || typeof value.provider.get !== "function") throw new ValidationError$1(`${context}: modelCredential.provider must implement get(name)`);
|
|
15685
|
-
const captured = {
|
|
15686
|
-
key: value.key,
|
|
15687
|
-
baseUrlKey: value.baseUrlKey
|
|
15688
|
-
};
|
|
15689
|
-
Object.defineProperty(captured, "provider", {
|
|
15690
|
-
configurable: false,
|
|
15691
|
-
enumerable: false,
|
|
15692
|
-
value: value.provider,
|
|
15693
|
-
writable: false
|
|
15694
|
-
});
|
|
15695
|
-
return Object.freeze(captured);
|
|
15696
|
-
}
|
|
15697
|
-
function validateBridgeModelCredential(value, bridgeUrl, context) {
|
|
15698
|
-
if (value === void 0) return void 0;
|
|
15699
|
-
if (!isLoopbackBridgeUrl(bridgeUrl)) throw new ValidationError$1(`${context}: modelCredential is allowed only for a loopback bridge URL`);
|
|
15700
|
-
return captureBridgeModelCredential(value, context);
|
|
15701
|
-
}
|
|
15702
|
-
function resolveProtectedModelBaseUrl(value, context) {
|
|
15703
|
-
let target;
|
|
15704
|
-
try {
|
|
15705
|
-
target = new URL(value);
|
|
15706
|
-
} catch {
|
|
15707
|
-
throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an absolute HTTPS URL`);
|
|
15708
|
-
}
|
|
15709
|
-
if (target.protocol !== "https:" || target.username || target.password || target.search || target.hash) throw new ValidationError$1(`${context}: modelCredential.baseUrl must be an HTTPS URL without credentials, query, or fragment`);
|
|
15710
|
-
return target.toString().replace(/\/$/u, "");
|
|
15711
|
-
}
|
|
15712
|
-
/** Resolve only at the outbound boundary. Provider errors are redacted because they may contain
|
|
15713
|
-
* the protected value; diagnostics identify key names, never values or provider errors. */
|
|
15714
|
-
async function resolveBridgeModelCredential(credential, context) {
|
|
15715
|
-
if (credential === void 0) return void 0;
|
|
15716
|
-
const resolveValue = async (key) => {
|
|
15717
|
-
let value;
|
|
15718
|
-
try {
|
|
15719
|
-
value = await credential.provider.get(key);
|
|
15720
|
-
} catch {
|
|
15721
|
-
throw new ValidationError$1(`${context}: modelCredential provider failed for '${key}'`);
|
|
15722
|
-
}
|
|
15723
|
-
if (typeof value !== "string" || value.length === 0 || /[\r\n\0]/u.test(value)) throw new ValidationError$1(`${context}: modelCredential provider has no usable value for '${key}'`);
|
|
15724
|
-
return value;
|
|
15725
|
-
};
|
|
15726
|
-
const [token, baseUrl] = await Promise.all([resolveValue(credential.key), resolveValue(credential.baseUrlKey)]);
|
|
15727
|
-
return {
|
|
15728
|
-
token,
|
|
15729
|
-
baseUrl: resolveProtectedModelBaseUrl(baseUrl, context)
|
|
15730
|
-
};
|
|
15731
|
-
}
|
|
15732
|
-
//#endregion
|
|
15733
15862
|
//#region src/runtime/codex-rollout-store.ts
|
|
15734
15863
|
const zeroCounters = {
|
|
15735
15864
|
input: 0,
|
|
@@ -17613,11 +17742,20 @@ function renderPeerMail(message, nonce) {
|
|
|
17613
17742
|
function createInbox() {
|
|
17614
17743
|
const pending = [];
|
|
17615
17744
|
let live = null;
|
|
17745
|
+
let waiters = [];
|
|
17616
17746
|
return {
|
|
17747
|
+
nextDelivery() {
|
|
17748
|
+
return new Promise((resolve) => {
|
|
17749
|
+
waiters.push(resolve);
|
|
17750
|
+
});
|
|
17751
|
+
},
|
|
17617
17752
|
deliver(msg) {
|
|
17618
17753
|
const m = parseDown(msg);
|
|
17619
17754
|
if (!m) return false;
|
|
17620
17755
|
pending.push(m);
|
|
17756
|
+
const woken = waiters;
|
|
17757
|
+
waiters = [];
|
|
17758
|
+
for (const wake of woken) wake();
|
|
17621
17759
|
if (m.interrupt && live && !live.signal.aborted) live.abort();
|
|
17622
17760
|
return true;
|
|
17623
17761
|
},
|
|
@@ -23245,6 +23383,18 @@ function registerScopeRetainedOwner(scope, args) {
|
|
|
23245
23383
|
nextSequence: () => state.nextSequence(),
|
|
23246
23384
|
now: args.now
|
|
23247
23385
|
}),
|
|
23386
|
+
onWorkspaceCapture: workspaceCaptureWriter({
|
|
23387
|
+
journal: args.journal,
|
|
23388
|
+
rootId: args.rootId,
|
|
23389
|
+
nodeId: args.nodeId,
|
|
23390
|
+
nextSequence: () => state.nextSequence(),
|
|
23391
|
+
now: args.now
|
|
23392
|
+
}),
|
|
23393
|
+
onEndOfTurnWork: (work) => {
|
|
23394
|
+
const prior = state.turnEnd;
|
|
23395
|
+
const settled = work.catch(() => void 0);
|
|
23396
|
+
state.turnEnd = prior === void 0 ? settled : Promise.all([prior, settled]).then(() => {});
|
|
23397
|
+
},
|
|
23248
23398
|
onResult: async (result) => {
|
|
23249
23399
|
scope.signal.throwIfAborted();
|
|
23250
23400
|
assertValidSpend(result.spent, "retained owner result");
|
|
@@ -23475,7 +23625,14 @@ async function checkpointHandle(state, sourceEnvironmentId, signal) {
|
|
|
23475
23625
|
return;
|
|
23476
23626
|
}
|
|
23477
23627
|
}
|
|
23478
|
-
/**
|
|
23628
|
+
/**
|
|
23629
|
+
* An aborted observation cannot prove that the provider never created a snapshot, so a request
|
|
23630
|
+
* whose lookup does not find it keeps its source alive for a later lookup, with one exception: a
|
|
23631
|
+
* provider that answers `not_found` for a request older than {@link WORKSPACE_CHECKPOINT_ABSENT_AFTER_MS}
|
|
23632
|
+
* never created it. No operation that request started can still be in flight, and keeping the
|
|
23633
|
+
* source then holds a sandbox for nothing: on Discovery Lab runs terraform-economics-20261005e and
|
|
23634
|
+
* f, each root was kept after its run settled over requests made hours earlier.
|
|
23635
|
+
*/
|
|
23479
23636
|
async function reconcileCheckpointRequests(state, events) {
|
|
23480
23637
|
const operationKey = (operation) => JSON.stringify([operation.idempotencyKey, operation.requestDigest]);
|
|
23481
23638
|
const resolved = new Set(events.flatMap((event) => event.kind === "workspace-checkpoint" && event.id === state.args.nodeId && event.provider === state.provider?.name ? [operationKey(event.checkpoint)] : []));
|
|
@@ -23490,7 +23647,29 @@ async function reconcileCheckpointRequests(state, events) {
|
|
|
23490
23647
|
idempotencyKey: event.request.idempotencyKey,
|
|
23491
23648
|
requestDigest: event.request.requestDigest
|
|
23492
23649
|
}, { signal }), signal, "retained owner checkpoint lookup timed out");
|
|
23493
|
-
if (result.status
|
|
23650
|
+
if (result.status === "not_found") {
|
|
23651
|
+
const requestedAt = Date.parse(event.at);
|
|
23652
|
+
if (Number.isFinite(requestedAt) && state.args.now() - requestedAt >= 12e5) continue;
|
|
23653
|
+
unconfirmed.push({
|
|
23654
|
+
event,
|
|
23655
|
+
reason: "lookup not_found while the request may be in flight"
|
|
23656
|
+
});
|
|
23657
|
+
continue;
|
|
23658
|
+
}
|
|
23659
|
+
if (result.status !== "found") {
|
|
23660
|
+
unconfirmed.push({
|
|
23661
|
+
event,
|
|
23662
|
+
reason: `lookup ${result.status}${"message" in result && result.message ? `: ${result.message}` : ""}`
|
|
23663
|
+
});
|
|
23664
|
+
continue;
|
|
23665
|
+
}
|
|
23666
|
+
if (!workspaceCheckpointResultMatchesRequest(event.request, result)) {
|
|
23667
|
+
unconfirmed.push({
|
|
23668
|
+
event,
|
|
23669
|
+
reason: "lookup found a checkpoint for another request"
|
|
23670
|
+
});
|
|
23671
|
+
continue;
|
|
23672
|
+
}
|
|
23494
23673
|
const recovered = {
|
|
23495
23674
|
kind: "workspace-checkpoint",
|
|
23496
23675
|
id: event.id,
|
|
@@ -23503,8 +23682,11 @@ async function reconcileCheckpointRequests(state, events) {
|
|
|
23503
23682
|
};
|
|
23504
23683
|
await state.args.journal.appendEvent(state.args.rootId, recovered);
|
|
23505
23684
|
events.push(recovered);
|
|
23506
|
-
} catch {
|
|
23507
|
-
unconfirmed.push(
|
|
23685
|
+
} catch (error) {
|
|
23686
|
+
unconfirmed.push({
|
|
23687
|
+
event,
|
|
23688
|
+
reason: `lookup failed: ${errorText(error instanceof Error ? error.message : error)}`
|
|
23689
|
+
});
|
|
23508
23690
|
}
|
|
23509
23691
|
}
|
|
23510
23692
|
return unconfirmed;
|
|
@@ -23582,16 +23764,94 @@ async function scopeRetainedOwnerRestorePoint(scope) {
|
|
|
23582
23764
|
function retainedOwnerReleaseRetriable(scope) {
|
|
23583
23765
|
return owners.get(scope)?.releaseRetriable ?? false;
|
|
23584
23766
|
}
|
|
23585
|
-
/**
|
|
23586
|
-
|
|
23767
|
+
/**
|
|
23768
|
+
* Mark one drive of the owner in progress until the returned function is called. An abort settles
|
|
23769
|
+
* the node while the drive is still ending its turn: stopping the harness, copying its session and
|
|
23770
|
+
* handing its workspace capture over. A release that ran then would find no receipt for the turn
|
|
23771
|
+
* and keep the source alive, as on terraform-economics-20261005f, where the root's last attempt was
|
|
23772
|
+
* recorded two minutes after its environment's release.
|
|
23773
|
+
*/
|
|
23774
|
+
function beginScopeRetainedOwnerDrive(scope) {
|
|
23587
23775
|
const state = owners.get(scope);
|
|
23588
|
-
if (
|
|
23589
|
-
|
|
23776
|
+
if (state === void 0) return () => {};
|
|
23777
|
+
let end;
|
|
23778
|
+
const drive = new Promise((resolve) => {
|
|
23779
|
+
end = resolve;
|
|
23780
|
+
});
|
|
23781
|
+
state.drive = drive;
|
|
23782
|
+
return () => {
|
|
23783
|
+
end();
|
|
23784
|
+
if (state.drive === drive) delete state.drive;
|
|
23785
|
+
};
|
|
23786
|
+
}
|
|
23787
|
+
/** Wait, bounded like a turn's own ending, for the owner's drive in progress to end. */
|
|
23788
|
+
async function ownerDriveEnded(state) {
|
|
23789
|
+
const drive = state.drive;
|
|
23790
|
+
if (drive === void 0) return;
|
|
23791
|
+
let timer;
|
|
23792
|
+
try {
|
|
23793
|
+
await Promise.race([drive, new Promise((resolve) => {
|
|
23794
|
+
timer = setTimeout(resolve, HARNESS_TRANSCRIPT_SETTLE_TIMEOUT_MS);
|
|
23795
|
+
})]);
|
|
23796
|
+
} finally {
|
|
23797
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
23798
|
+
}
|
|
23799
|
+
}
|
|
23800
|
+
/**
|
|
23801
|
+
* Wait for the end-of-turn work the owner's last turn handed over: its workspace capture and the
|
|
23802
|
+
* evidence record of its receipt. A turn hands it over so that its node settles without it; the
|
|
23803
|
+
* owner's next turn and its environment's release wait for it here.
|
|
23804
|
+
*/
|
|
23805
|
+
async function scopeRetainedOwnerTurnEnded(scope) {
|
|
23806
|
+
const state = owners.get(scope);
|
|
23807
|
+
if (state === void 0) return;
|
|
23808
|
+
for (;;) {
|
|
23809
|
+
const pending = state.turnEnd;
|
|
23810
|
+
if (pending === void 0) return;
|
|
23811
|
+
await pending;
|
|
23812
|
+
if (state.turnEnd === pending) {
|
|
23813
|
+
delete state.turnEnd;
|
|
23814
|
+
return;
|
|
23815
|
+
}
|
|
23816
|
+
}
|
|
23817
|
+
}
|
|
23818
|
+
/** @internal Wait for everything this owner still has in flight: the drive ending its turn, the
|
|
23819
|
+
* work that turn handed over, and a release. */
|
|
23820
|
+
async function scopeRetainedOwnerSettled(scope) {
|
|
23821
|
+
const state = owners.get(scope);
|
|
23822
|
+
if (state === void 0) return;
|
|
23823
|
+
await ownerDriveEnded(state);
|
|
23824
|
+
await scopeRetainedOwnerTurnEnded(scope);
|
|
23825
|
+
await state.releasing?.catch(() => void 0);
|
|
23826
|
+
}
|
|
23827
|
+
/**
|
|
23828
|
+
* Release the owner's environment once no turn of it will run again: at the run's final
|
|
23829
|
+
* settlement for the root, and when a nested manager's own scope has finished. A second call while
|
|
23830
|
+
* one is in flight joins it. The release first waits for the end-of-turn capture of the owner's
|
|
23831
|
+
* last turn, so the capture always precedes the destroy.
|
|
23832
|
+
*/
|
|
23833
|
+
function releaseScopeRetainedOwnerEnvironment(scope) {
|
|
23834
|
+
const state = owners.get(scope);
|
|
23835
|
+
const provider = state?.provider;
|
|
23836
|
+
if (state === void 0 || provider === void 0) return Promise.resolve([]);
|
|
23837
|
+
if (state.releasing !== void 0) return state.releasing;
|
|
23838
|
+
const tracked = (async () => {
|
|
23839
|
+
await ownerDriveEnded(state);
|
|
23840
|
+
await scopeRetainedOwnerTurnEnded(scope);
|
|
23841
|
+
return await releaseOwnerEnvironment(state, provider);
|
|
23842
|
+
})().finally(() => {
|
|
23843
|
+
if (state.releasing === tracked) delete state.releasing;
|
|
23844
|
+
});
|
|
23845
|
+
state.releasing = tracked;
|
|
23846
|
+
return tracked;
|
|
23847
|
+
}
|
|
23848
|
+
async function releaseOwnerEnvironment(state, provider) {
|
|
23849
|
+
const { args } = state;
|
|
23590
23850
|
state.checkpointsUnavailable ??= "released";
|
|
23591
23851
|
await state.checkpointing?.catch(() => void 0);
|
|
23592
23852
|
const events = [...await args.journal.loadTree(args.rootId) ?? []];
|
|
23593
23853
|
const requestFailures = await reconcileCheckpointRequests(state, events);
|
|
23594
|
-
const pendingSources = new Set(requestFailures.map((event) => event.environmentId));
|
|
23854
|
+
const pendingSources = new Set(requestFailures.map(({ event }) => event.environmentId));
|
|
23595
23855
|
const released = new Set(events.flatMap((event) => event.kind === "environment-teardown" && event.id === args.nodeId && event.provider === provider.name && event.destroyed ? [event.environmentId] : []));
|
|
23596
23856
|
const environments = new Set(events.flatMap((event) => event.id === args.nodeId && event.kind === "execution-admitted" && event.admission.phase === "environment" ? [event.admission.environmentId] : []));
|
|
23597
23857
|
const retentionFailures = state.workspaceRetention || events.some((event) => event.kind === "execution-input" && event.id === args.nodeId && event.workspaceRetention === true) ? await ownerWorkspaceRetentionFailures(events, args.nodeId, args.blobs) : /* @__PURE__ */ new Set();
|
|
@@ -23674,12 +23934,12 @@ async function releaseScopeRetainedOwnerEnvironment(scope) {
|
|
|
23674
23934
|
runtime: provider.name,
|
|
23675
23935
|
status: "done",
|
|
23676
23936
|
detail: `checkpoint cleanup unconfirmed: ${event.checkpoint.checkpointId} from ${event.environmentId}`
|
|
23677
|
-
})), ...requestFailures.map((event) => ({
|
|
23937
|
+
})), ...requestFailures.map(({ event, reason }) => ({
|
|
23678
23938
|
id: args.nodeId,
|
|
23679
23939
|
label: "scope owner checkpoint request",
|
|
23680
23940
|
runtime: provider.name,
|
|
23681
23941
|
status: "done",
|
|
23682
|
-
detail: `checkpoint request unresolved: ${event.request.idempotencyKey} from ${event.environmentId}`
|
|
23942
|
+
detail: `checkpoint request unresolved: ${event.request.idempotencyKey} from ${event.environmentId} (${reason})`
|
|
23683
23943
|
}))];
|
|
23684
23944
|
return unconfirmed.length > 0 || preserved.length > 0 ? [{
|
|
23685
23945
|
id: args.nodeId,
|
|
@@ -23718,7 +23978,15 @@ function unsettledOwnerRuns(events, nodeId, environmentId) {
|
|
|
23718
23978
|
close();
|
|
23719
23979
|
return [...runs.values()];
|
|
23720
23980
|
}
|
|
23721
|
-
/**
|
|
23981
|
+
/**
|
|
23982
|
+
* Group owner admissions by input and require a verified workspace receipt before deletion.
|
|
23983
|
+
*
|
|
23984
|
+
* The receipt is the attempt's committed result, or an evidence record of the same attempt: a
|
|
23985
|
+
* turn its manager stopped commits its result first and journals its capture as evidence after
|
|
23986
|
+
* it, and a turn that failed journals the capture it took of the stopped session. This runs only
|
|
23987
|
+
* at a release no process will resume, so a complete, verified capture of the exact execution is
|
|
23988
|
+
* the whole of what keeping the source would preserve.
|
|
23989
|
+
*/
|
|
23722
23990
|
async function ownerWorkspaceRetentionFailures(events, nodeId, blobs) {
|
|
23723
23991
|
const attempts = [];
|
|
23724
23992
|
let current;
|
|
@@ -23726,30 +23994,26 @@ async function ownerWorkspaceRetentionFailures(events, nodeId, blobs) {
|
|
|
23726
23994
|
if (current !== void 0) attempts.push(current);
|
|
23727
23995
|
current = void 0;
|
|
23728
23996
|
};
|
|
23997
|
+
const fresh = (executionId) => ({
|
|
23998
|
+
...executionId === void 0 ? {} : { executionId },
|
|
23999
|
+
environmentIds: /* @__PURE__ */ new Set(),
|
|
24000
|
+
controlByEnvironment: /* @__PURE__ */ new Map(),
|
|
24001
|
+
evidence: []
|
|
24002
|
+
});
|
|
23729
24003
|
for (const event of events) {
|
|
23730
24004
|
if (!("id" in event) || event.id !== nodeId) continue;
|
|
23731
24005
|
if (event.kind === "execution-input") {
|
|
23732
24006
|
flush();
|
|
23733
|
-
current = {
|
|
23734
|
-
executionId: `${nodeId}:input:${event.seq}`,
|
|
23735
|
-
environmentIds: /* @__PURE__ */ new Set(),
|
|
23736
|
-
controlByEnvironment: /* @__PURE__ */ new Map()
|
|
23737
|
-
};
|
|
24007
|
+
current = fresh(`${nodeId}:input:${event.seq}`);
|
|
23738
24008
|
} else if (event.kind === "execution-admitted" && event.admission.phase === "environment") {
|
|
23739
24009
|
if (current?.result !== void 0) flush();
|
|
23740
|
-
current ??=
|
|
23741
|
-
environmentIds: /* @__PURE__ */ new Set(),
|
|
23742
|
-
controlByEnvironment: /* @__PURE__ */ new Map()
|
|
23743
|
-
};
|
|
24010
|
+
current ??= fresh();
|
|
23744
24011
|
current.environmentIds.add(event.admission.environmentId);
|
|
23745
24012
|
} else if (event.kind === "execution-admitted" && event.admission.phase === "dispatched") current?.controlByEnvironment.set(event.admission.controlRef.environmentId, event.admission.controlRef);
|
|
23746
24013
|
else if (event.kind === "execution-result") {
|
|
23747
|
-
current ??=
|
|
23748
|
-
environmentIds: /* @__PURE__ */ new Set(),
|
|
23749
|
-
controlByEnvironment: /* @__PURE__ */ new Map()
|
|
23750
|
-
};
|
|
24014
|
+
current ??= fresh();
|
|
23751
24015
|
current.result = event;
|
|
23752
|
-
}
|
|
24016
|
+
} else if (event.kind === "execution-evidence") current?.evidence.push(event);
|
|
23753
24017
|
}
|
|
23754
24018
|
flush();
|
|
23755
24019
|
const failures = /* @__PURE__ */ new Set();
|
|
@@ -23759,25 +24023,30 @@ async function ownerWorkspaceRetentionFailures(events, nodeId, blobs) {
|
|
|
23759
24023
|
for (const environmentId of attempt.environmentIds) failures.add(environmentId);
|
|
23760
24024
|
continue;
|
|
23761
24025
|
}
|
|
23762
|
-
const result = attempt.result;
|
|
23763
|
-
if (result === void 0) {
|
|
23764
|
-
for (const environmentId of attempt.environmentIds) failures.add(environmentId);
|
|
23765
|
-
continue;
|
|
23766
|
-
}
|
|
23767
|
-
let output;
|
|
23768
|
-
try {
|
|
23769
|
-
output = await blobs.get(result.outRef);
|
|
23770
|
-
if (output === void 0 || contentAddress(output) !== result.outRef) throw new Error();
|
|
23771
|
-
} catch {
|
|
23772
|
-
output = void 0;
|
|
23773
|
-
}
|
|
23774
|
-
const snapshot = output !== null && typeof output === "object" ? output.workspaceSnapshot : void 0;
|
|
23775
24026
|
const environmentId = [...attempt.environmentIds][0];
|
|
23776
24027
|
const controlRef = attempt.controlByEnvironment.get(environmentId);
|
|
23777
|
-
|
|
24028
|
+
const receipts = [...attempt.result === void 0 ? [] : [attempt.result.outRef], ...attempt.evidence.map((event) => event.outRef)];
|
|
24029
|
+
let verified = false;
|
|
24030
|
+
for (const outRef of receipts) {
|
|
24031
|
+
const output = await storedOutput(blobs, outRef);
|
|
24032
|
+
if (hasDurableWorkspaceCapture(output, output !== null && typeof output === "object" ? output.workspaceSnapshot : void 0, environmentId, attempt.executionId, controlRef)) {
|
|
24033
|
+
verified = true;
|
|
24034
|
+
break;
|
|
24035
|
+
}
|
|
24036
|
+
}
|
|
24037
|
+
if (!verified) failures.add(environmentId);
|
|
23778
24038
|
}
|
|
23779
24039
|
return failures;
|
|
23780
24040
|
}
|
|
24041
|
+
/** A stored output whose bytes match its content reference, or undefined. */
|
|
24042
|
+
async function storedOutput(blobs, outRef) {
|
|
24043
|
+
try {
|
|
24044
|
+
const output = await blobs.get(outRef);
|
|
24045
|
+
return output === void 0 || contentAddress(output) !== outRef ? void 0 : output;
|
|
24046
|
+
} catch {
|
|
24047
|
+
return;
|
|
24048
|
+
}
|
|
24049
|
+
}
|
|
23781
24050
|
/** A stored result authorizes cleanup only for the exact source and complete capture. */
|
|
23782
24051
|
function hasDurableWorkspaceCapture(output, snapshot, environmentId, executionId, controlRef) {
|
|
23783
24052
|
const parsed = agentCandidateWorkspaceSnapshotEvidenceSchema.safeParse(snapshot);
|
|
@@ -23993,13 +24262,12 @@ function consumeScopeRetainedOwnerResult(scope) {
|
|
|
23993
24262
|
* absolute `timeoutAtMs` passes (CI status, file existence, an HTTP probe, an
|
|
23994
24263
|
* inbox message).
|
|
23995
24264
|
*
|
|
23996
|
-
* ── How this differs from
|
|
24265
|
+
* ── How this differs from a manager's wake (`./wake`) ──
|
|
23997
24266
|
*
|
|
23998
|
-
* They look similar and are not the same mechanism.
|
|
23999
|
-
*
|
|
24000
|
-
*
|
|
24001
|
-
*
|
|
24002
|
-
* up, and nothing about that wait is recorded: kill the process and the wait is simply gone.
|
|
24267
|
+
* They look similar and are not the same mechanism. A wake is an IN-RUN RENDEZVOUS: a manager
|
|
24268
|
+
* that ends its turn with work open is resumed when the coordination bus delivers its next event.
|
|
24269
|
+
* It costs no model turn, but it lives in a process that must stay up, and nothing about that
|
|
24270
|
+
* wait is recorded: kill the process and the wait is simply gone.
|
|
24003
24271
|
*
|
|
24004
24272
|
* A wait-state is a NODE, not a call. It has a node id in the tree, a journal record carrying its
|
|
24005
24273
|
* ABSOLUTE deadline, and it settles through the same `Scope.next()` cursor as any worker. Nobody
|
|
@@ -24191,6 +24459,10 @@ const teardownRetriable = /* @__PURE__ */ new WeakMap();
|
|
|
24191
24459
|
const ownerUnconfirmedByScope = /* @__PURE__ */ new WeakMap();
|
|
24192
24460
|
/** The scope a recursive executor owns, so the settlement retry reaches its descendants. */
|
|
24193
24461
|
const nestedTeardownScopes = /* @__PURE__ */ new WeakMap();
|
|
24462
|
+
/** Each scope's reader of the manager scopes its children own, read live. */
|
|
24463
|
+
const nestedManagerScopeReaders = /* @__PURE__ */ new WeakMap();
|
|
24464
|
+
/** A manager scope's release of its own environment, started once and joined by later callers. */
|
|
24465
|
+
const managerEnvironmentReleases = /* @__PURE__ */ new WeakMap();
|
|
24194
24466
|
/** Scopes whose settlement released retained environments: none of their retained children is
|
|
24195
24467
|
* kept for a resume any longer. */
|
|
24196
24468
|
const releasingScopes = /* @__PURE__ */ new WeakSet();
|
|
@@ -24268,9 +24540,47 @@ async function releaseRetainedEnvironments(scope) {
|
|
|
24268
24540
|
releasingScopes.add(scope);
|
|
24269
24541
|
const release = retainedReleasers.get(scope);
|
|
24270
24542
|
if (release) await release();
|
|
24543
|
+
await releaseNestedManagerEnvironments(scope);
|
|
24271
24544
|
ownerUnconfirmedByScope.set(scope, await releaseScopeRetainedOwnerEnvironment(scope));
|
|
24272
24545
|
return unconfirmedTeardowns(scope);
|
|
24273
24546
|
}
|
|
24547
|
+
/** The manager scopes this scope's children own, read live. */
|
|
24548
|
+
function nestedManagerScopes(scope) {
|
|
24549
|
+
return nestedManagerScopeReaders.get(scope)?.() ?? [];
|
|
24550
|
+
}
|
|
24551
|
+
async function releaseNestedManagerEnvironments(scope) {
|
|
24552
|
+
await Promise.all(nestedManagerScopes(scope).map(async (nested) => {
|
|
24553
|
+
await releaseNestedManagerEnvironments(nested);
|
|
24554
|
+
if (!ownerUnconfirmedByScope.has(nested)) await releaseManagerEnvironment(nested);
|
|
24555
|
+
}));
|
|
24556
|
+
}
|
|
24557
|
+
/**
|
|
24558
|
+
* @internal Release the environment a manager kept between its turns, once its own scope has
|
|
24559
|
+
* finished and no turn of it will run again. The release first waits for the manager's last
|
|
24560
|
+
* end-of-turn capture, so it runs in the background of the manager's settlement; a later call,
|
|
24561
|
+
* including the run's settlement sweep, joins it. Its receipt is journaled in the manager's own
|
|
24562
|
+
* tree. It is the manager's own resource, not one of its descendants, so it never changes the
|
|
24563
|
+
* teardown answer its executor gives the parent.
|
|
24564
|
+
*/
|
|
24565
|
+
function releaseManagerEnvironment(scope) {
|
|
24566
|
+
let release = managerEnvironmentReleases.get(scope);
|
|
24567
|
+
if (release === void 0) {
|
|
24568
|
+
release = releaseScopeRetainedOwnerEnvironment(scope).then(() => void 0);
|
|
24569
|
+
managerEnvironmentReleases.set(scope, release);
|
|
24570
|
+
}
|
|
24571
|
+
return release;
|
|
24572
|
+
}
|
|
24573
|
+
/**
|
|
24574
|
+
* @internal Wait for the work every manager in this scope's tree still has in flight after its
|
|
24575
|
+
* node settled: the end-of-turn capture its last turn handed over, and the release of its
|
|
24576
|
+
* environment. The run's settlement awaits it under either retention policy, so nothing writes to
|
|
24577
|
+
* the run's journal after the run settles and no capture is cut short by the process exiting.
|
|
24578
|
+
*/
|
|
24579
|
+
async function settleManagerWork(scope) {
|
|
24580
|
+
await Promise.all(nestedManagerScopes(scope).map((nested) => settleManagerWork(nested)));
|
|
24581
|
+
await scopeRetainedOwnerSettled(scope);
|
|
24582
|
+
await managerEnvironmentReleases.get(scope)?.catch(() => void 0);
|
|
24583
|
+
}
|
|
24274
24584
|
/**
|
|
24275
24585
|
* @internal Close the cursor slot of every retained child this scope and its nested scopes still
|
|
24276
24586
|
* hold open, once the settlement is final and the release and its retries are done.
|
|
@@ -24694,6 +25004,14 @@ function createScope(args) {
|
|
|
24694
25004
|
}, "accepted retained child result");
|
|
24695
25005
|
live.recoveryPending = false;
|
|
24696
25006
|
});
|
|
25007
|
+
let captureSeq = 0;
|
|
25008
|
+
const onWorkspaceCapture = workspaceCaptureWriter({
|
|
25009
|
+
journal: args.journal,
|
|
25010
|
+
rootId: args.root,
|
|
25011
|
+
nodeId: id,
|
|
25012
|
+
nextSequence: () => captureSeq++,
|
|
25013
|
+
now
|
|
25014
|
+
});
|
|
24697
25015
|
const onPause = (pause) => retainedWrite(async () => {
|
|
24698
25016
|
await args.journal.appendEvent(args.root, {
|
|
24699
25017
|
kind: "paused",
|
|
@@ -24722,6 +25040,7 @@ function createScope(args) {
|
|
|
24722
25040
|
now
|
|
24723
25041
|
}),
|
|
24724
25042
|
onPause,
|
|
25043
|
+
onWorkspaceCapture,
|
|
24725
25044
|
continueInvocation: async (nextTask) => {
|
|
24726
25045
|
controller.signal.throwIfAborted();
|
|
24727
25046
|
if (live.acceptedResult === void 0) throw new ValidationError$1("scope: a retained child continues only after its invocation committed a result");
|
|
@@ -24838,7 +25157,7 @@ function createScope(args) {
|
|
|
24838
25157
|
abortChild: (reason) => controller.abort(reason)
|
|
24839
25158
|
};
|
|
24840
25159
|
const recordCancellation = () => {
|
|
24841
|
-
if (!live.executorDone && live.acceptedResult === void 0 && controller.signal.reason instanceof RunCancellationReason) live.cancellationReason = controller.signal.reason;
|
|
25160
|
+
if (!live.executorDone && live.acceptedResult === void 0 && executor.resultAccepted?.() !== true && controller.signal.reason instanceof RunCancellationReason) live.cancellationReason = controller.signal.reason;
|
|
24842
25161
|
};
|
|
24843
25162
|
if (controller.signal.aborted) recordCancellation();
|
|
24844
25163
|
else controller.signal.addEventListener("abort", recordCancellation, { once: true });
|
|
@@ -25498,6 +25817,10 @@ function createScope(args) {
|
|
|
25498
25817
|
return child.ownedTreeRoot === void 0 || nested === void 0 || hasRetriableTeardowns(nested, true);
|
|
25499
25818
|
});
|
|
25500
25819
|
teardownRetriable.set(scope, (release) => retriableTeardowns().length > 0 || release && (releasable().length > 0 || retainedOwnerReleaseRetriable(scope)));
|
|
25820
|
+
nestedManagerScopeReaders.set(scope, () => [...children.values()].flatMap((child) => {
|
|
25821
|
+
const nested = child.readNestedScope?.();
|
|
25822
|
+
return nested === void 0 ? [] : [nested];
|
|
25823
|
+
}));
|
|
25501
25824
|
teardownRetriers.set(scope, async () => {
|
|
25502
25825
|
await Promise.all(retriableTeardowns().map((child) => {
|
|
25503
25826
|
child.teardownRetry ??= (async () => {
|
|
@@ -26261,7 +26584,7 @@ async function runChild(live, executor, childAbort, task, opts, pool, ticket, bl
|
|
|
26261
26584
|
const reconcileError = reconcileOnce(accounting?.reservation ?? terminalSpend);
|
|
26262
26585
|
if (reconcileError !== void 0) throw reconcileError;
|
|
26263
26586
|
} else {
|
|
26264
|
-
const terminal = await retainOutput(await
|
|
26587
|
+
const terminal = await retainOutput(await awaitUnlessAccepted(Promise.resolve(ran), childAbort.signal, executor));
|
|
26265
26588
|
await executionEvidence.complete();
|
|
26266
26589
|
const accounting = executor.accounting?.();
|
|
26267
26590
|
live.spent = accounting?.reported ?? terminal.spent;
|
|
@@ -26275,7 +26598,7 @@ async function runChild(live, executor, childAbort, task, opts, pool, ticket, bl
|
|
|
26275
26598
|
const ownMetered = executor.metered?.();
|
|
26276
26599
|
const trace = await captureTraceOnce();
|
|
26277
26600
|
const childHarnessTranscript = await persistTranscriptOnce();
|
|
26278
|
-
if (childAbort.signal.aborted && live.acceptedResult === void 0) {
|
|
26601
|
+
if (childAbort.signal.aborted && live.acceptedResult === void 0 && executor.resultAccepted?.() !== true) {
|
|
26279
26602
|
await teardownOnce(opts.shutdown ?? "brutalKill");
|
|
26280
26603
|
return downRecord("aborted before settle", true, trace, ownMetered, runtimeOwnedExecutorProviderEvidence(executor), retainedOutputRef, childHarnessTranscript);
|
|
26281
26604
|
}
|
|
@@ -26667,6 +26990,19 @@ function preserveUnknownTelemetry(streamed, terminal) {
|
|
|
26667
26990
|
...(streamed.tokensProvenance ?? terminal.tokensProvenance) === void 0 ? {} : { tokensProvenance: streamed.tokensProvenance ?? terminal.tokensProvenance }
|
|
26668
26991
|
};
|
|
26669
26992
|
}
|
|
26993
|
+
/**
|
|
26994
|
+
* Await a one-shot executor's terminal result unless an abort wins first, except for an execution
|
|
26995
|
+
* whose result was accepted before the abort arrived: it is ending the turn that submitted that
|
|
26996
|
+
* result, so it is awaited rather than discarded, and the executor bounds that wait itself.
|
|
26997
|
+
*/
|
|
26998
|
+
async function awaitUnlessAccepted(work, signal, executor) {
|
|
26999
|
+
try {
|
|
27000
|
+
return await awaitAbortable(work, signal);
|
|
27001
|
+
} catch (error) {
|
|
27002
|
+
if (signal.aborted && executor.resultAccepted?.() === true) return await work;
|
|
27003
|
+
throw error;
|
|
27004
|
+
}
|
|
27005
|
+
}
|
|
26670
27006
|
async function awaitAbortable(work, signal) {
|
|
26671
27007
|
if (signal.aborted) {
|
|
26672
27008
|
work.catch(() => void 0);
|
|
@@ -26879,6 +27215,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
|
|
|
26879
27215
|
...spec.progress ? { progress: spec.progress } : {},
|
|
26880
27216
|
...spec.harnessTranscript ? { harnessTranscript: spec.harnessTranscript } : {},
|
|
26881
27217
|
...spec.harnessTranscriptSettled ? { harnessTranscriptSettled: spec.harnessTranscriptSettled } : {},
|
|
27218
|
+
resultAccepted: () => driver.resultAccepted?.() === true,
|
|
26882
27219
|
...deliver ? { deliver(message) {
|
|
26883
27220
|
return deliver(message) !== false;
|
|
26884
27221
|
} } : {},
|
|
@@ -26901,8 +27238,15 @@ const driverExecutorFactory = (rawSpec, ctx) => {
|
|
|
26901
27238
|
if (recovering && (!spec.recoverExecutor || !seam.restore)) throw new RetainedExecutionPendingError(new ValidationError$1("driverExecutor: nested recovery has no original executor reconstruction"), "nested-recovery");
|
|
26902
27239
|
signal.throwIfAborted();
|
|
26903
27240
|
const controller = new AbortController();
|
|
26904
|
-
|
|
26905
|
-
|
|
27241
|
+
let clearAcceptedGrace;
|
|
27242
|
+
const onParentAbort = () => {
|
|
27243
|
+
if (driver.resultAccepted?.() === true) {
|
|
27244
|
+
clearAcceptedGrace ??= armDeadlineTimer(ACCEPTED_RESULT_GRACE_MS, () => controller.abort(signal.reason));
|
|
27245
|
+
return;
|
|
27246
|
+
}
|
|
27247
|
+
controller.abort(signal.reason);
|
|
27248
|
+
};
|
|
27249
|
+
if (signal.aborted) onParentAbort();
|
|
26906
27250
|
else signal.addEventListener("abort", onParentAbort, { once: true });
|
|
26907
27251
|
let nestedScope;
|
|
26908
27252
|
try {
|
|
@@ -26925,6 +27269,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
|
|
|
26925
27269
|
const out = await runAbortable(() => driver.act(task, nestedScope), controller.signal, "driver aborted");
|
|
26926
27270
|
await finalizeScopeOwnerMaterialization(nestedScope);
|
|
26927
27271
|
await closeActive("driver completed");
|
|
27272
|
+
releaseManagerEnvironment(nestedScope).catch(() => void 0);
|
|
26928
27273
|
const events = await loadTreeEvents(journal, nestedRoot);
|
|
26929
27274
|
const childWork = sumSpend(events.filter(isSettled));
|
|
26930
27275
|
const totalMetered = sumMetered(events);
|
|
@@ -26955,6 +27300,7 @@ const driverExecutorFactory = (rawSpec, ctx) => {
|
|
|
26955
27300
|
throw err;
|
|
26956
27301
|
} finally {
|
|
26957
27302
|
signal.removeEventListener("abort", onParentAbort);
|
|
27303
|
+
clearAcceptedGrace?.();
|
|
26958
27304
|
active = void 0;
|
|
26959
27305
|
}
|
|
26960
27306
|
},
|
|
@@ -27953,7 +28299,7 @@ var DriverAttemptsExhaustedError = class extends RuntimeRunStateError {
|
|
|
27953
28299
|
function summarizeDriverAttempts(records) {
|
|
27954
28300
|
let barren = 0;
|
|
27955
28301
|
for (const record of records) if (record.madeProgress) barren = 0;
|
|
27956
|
-
else if (record.error === void 0 && record.reentry !== void 0 && record.contract === "unmet") barren += 1;
|
|
28302
|
+
else if (record.error === void 0 && record.reentry !== void 0 && record.reentry !== "wake" && record.contract === "unmet") barren += 1;
|
|
27957
28303
|
const last = records.at(-1);
|
|
27958
28304
|
const refused = records.filter((record) => record.classification === "unavailable");
|
|
27959
28305
|
return {
|
|
@@ -27963,6 +28309,8 @@ function summarizeDriverAttempts(records) {
|
|
|
27963
28309
|
unavailablePauses: refused.filter((record) => record.retryInMs !== void 0).length,
|
|
27964
28310
|
unavailableMs: refused.reduce((sum, record) => sum + (record.madeProgress ? 0 : record.durationMs) + (record.retryInMs ?? 0), 0),
|
|
27965
28311
|
barrenReentries: barren,
|
|
28312
|
+
wakes: records.filter((record) => record.reentry === "wake").length,
|
|
28313
|
+
waitedMs: records.reduce((sum, record) => sum + (record.waitedMs ?? 0), 0),
|
|
27966
28314
|
ended: last?.stop ?? "unrecorded",
|
|
27967
28315
|
...last?.repromptRefusedBy === void 0 ? {} : { repromptRefusedBy: last.repromptRefusedBy }
|
|
27968
28316
|
};
|
|
@@ -28005,6 +28353,7 @@ async function runDriverWithRetry(run) {
|
|
|
28005
28353
|
let consecutivePauses = 0;
|
|
28006
28354
|
let pauses = 0;
|
|
28007
28355
|
let continuations = 0;
|
|
28356
|
+
let wakes = 0;
|
|
28008
28357
|
let reentry;
|
|
28009
28358
|
const emit = async (record) => {
|
|
28010
28359
|
const entered = reentry === void 0 ? {} : { reentry: reentry.reason };
|
|
@@ -28164,7 +28513,28 @@ async function runDriverWithRetry(run) {
|
|
|
28164
28513
|
const contract = contractOf(after);
|
|
28165
28514
|
const contractField = contract === "none" ? {} : { contract };
|
|
28166
28515
|
if (progressed) barrenReentries = 0;
|
|
28167
|
-
else if (reentry !== void 0 && contract === "unmet") barrenReentries += 1;
|
|
28516
|
+
else if (reentry !== void 0 && reentry.reason !== "wake" && contract === "unmet") barrenReentries += 1;
|
|
28517
|
+
const wait = run.wait;
|
|
28518
|
+
if (wait !== void 0 && contract !== "met" && !(continuation?.closed() ?? false) && !run.signal.aborted && budgetStop(run.budget(), now()) === void 0 && wait.open()) {
|
|
28519
|
+
const woken = await wait.wake(attempt + 1);
|
|
28520
|
+
if (woken !== void 0 && !run.signal.aborted) {
|
|
28521
|
+
wakes += 1;
|
|
28522
|
+
await emit({
|
|
28523
|
+
attempt,
|
|
28524
|
+
durationMs,
|
|
28525
|
+
madeProgress: progressed,
|
|
28526
|
+
...contractField,
|
|
28527
|
+
waitedMs: woken.idleMs,
|
|
28528
|
+
retryInMs: 0
|
|
28529
|
+
});
|
|
28530
|
+
reentry = {
|
|
28531
|
+
reason: "wake",
|
|
28532
|
+
input: woken.input,
|
|
28533
|
+
wake: wakes
|
|
28534
|
+
};
|
|
28535
|
+
continue;
|
|
28536
|
+
}
|
|
28537
|
+
}
|
|
28168
28538
|
if (contract === "unmet" && continuation !== void 0) {
|
|
28169
28539
|
const decision = await decideContinuation(continuation, attempt, after);
|
|
28170
28540
|
if ("steer" in decision) {
|
|
@@ -28590,6 +28960,7 @@ function createSupervisor() {
|
|
|
28590
28960
|
task = input.task;
|
|
28591
28961
|
const rootAct = root.act.bind(root);
|
|
28592
28962
|
const rootDeliver = root.deliver?.bind(root);
|
|
28963
|
+
const rootResultAccepted = root.resultAccepted?.bind(root);
|
|
28593
28964
|
const now = opts.now ?? Date.now;
|
|
28594
28965
|
assertRootIdentity(opts);
|
|
28595
28966
|
const rootLease = attached?.acquire();
|
|
@@ -28711,10 +29082,19 @@ function createSupervisor() {
|
|
|
28711
29082
|
});
|
|
28712
29083
|
let deadlineExceeded = false;
|
|
28713
29084
|
const rootDeadlineAtMs = pool.readout().deadlineMs;
|
|
28714
|
-
|
|
28715
|
-
const
|
|
29085
|
+
let clearAcceptedGrace;
|
|
29086
|
+
const reachRootDeadline = () => {
|
|
29087
|
+
if (clearAcceptedGrace !== void 0) return;
|
|
29088
|
+
if (rootResultAccepted?.() === true) {
|
|
29089
|
+
clearAcceptedGrace = armDeadlineTimer(ACCEPTED_RESULT_GRACE_MS, () => {
|
|
29090
|
+
deadlineExceeded = cascadeAbort(ROOT_DEADLINE_REASON);
|
|
29091
|
+
});
|
|
29092
|
+
return;
|
|
29093
|
+
}
|
|
28716
29094
|
deadlineExceeded = cascadeAbort(ROOT_DEADLINE_REASON);
|
|
28717
|
-
}
|
|
29095
|
+
};
|
|
29096
|
+
if (rootDeadlineAtMs > 0 && now() >= rootDeadlineAtMs) reachRootDeadline();
|
|
29097
|
+
const clearRootDeadline = opts.budget.deadlineMs === void 0 ? void 0 : armDeadlineTimer(Math.max(0, rootDeadlineAtMs - now()), reachRootDeadline);
|
|
28718
29098
|
let actOutcome = {
|
|
28719
29099
|
ok: false,
|
|
28720
29100
|
error: new RuntimeRunStateError("supervisor: root execution did not start")
|
|
@@ -28741,9 +29121,11 @@ function createSupervisor() {
|
|
|
28741
29121
|
allChildrenDownAtSettle = allSpawnedChildrenDown(runTree(openScope));
|
|
28742
29122
|
if (!controller.signal.aborted && rootDeadlineAtMs > 0 && now() >= rootDeadlineAtMs) deadlineExceeded = true;
|
|
28743
29123
|
clearRootDeadline?.();
|
|
29124
|
+
clearAcceptedGrace?.();
|
|
28744
29125
|
const settleGraceMs = !controller.signal.aborted ? boundedSettleGrace(opts.childSettleGraceMs, rootDeadlineAtMs, now) : 0;
|
|
28745
29126
|
try {
|
|
28746
29127
|
teardownUnconfirmed = await drainLiveChildren(openScope, controller, settleGraceMs);
|
|
29128
|
+
await settleManagerWork(openScope);
|
|
28747
29129
|
if (!persistence.failed && retainedAtSettlement === "release") teardownUnconfirmed = await releaseRetainedEnvironments(openScope);
|
|
28748
29130
|
const confirmWindowMs = opts.teardownConfirmMs ?? DEFAULT_TEARDOWN_CONFIRM_MS;
|
|
28749
29131
|
const releasing = !persistence.failed && retainedAtSettlement === "release";
|
|
@@ -29315,6 +29697,6 @@ function isNonEmptySpend(s) {
|
|
|
29315
29697
|
return s.iterations > 0 || s.tokens.input > 0 || s.tokens.output > 0 || s.usd > 0 || s.ms > 0 || s.tokensKnown === false || s.usdKnown === false || Object.values(s.resources ?? {}).some((resource) => resource.amount > 0 || !resource.known);
|
|
29316
29698
|
}
|
|
29317
29699
|
//#endregion
|
|
29318
|
-
export {
|
|
29700
|
+
export { bindScopeRetainedOwnerEnvironmentId as $, executableAgentProfileSnapshot as $i, parseWorkerToolTraceArtifact as $n, sanitizeAgentRuntimeEvent as $r, claimsAuthority as $t, driverExecutorFactory as A, withTimeout as Aa, worktreeCliProfileMaterialization as Ai, resolveAgentEnvironmentProvider as An, resolveHarnessTranscriptCapture as Ar, cliInPlaceExecutor as At, recordScopeOwnerDriverAttempt as B, teardownExecutor as Ba, knownExecutionBindingReceipt as Bi, InMemoryResultBlobStore as Bn, buildLoopOtelSpans as Br, WORKER_TRACE_PROPAGATION as Bt, createContinuationKeeper as C, promptCacheTokenClasses as Ca, promptOnlyProfileMaterialization as Ci, readPromptOptions as Cn, abortError as Cr, recoverRetainedInteractiveRun as Ct, passedItems as D, throwAbort as Da, sandboxActProfileMaterialization as Di, createAgentEnvironmentProviderRegistry as Dn, harnessTranscriptArtifact as Dr, rollingDispatch as Dt, failedItems as E, stringifySafe as Ea, renderUnsupported as Ei, LEAF_CONTINUATION_TASK as En, captureHarnessTranscript as Er, queueOf as Et, beginScopeOwnerAttempt as F, decodeHarnessUsage as Fa, attestRuntimeOwnedPendingExecutor as Fi, sandboxSessionTraceSource as Fn, readTraceContextFromEnv as Fr, createWorktreeCliExecutor as Ft, settledToIteration as G, runtimeOwnedDriveHarnessProviderEvidence as Gi, insideCursorNamespace as Gn, flatOtelSpan as Gr, taskToPrompt as Gt, recordScopeOwnerPause as H, promptFromAgentTurnInput as Ha, newExecutionAttemptId as Hi, SpawnEventIndex as Hn, buildRuntimeEventOtelSpans as Hr, workerTraceEnv as Ht, createScope as I, abortError$2 as Ia, attestRuntimeOwnedScopeOwner as Ii, registerRetainedExecutorPreparation as In, traceContextToEnv as Ir, DEFAULT_SANDBOX_STEERING_MAX_TURNS as It, pollFor as J, runtimeOwnedExecutorProviderEvidence as Ji, pendingWaits as Jn, padSpanId as Jr, readWorkerProgress as Jt, createWaitProbes as K, runtimeOwnedExecutorExecutionBinding as Ki, loadSpawnForest as Kn, generateSpanId as Kr, DEFAULT_STALL_AFTER_MS as Kt, deriveNodeExecutionIdentity as L, awaitAbortable$1 as La, authoredProfileDigest as Li, retainedExecutorSeamKey as Ln, defaultRedactor as Lr, createSteerableSandboxSession as Lt, withDriverExecutor as M, addResourceSpend as Ma, prepareJsonlAppend as Mi, unavailableSignalOfFailure as Mn, contentAddress as Mr, createExecutor as Mt, SUBTREE_RESULT_LIMIT as N, resourceTelemetry as Na, readCommittedJsonLines as Ni, createPushTraceSource as Nn, createPropagatingTraceEmitter as Nr, createExecutorRegistry as Nt, verdictFromJudgeScore as O, throwIfAborted as Oa, unsupportedProfileDimensions as Oi, providerAsExecutor as On, persistHarnessTranscript as Or, bindReusableExecutorExecutionId as Ot, assertRecursiveReservationPolicy as P, withBudgetResources as Pa, writeAllBytes as Pi, decodeToolPart as Pn, mergeTraceEnv as Pr, snapshotExecutorConfig as Pt, beginScopeRetainedOwnerDrive as Q, unknownMaterializationReceipt as Qi, isTraceAnalysisStore as Qn, createRuntimeStreamEventCollector as Qr, PEER_MAIL_WIRE_KEY as Qt, meterRuntimeOwnedAccounting as R, DEFAULT_SUCCESSFUL_SHUTDOWN_MS as Ra, finalizeRuntimeOwnedPendingExecutor as Ri, FileResultBlobStore as Rn, defaultRedactorIdentityMaterial as Rr, createRouterTranscript as Rt, composeContinuationNote as S, isAbortError$2 as Sa, promptModelProfileMaterialization as Si, assertBoxlessPromptOptions as Sn, RunCancellationReason as Sr, reconnectRetainedInteractiveRun as St, expandQuestions as T, sleep as Ta, renderProfileMaterializationIssues as Ti, runBrainLoop as Tn, runAbortable as Tr, freeSlots as Tt, restoreScopeOwnerAcceptedExecution as U, promptOptionsFromAgentTurnInput as Ua, providerAttemptEvidence as Ui, assertContentAddress as Un, createOpenInferenceFileExporter as Ur, workerTraceHeaders as Ut, recordScopeOwnerMaterialization as V, teardownSurfaces as Va, knownMaterializationReceipt as Vi, InMemorySpawnJournal as Vn, buildLoopSpanNodes as Vr, readWorkerTraceContext as Vt, scopeOwnerExecutorNodeContext as W, providerMessageText as Wa, recordRuntimeOwnedDriveHarnessProviderEvidence as Wi, encodeResultBlob as Wn, createOtelExporter as Wr, workerTraceSeamKey as Wt, validateWaitSpec as X, runtimeOwnedScopeOwnerRuntime as Xi, WORKER_TOOL_TRACE_SCHEMA_VERSION as Xn, toOtelAttributes as Xr, AUTHORITY_MARKERS as Xt, timerAt as Y, runtimeOwnedPendingExecutorMaterialization as Yi, replaySpawnTree as Yn, padTraceId as Yr, createInbox as Yt, waitUntil as Z, unknownExecutionBindingReceipt as Zi, captureWorkerTraceEvidence as Zn, createRuntimeEventCollector as Zr, DEFAULT_PEER_MAIL_LIMITS as Zt, CheckUnavailableError as _, addSpend as _a, controlProfileMaterialization as _i, createSandboxLineage as _n, retainedCreateMaterial as _r, workerInteractiveAdmissionFile as _t, collectDelivered as a, assertSandboxServedModel as aa, createWorktree as ai, isTerminalNodeStatus as an, createBudgetPool as ar, scopeRetainedOwnerContext as at, bestComposite as b, deleteBoxSafe as ba, profileMaterializationAxes$1 as bi, SandboxEvidenceRetentionError as bn, createWorkerSlots as br, workerInteractiveBindingFile as bt, runTree as c, createSandboxUsageLedger as ca, LOCAL_HARNESSES as ci, addHarnessUsage as cn, spendFromUsageEvents as cr, scopeRetainedOwnerRestorePoint as ct, classifyDriverFailure as d, mapSandboxEvent as da, localHarnessExecutable as di, readCodexRolloutSession as dn, bridgeStopSignalKey as dr, SPAWN_RESOURCE_PATH_MAX_BYTES as dt, executableAgentSpecSnapshot as ea, sanitizeKnowledgeReadinessReport as ei, createPeerMailbox as en, workerTraceAnalysisStore as er, bindScopeRetainedOwnerProvider as et, runDriverWithRetry as f, mapSandboxToolEvent as fa, parseCodexTokenUsage as fi, TERMINAL_DECISIONS as fn, errMessage as fr, environmentReader as ft, CONTINUATION_FACTS as g, sumSandboxUsage as ga, assertProfileMaterialization as gi, runAgentRounds as gn, startRetainedRunInEnvironment as gr, readWorkerInteractiveAdmissions as gt, CONTINUATIONS_DIR as h, sandboxProgressEvents as ha, AGENT_PROFILE_MATERIALIZATION_AXES as hi, isTerminalDecision as hn, startRetainedRun as hr, interactiveAdmissionSeamKey as ht, bestDelivered as i, readSandboxOutcome as ia, captureWorktreeDiff as ii, isLiveNodeStatus as in, assertValidBudget as ir, reconcileScopeRetainedOwnerEnvironment as it, isDriverSpec as j, zeroSpend as ja, isNoEntError as ji, unavailablePauseMs as jn, retainHarnessTranscript as jr, cliWorktreeExecutor as jt, driverChild as k, unmeteredSpend as ka, validateProfileMaterialization as ki, providerAsSandboxClient as kn, readHarnessTranscript as kr, captureReusableExecutorConfig as kt, DriverAttemptsExhaustedError as l, extractLlmCallEvent as la, harnessInvocation as li, createCodexRolloutStoreReader as ln, spendFromUsageTotals as lr, scopeRetainedOwnerResult as lt, upstreamUnavailableSignal as m, sandboxEventServedBackend as ma, terminateProcessTreeAndConfirm as mi, defaultSelectWinner as mn, recoverRetainedRun as mr, resolveSpawnResourcePaths as mt, createRootHandle as n, detachedSnapshot as na, runSettledCommand as ni, peerMailTools as nn, BudgetReconcileFault as nr, noteScopeRetainedOwnerCoordination as nt, pickBestDelivered as o, canonicalStreamEventFromSandboxEvent as oa, removeWorktree as oi, bridgeAdmissionRefusal as on, meterUsageEvent as or, scopeRetainedOwnerPriorSpend as ot, summarizeDriverAttempts as p, notifySandboxEventObserver as pa, CodexExecutionDiagnosticError as pi, createSandboxForSpec as pn, reconnectRetainedRun as pr, hostDirectoryReader as pt, isWaitOutcome as q, runtimeOwnedExecutorMaterialization as qi, materializeTreeView as qn, loopEventToOtelSpan as qr, createActivityLog as qt, createSupervisor as r, projectSandboxOutcome as ra, runWorktreeHarness as ri, peerMailVerbNames as rn, ReservationWaitRefused as rr, prepareScopeRetainedOwnerTask as rt, runFinalizer as s, createSandboxToolPartState as sa, DEFAULT_LOCAL_HARNESS as si, bridgeModelRouteRefusal as sn, newUsageTotals as sr, scopeRetainedOwnerResourceReader as st, DEFAULT_MAX_DEPTH as t, detachedFrozen as ta, sanitizeRuntimeStreamEvent as ti, isPeerMailEnvelope as tn, executorFailure as tr, consumeScopeRetainedOwnerResult as tt, HarnessTurnFailedError as u, isSandboxTerminalEvent as ua, harnessSupportsReasoningEffort as ui, harnessUsageIsEmpty as un, bridgeRuntimeAttachmentsKey as ur, scopeRetainedOwnerTurnEnded as ut, admitContinuationPolicy as v, chargedTokens as va, defineProfileMaterializationContract as vi, probeSandboxCapabilities as vn, destroyInteractiveEnvironment as vr, attachWorker as vt, distillFindings as w, randomSuffix as wa, promptResourceProfileMaterialization as wi, routerBrain as wn, linkAbort as wr, startRetainedInteractiveRun as wt, checkVerdictOf as x, hasCompleteCacheBreakdown as xa, promptControlProfileMaterialization as xi, captureBeforeDestroy as xn, openSlotGroup as xr, workerInteractiveBindingsDir as xt, admitFinding as y, cloneSpend as ya, fullProfileMaterialization as yi, acquireSandbox as yn, environmentGone as yr, readWorkerInteractiveBinding as yt, meterRuntimeOwnedProviderAttempt as z, armDeadlineTimer as za, inheritRuntimeOwnedExecutorAttestation as zi, FileSpawnJournal as zn, resolveRedactor as zr, createInPlaceCliExecutor as zt };
|
|
29319
29701
|
|
|
29320
|
-
//# sourceMappingURL=supervisor-
|
|
29702
|
+
//# sourceMappingURL=supervisor-DA_nvF-h.js.map
|