@tangle-network/agent-runtime 0.344.0 → 0.349.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-C5rFWXGj.js → activation-tNGW73Y9.js} +4 -4
- package/dist/{activation-C5rFWXGj.js.map → activation-tNGW73Y9.js.map} +1 -1
- package/dist/{activation-CGtGr0qu.d.ts → activation-wBipBkCf.d.ts} +2 -2
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -3
- package/dist/{bundle-DKQtOO9d.js → bundle-1xaJEgjq.js} +2 -2
- package/dist/{bundle-DKQtOO9d.js.map → bundle-1xaJEgjq.js.map} +1 -1
- package/dist/candidate-execution/index.js +4 -4
- package/dist/{coordination-manager-T98ZbsEt.js → coordination-manager-B2Z_MmL9.js} +22 -19
- package/dist/coordination-manager-B2Z_MmL9.js.map +1 -0
- package/dist/{delegate-CjdtLf1v.js → delegate-Dr-63jFl.js} +2 -2
- package/dist/{delegate-CjdtLf1v.js.map → delegate-Dr-63jFl.js.map} +1 -1
- package/dist/durable.d.ts +7 -2
- package/dist/durable.js +129 -117
- package/dist/durable.js.map +1 -1
- package/dist/{graph-kgzTaNMA.js → graph-DPejYB3C.js} +6 -5
- package/dist/graph-DPejYB3C.js.map +1 -0
- package/dist/{improve-DevAd83a.js → improve-DwSahPi1.js} +7 -7
- package/dist/{improve-DevAd83a.js.map → improve-DwSahPi1.js.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +9 -9
- package/dist/intelligence.d.ts +2 -2
- package/dist/intelligence.js +6 -6
- package/dist/kernel.d.ts +2 -2
- package/dist/kernel.js +11 -11
- package/dist/{loop-runner-DsVqEv8O.d.ts → loop-runner-C6pGq-2l.d.ts} +2 -2
- package/dist/{loop-runner-BM509Zmp.js → loop-runner-CP6MfO1b.js} +2 -2
- package/dist/{loop-runner-BM509Zmp.js.map → loop-runner-CP6MfO1b.js.map} +1 -1
- 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 +1 -1
- package/dist/mcp/index.js +6 -6
- package/dist/mcp/index.js.map +1 -1
- package/dist/model-policy-CyCUwHed.js.map +1 -1
- package/dist/{prepare-TEEHSJwq.js → prepare-B9wWffjO.js} +3 -3
- package/dist/{prepare-TEEHSJwq.js.map → prepare-B9wWffjO.js.map} +1 -1
- package/dist/{profile-6OLpbjvV.js → profile-JLJd2wFG.js} +2 -2
- package/dist/{profile-6OLpbjvV.js.map → profile-JLJd2wFG.js.map} +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{provision-supervisor-CysVhSqV.js → provision-supervisor-C4v2vqDo.js} +6 -6
- package/dist/{provision-supervisor-CysVhSqV.js.map → provision-supervisor-C4v2vqDo.js.map} +1 -1
- package/dist/{durable-file-DLcrzrjL.js → record-events-D93DkpAx.js} +100 -3
- package/dist/record-events-D93DkpAx.js.map +1 -0
- package/dist/{run-cancellation-CEDiqfhC.js → run-cancellation-CzFhQGMa.js} +11 -9
- package/dist/run-cancellation-CzFhQGMa.js.map +1 -0
- package/dist/{runtime-B_93oWEv.js → runtime-CsvGCQpl.js} +448 -55
- package/dist/runtime-CsvGCQpl.js.map +1 -0
- package/dist/{sandbox-profile-compat-_fEtHPCj.js → sandbox-profile-compat-DtuJWFrM.js} +2 -2
- package/dist/sandbox-profile-compat-DtuJWFrM.js.map +1 -0
- package/dist/{search-executor-t05_9Wwk.js → search-executor-CCb82Umc.js} +5 -5
- package/dist/search-executor-CCb82Umc.js.map +1 -0
- package/dist/{server-DjrVWzH2.js → server-CKPwZU-I.js} +4 -4
- package/dist/{server-DjrVWzH2.js.map → server-CKPwZU-I.js.map} +1 -1
- package/dist/{structural-rollout-CpJknIaL.js → structural-rollout-DylC_fwU.js} +3 -3
- package/dist/{structural-rollout-CpJknIaL.js.map → structural-rollout-DylC_fwU.js.map} +1 -1
- package/dist/{supervise-BuVVC7Bl.js → supervise-BGfm2GlY.js} +293 -87
- package/dist/supervise-BGfm2GlY.js.map +1 -0
- package/dist/{supervisor-D3M9ab1v.js → supervisor-wS9Ehz_x.js} +454 -187
- package/dist/supervisor-wS9Ehz_x.js.map +1 -0
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +13 -13
- package/dist/{top-snapshot-BGYI6G6K.js → top-snapshot-CflmaDgk.js} +6 -4
- package/dist/top-snapshot-CflmaDgk.js.map +1 -0
- package/dist/tui/bin.js +2 -2
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +2 -2
- package/dist/{types-DztCeYd6.d.ts → types-C8BGOCBn.d.ts} +286 -34
- package/package.json +11 -11
- package/skills/agent-graphs/SKILL.md +40 -2
- package/skills/graph-designer/SKILL.md +6 -0
- package/skills/profile-authoring/SKILL.md +1 -1
- package/dist/coordination-manager-T98ZbsEt.js.map +0 -1
- package/dist/durable-file-DLcrzrjL.js.map +0 -1
- package/dist/graph-kgzTaNMA.js.map +0 -1
- package/dist/run-cancellation-CEDiqfhC.js.map +0 -1
- package/dist/runtime-B_93oWEv.js.map +0 -1
- package/dist/sandbox-profile-compat-_fEtHPCj.js.map +0 -1
- package/dist/search-executor-t05_9Wwk.js.map +0 -1
- package/dist/supervise-BuVVC7Bl.js.map +0 -1
- package/dist/supervisor-D3M9ab1v.js.map +0 -1
- package/dist/top-snapshot-BGYI6G6K.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as publishExclusiveDurableFile, c as captureRunWriteContext, l as fenceRunWrite, p as sha256, r as assertNoSymlinkDescendant, s as writeAtomicDurableFile, t as spawnJournalRecordEvents } from "./record-events-D93DkpAx.js";
|
|
2
2
|
import { c as RetainedInteractiveAdmissionError, d as RetainedRunDispatchBindingError, f as RuntimeRunStateError, i as ConfigError, l as RetainedInteractiveBindingError, m as ValidationError$1, r as BackendTransportError, t as AgentEvalError$1, u as RetainedRunAdmissionError } from "./errors-DodWX-cb.js";
|
|
3
|
-
import { $ as isAbortError$1, B as sha256Bytes$1, Ct as armDeadlineTimer, Dt as singleFlightTeardown, Et as isDeadlineAbortReason, G as addTokenUsage, H as hasControlCharacter, I as deepFreezeCandidate, J as cloneTokenUsage, K as chargedTokens, M as verifyWorkspaceSnapshotArtifacts, Ot as teardownExecutor, Q as hasCompleteCacheBreakdown, St as ROOT_DEADLINE_REASON, Tt as checkInIdleMs, U as abortError, W as addSpend, X as errorMessage, Y as deleteBoxSafe, Z as fnv1a32Hex, _t as withBudgetResources, at as roundBoxMinutes, c as verifyAgentCandidateWorkspaceTree, ct as throwAbort, dt as withTimeout, et as isAsyncIterable, ft as zeroSpend, g as verifiedArtifactChunks, gt as resourceTelemetry, ht as assertResources, it as randomUuid, kt as teardownSurfaces, lt as throwIfAborted, mt as addResourceSpend, nt as promptCacheTokenClasses, o as readAgentCandidateWorkspaceArtifactFiles, ot as sleep, pt as zeroTokenUsage, q as cloneSpend, rt as randomSuffix, s as verifyAgentCandidateWorkspaceArtifacts, st as stringifySafe, t as assertSandboxProfileCompatibility, tt as mapWithConcurrency, ut as unmeteredSpend, v as verifyAgentCandidateWorkspaceArchive, vt as ACCEPTED_RESULT_GRACE_MS, wt as boundedChildDeadlineAt, yt as CHILD_DEADLINE_REASON } from "./sandbox-profile-compat-
|
|
3
|
+
import { $ as isAbortError$1, B as sha256Bytes$1, Ct as armDeadlineTimer, Dt as singleFlightTeardown, Et as isDeadlineAbortReason, G as addTokenUsage, H as hasControlCharacter, I as deepFreezeCandidate, J as cloneTokenUsage, K as chargedTokens, M as verifyWorkspaceSnapshotArtifacts, Ot as teardownExecutor, Q as hasCompleteCacheBreakdown, St as ROOT_DEADLINE_REASON, Tt as checkInIdleMs, U as abortError, W as addSpend, X as errorMessage, Y as deleteBoxSafe, Z as fnv1a32Hex, _t as withBudgetResources, at as roundBoxMinutes, c as verifyAgentCandidateWorkspaceTree, ct as throwAbort, dt as withTimeout, et as isAsyncIterable, ft as zeroSpend, g as verifiedArtifactChunks, gt as resourceTelemetry, ht as assertResources, it as randomUuid, kt as teardownSurfaces, lt as throwIfAborted, mt as addResourceSpend, nt as promptCacheTokenClasses, o as readAgentCandidateWorkspaceArtifactFiles, ot as sleep, pt as zeroTokenUsage, q as cloneSpend, rt as randomSuffix, s as verifyAgentCandidateWorkspaceArtifacts, st as stringifySafe, t as assertSandboxProfileCompatibility, tt as mapWithConcurrency, ut as unmeteredSpend, v as verifyAgentCandidateWorkspaceArchive, vt as ACCEPTED_RESULT_GRACE_MS, wt as boundedChildDeadlineAt, yt as CHILD_DEADLINE_REASON } from "./sandbox-profile-compat-DtuJWFrM.js";
|
|
4
4
|
import { runTaskQueue } from "./task-queue.js";
|
|
5
5
|
import { _ as agentHarness, a as concreteProfileModel, c as profileModelExecutionSettings, d as assertRouterAutoDeclaration, f as assertRouterAutoResponse, g as observedModelMatchesDeclared, h as observedModelHasSnapshot, l as profileProviderModel, m as mergeObservedModelIdentity, o as enforceTokenLimits, s as profileBridgeWireModel, t as assertExecutableAgentProfile, u as resolveRouterRetryPolicy } from "./model-policy-CyCUwHed.js";
|
|
6
6
|
import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
|
|
@@ -13,7 +13,7 @@ import { REDACTION_VERSION as REDACTION_VERSION$1, redact } from "@tangle-networ
|
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
15
15
|
import { LedgerCanonicalizationError, canonicalString, jsonDocument, merkleLeafHash, merkleRoot, merkleSalt } from "@tangle-network/agent-eval/ledger-core";
|
|
16
|
-
import { appendFileSync, closeSync, constants, createReadStream, existsSync, mkdirSync, openSync, readFileSync } from "node:fs";
|
|
16
|
+
import { appendFileSync, closeSync, constants, createReadStream, existsSync, fstatSync, fsyncSync, ftruncateSync, mkdirSync, openSync, readFileSync, readSync, statSync, writeSync } from "node:fs";
|
|
17
17
|
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep, win32 } from "node:path";
|
|
18
18
|
import { spawn } from "node:child_process";
|
|
19
19
|
import { access, chmod, copyFile, mkdir, mkdtemp, open, readFile, readdir, realpath, rm, rmdir, stat, symlink, writeFile } from "node:fs/promises";
|
|
@@ -23,6 +23,7 @@ import { homedir, hostname, tmpdir } from "node:os";
|
|
|
23
23
|
import { request } from "node:http";
|
|
24
24
|
import { request as request$1 } from "node:https";
|
|
25
25
|
import { Readable } from "node:stream";
|
|
26
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
26
27
|
import { ATTR, deriveHexId, isW3CSpanId, isW3CTraceId } from "@tangle-network/agent-trace-contract";
|
|
27
28
|
import { clearImmediate, setImmediate as setImmediate$1 } from "node:timers";
|
|
28
29
|
//#region src/runtime/turn-input.ts
|
|
@@ -508,7 +509,7 @@ function sandboxEventServedBackend(event) {
|
|
|
508
509
|
/**
|
|
509
510
|
* Fail the execution when the platform reports serving a model other than the exact one asked for.
|
|
510
511
|
*
|
|
511
|
-
* Measured motive (agent-runtime#892, live infrastructure
|
|
512
|
+
* Measured motive (agent-runtime#892, live infrastructure): 6 of 6 boxes whose profile
|
|
512
513
|
* declared `zai-coding-plan/glm-5.2` reported
|
|
513
514
|
* `{"provider":"openai-compat","model":"deepseek/deepseek-v4-flash","source":"environment"}`,
|
|
514
515
|
* while the materialization receipt recorded the declared model as `status: "known"`. Sending
|
|
@@ -3164,7 +3165,7 @@ function leafContinuationExecutionId(nodeId, inputSeq) {
|
|
|
3164
3165
|
return `${nodeId}:input:${inputSeq}`;
|
|
3165
3166
|
}
|
|
3166
3167
|
const retainedPreparations = /* @__PURE__ */ new WeakMap();
|
|
3167
|
-
/** Reconstruct an admitted
|
|
3168
|
+
/** Reconstruct an admitted worker through its original composition boundary. @internal */
|
|
3168
3169
|
function registerRetainedExecutorPreparation(factory, prepare) {
|
|
3169
3170
|
retainedPreparations.set(factory, prepare);
|
|
3170
3171
|
return factory;
|
|
@@ -4235,8 +4236,8 @@ const CODEX_PERMISSION_PROFILE = "agent_runtime_reproducible";
|
|
|
4235
4236
|
* Default per-harness command + arg shape. `buildArgs` takes ONLY the task prompt and
|
|
4236
4237
|
* emits the prompt-only invocation (no model, no system prompt) — the safe default shape
|
|
4237
4238
|
* the in-process executor's `streamPrompt` drives. `modelArgs` maps a resolved model to
|
|
4238
|
-
* the harness's selector flag, which each harness spells for itself: codex and
|
|
4239
|
-
* take `-m <model>`, claude-code and pi take `--model <model>`. The §1.5
|
|
4239
|
+
* the harness's selector flag, which each harness spells for itself: codex, kimi-code and
|
|
4240
|
+
* opencode take `-m <model>`, claude-code and pi take `--model <model>`. The §1.5
|
|
4240
4241
|
* profile-aware mapper `harnessInvocation` composes these to thread the full
|
|
4241
4242
|
* supervisor-authored profile (systemPrompt + model) into argv.
|
|
4242
4243
|
*
|
|
@@ -4259,7 +4260,8 @@ const HARNESS_INVOCATIONS = {
|
|
|
4259
4260
|
},
|
|
4260
4261
|
args: (level) => ["--effort", level]
|
|
4261
4262
|
},
|
|
4262
|
-
permissionBypassArgs: () => ["--dangerously-skip-permissions"]
|
|
4263
|
+
permissionBypassArgs: () => ["--dangerously-skip-permissions"],
|
|
4264
|
+
profileMcp: true
|
|
4263
4265
|
},
|
|
4264
4266
|
codex: {
|
|
4265
4267
|
command: "codex",
|
|
@@ -4283,7 +4285,8 @@ const HARNESS_INVOCATIONS = {
|
|
|
4283
4285
|
"-c",
|
|
4284
4286
|
"approval_policy=\"never\""
|
|
4285
4287
|
],
|
|
4286
|
-
fullAccessArgs: () => ["--dangerously-bypass-approvals-and-sandbox"]
|
|
4288
|
+
fullAccessArgs: () => ["--dangerously-bypass-approvals-and-sandbox"],
|
|
4289
|
+
profileMcp: true
|
|
4287
4290
|
},
|
|
4288
4291
|
opencode: {
|
|
4289
4292
|
command: "opencode",
|
|
@@ -4300,7 +4303,8 @@ const HARNESS_INVOCATIONS = {
|
|
|
4300
4303
|
},
|
|
4301
4304
|
args: (level) => ["--variant", level]
|
|
4302
4305
|
},
|
|
4303
|
-
permissionBypassArgs: () => ["--auto"]
|
|
4306
|
+
permissionBypassArgs: () => ["--auto"],
|
|
4307
|
+
profileMcp: true
|
|
4304
4308
|
},
|
|
4305
4309
|
pi: {
|
|
4306
4310
|
command: "pi",
|
|
@@ -4317,7 +4321,14 @@ const HARNESS_INVOCATIONS = {
|
|
|
4317
4321
|
},
|
|
4318
4322
|
args: (level) => ["--thinking", level]
|
|
4319
4323
|
},
|
|
4320
|
-
permissionBypassArgs: () => ["--approve"]
|
|
4324
|
+
permissionBypassArgs: () => ["--approve"],
|
|
4325
|
+
profileMcp: true
|
|
4326
|
+
},
|
|
4327
|
+
"kimi-code": {
|
|
4328
|
+
command: "kimi",
|
|
4329
|
+
buildArgs: (taskPrompt) => ["-p", taskPrompt],
|
|
4330
|
+
modelArgs: (model) => ["-m", model],
|
|
4331
|
+
profileMcp: true
|
|
4321
4332
|
}
|
|
4322
4333
|
};
|
|
4323
4334
|
/** Every local harness, in table order — the one list `AGENT_RUNTIME_LOCAL_HARNESSES` and any
|
|
@@ -4331,6 +4342,15 @@ const LOCAL_HARNESSES = Object.keys(HARNESS_INVOCATIONS);
|
|
|
4331
4342
|
function harnessSupportsReasoningEffort(harness, reasoningEffort) {
|
|
4332
4343
|
return HARNESS_INVOCATIONS[harness].reasoning?.levels[reasoningEffort] !== void 0;
|
|
4333
4344
|
}
|
|
4345
|
+
/**
|
|
4346
|
+
* Whether a profile's MCP servers reach this harness on the local-harness path — the row's
|
|
4347
|
+
* `profileMcp` claim that the shared materializer's plan names a config surface the installed
|
|
4348
|
+
* CLI reads. Admission checks read this so a profile the spawn would silently disarm is
|
|
4349
|
+
* rejected BEFORE any workspace state is created, against the same table that emits the argv.
|
|
4350
|
+
*/
|
|
4351
|
+
function harnessMaterializesProfileMcp(harness) {
|
|
4352
|
+
return HARNESS_INVOCATIONS[harness].profileMcp === true;
|
|
4353
|
+
}
|
|
4334
4354
|
function harnessReasoningArgs(harness, reasoningEffort) {
|
|
4335
4355
|
const reasoning = HARNESS_INVOCATIONS[harness].reasoning;
|
|
4336
4356
|
const level = reasoning?.levels[reasoningEffort];
|
|
@@ -4399,6 +4419,7 @@ function harnessProfileModel(harness, profile) {
|
|
|
4399
4419
|
const provider = profile.model?.provider?.trim();
|
|
4400
4420
|
if (!provider) return model;
|
|
4401
4421
|
if (harness === "opencode") return model.includes("/") ? model : `${provider}/${model}`;
|
|
4422
|
+
if (harness === "kimi-code") return model;
|
|
4402
4423
|
const nativeProvider = harness === "codex" ? "openai" : "anthropic";
|
|
4403
4424
|
if (provider !== nativeProvider) throw new Error(`harnessInvocation: ${harness} cannot materialize model provider ${JSON.stringify(provider)}; expected ${nativeProvider}`);
|
|
4404
4425
|
return model;
|
|
@@ -5377,7 +5398,7 @@ async function runLocalHarness(options) {
|
|
|
5377
5398
|
*
|
|
5378
5399
|
* Git worktree helpers for the in-process delegation executor. Each
|
|
5379
5400
|
* delegation runs in its own worktree so multiple parallel harness
|
|
5380
|
-
* subprocesses (claude / codex / opencode in
|
|
5401
|
+
* subprocesses (claude / codex / opencode / pi / kimi-code in an N-way fanout) don't clobber
|
|
5381
5402
|
* each other's edits on the shared workspace.
|
|
5382
5403
|
*
|
|
5383
5404
|
* Worktrees live under `<repoRoot>/.agent-worktrees/<runId>/`. After the
|
|
@@ -5534,7 +5555,7 @@ async function removeWorktree(options) {
|
|
|
5534
5555
|
/**
|
|
5535
5556
|
*
|
|
5536
5557
|
* The ONE worktree-harness execution core. The physical act — run a supervisor-authored
|
|
5537
|
-
* `AgentProfile` on a local coding-harness CLI (claude / codex / opencode) against a fresh git
|
|
5558
|
+
* `AgentProfile` on a local coding-harness CLI (claude / codex / opencode / pi / kimi-code) against a fresh git
|
|
5538
5559
|
* worktree off `repoRoot`, capture the diff, derive the test/typecheck PASS signals, then clean
|
|
5539
5560
|
* up — lives here ONCE. Two executors adapt it to two ports without re-implementing it:
|
|
5540
5561
|
* - `createWorktreeCliExecutor` — the `Scope`/`Supervisor` leaf `Executor`.
|
|
@@ -5871,6 +5892,7 @@ function assertSupportedWorktreeProfile(profile, harness) {
|
|
|
5871
5892
|
const unsupportedAxes = [];
|
|
5872
5893
|
const reasoningEffort = profile.model?.reasoningEffort;
|
|
5873
5894
|
if (reasoningEffort !== void 0 && !harnessSupportsReasoningEffort(harness, reasoningEffort)) unsupportedAxes.push("model.reasoningEffort");
|
|
5895
|
+
if (hasEnabledProfileMcpServer(profile) && !harnessMaterializesProfileMcp(harness)) unsupportedAxes.push("mcp");
|
|
5874
5896
|
if (unsupportedAxes.length > 0) throw new Error(`runWorktreeHarness: profile requests unsupported worktree behavior: ${unsupportedAxes.join(", ")}`);
|
|
5875
5897
|
}
|
|
5876
5898
|
function assertSafeMaterializedPaths(plan) {
|
|
@@ -5883,6 +5905,9 @@ function isGitMetadataSegment(segment) {
|
|
|
5883
5905
|
const windowsCanonical = segment.replace(/[ .]+$/u, "").toLowerCase();
|
|
5884
5906
|
return windowsCanonical === ".git" || windowsCanonical.startsWith(".git:");
|
|
5885
5907
|
}
|
|
5908
|
+
function hasEnabledProfileMcpServer(profile) {
|
|
5909
|
+
return Object.values(profile.mcp ?? {}).some((server) => server.enabled !== false);
|
|
5910
|
+
}
|
|
5886
5911
|
function profileMaterializationReceipt(applied, resourceInstructions) {
|
|
5887
5912
|
return {
|
|
5888
5913
|
workspacePlanDigest: applied.workspacePlanDigest,
|
|
@@ -8759,7 +8784,7 @@ function isFiniteNumber(value) {
|
|
|
8759
8784
|
* The continuation: what a manager with a completion check is told when its turn ends and the
|
|
8760
8785
|
* check is unmet, and the one rule that decides whether it is sent back.
|
|
8761
8786
|
*
|
|
8762
|
-
* Measured on discovery-lab before this module (
|
|
8787
|
+
* Measured on discovery-lab before this module (670 settled runs, 1,596 re-entries):
|
|
8763
8788
|
* 1,565 re-entries followed a failed turn and resent the original task, and 31 carried note text.
|
|
8764
8789
|
* The note Runtime wrote itself held seven fixed lines and no field for the check's verdict. Of 40
|
|
8765
8790
|
* episodes where the director ended on its own and the outside check disagreed, 33 were told
|
|
@@ -9037,9 +9062,9 @@ const CONTINUATIONS_DIR = "continuations";
|
|
|
9037
9062
|
async function writeContinuationFiles(dir, continuation, files) {
|
|
9038
9063
|
const at = join(dir, String(continuation));
|
|
9039
9064
|
await mkdir(at, { recursive: true });
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
if (files.panel !== void 0)
|
|
9065
|
+
writeAtomicDurableFile(join(at, "note.md"), `${files.note}\n`);
|
|
9066
|
+
writeAtomicDurableFile(join(at, "verdict.json"), `${JSON.stringify(files.verdict ?? null, null, 2)}\n`);
|
|
9067
|
+
if (files.panel !== void 0) writeAtomicDurableFile(join(at, "panel.jsonl"), files.panel.map((line) => JSON.stringify(line)).join("\n") + (files.panel.length ? "\n" : ""));
|
|
9043
9068
|
}
|
|
9044
9069
|
/** The best composite across `reads`, or `undefined` when no read scored. */
|
|
9045
9070
|
function bestComposite(reads) {
|
|
@@ -9249,19 +9274,53 @@ function createContinuationKeeper(input) {
|
|
|
9249
9274
|
* executor has produced its output. The inner `score` is preserved; only `valid` is gated.
|
|
9250
9275
|
*/
|
|
9251
9276
|
function gateOnDeliverable(inner, deliverable) {
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9277
|
+
return wrapCompletionGate(inner, (result) => checkDeliverable(deliverable, result));
|
|
9278
|
+
}
|
|
9279
|
+
/** Build a worker with the same check on durable acceptance and normal completion. @internal */
|
|
9280
|
+
function gateFactoryOnDeliverable(factory, deliverable) {
|
|
9281
|
+
return (spec, ctx) => {
|
|
9282
|
+
const retention = retainedExecutorContext(ctx);
|
|
9283
|
+
if (retention === void 0) return gateOnDeliverable(factory(spec, ctx), deliverable);
|
|
9284
|
+
const verdicts = /* @__PURE__ */ new WeakMap();
|
|
9285
|
+
const check = (result) => {
|
|
9286
|
+
let verdict = verdicts.get(result);
|
|
9287
|
+
if (verdict === void 0) {
|
|
9288
|
+
verdict = checkDeliverable(deliverable, result);
|
|
9289
|
+
verdicts.set(result, verdict);
|
|
9290
|
+
}
|
|
9291
|
+
return verdict;
|
|
9263
9292
|
};
|
|
9293
|
+
const checkedRetention = (source) => ({
|
|
9294
|
+
...source,
|
|
9295
|
+
onResult: async (result) => source.onResult({
|
|
9296
|
+
...result,
|
|
9297
|
+
verdict: await check(result)
|
|
9298
|
+
}),
|
|
9299
|
+
...source.continueInvocation === void 0 ? {} : { continueInvocation: async (task) => checkedRetention(await source.continueInvocation(task)) }
|
|
9300
|
+
});
|
|
9301
|
+
return wrapCompletionGate(factory(spec, {
|
|
9302
|
+
...ctx,
|
|
9303
|
+
seams: {
|
|
9304
|
+
...ctx.seams,
|
|
9305
|
+
[retainedExecutorSeamKey]: checkedRetention(retention)
|
|
9306
|
+
}
|
|
9307
|
+
}), check);
|
|
9308
|
+
};
|
|
9309
|
+
}
|
|
9310
|
+
async function checkDeliverable(deliverable, result) {
|
|
9311
|
+
let delivered;
|
|
9312
|
+
try {
|
|
9313
|
+
delivered = checkVerdictOf(await deliverable.check(result.out)).pass;
|
|
9314
|
+
} catch {
|
|
9315
|
+
delivered = false;
|
|
9316
|
+
}
|
|
9317
|
+
return {
|
|
9318
|
+
valid: delivered,
|
|
9319
|
+
score: result.verdict?.score ?? (delivered ? 1 : 0)
|
|
9264
9320
|
};
|
|
9321
|
+
}
|
|
9322
|
+
function wrapCompletionGate(inner, check) {
|
|
9323
|
+
let gated;
|
|
9265
9324
|
/**
|
|
9266
9325
|
* Ask the delivery question once, from whatever the inner executor managed to produce.
|
|
9267
9326
|
*
|
|
@@ -9275,7 +9334,7 @@ function gateOnDeliverable(inner, deliverable) {
|
|
|
9275
9334
|
} catch {
|
|
9276
9335
|
return;
|
|
9277
9336
|
}
|
|
9278
|
-
gated = await check(art
|
|
9337
|
+
gated = await check(art);
|
|
9279
9338
|
};
|
|
9280
9339
|
const gateExecution = (r) => {
|
|
9281
9340
|
if (isAsyncIterable(r)) return (async function* () {
|
|
@@ -9293,7 +9352,7 @@ function gateOnDeliverable(inner, deliverable) {
|
|
|
9293
9352
|
await settleVerdict();
|
|
9294
9353
|
throw error;
|
|
9295
9354
|
}
|
|
9296
|
-
gated = await check(res
|
|
9355
|
+
gated = await check(res);
|
|
9297
9356
|
return {
|
|
9298
9357
|
...res,
|
|
9299
9358
|
verdict: gated
|
|
@@ -9308,6 +9367,7 @@ function gateOnDeliverable(inner, deliverable) {
|
|
|
9308
9367
|
...inner.traceSource ? { traceSource: () => inner.traceSource?.() } : {},
|
|
9309
9368
|
...inner.metered ? { metered: () => inner.metered?.() } : {},
|
|
9310
9369
|
...inner.accounting ? { accounting: () => inner.accounting?.() } : {},
|
|
9370
|
+
...inner.resultAccepted ? { resultAccepted: () => inner.resultAccepted?.() === true } : {},
|
|
9311
9371
|
...inner.harnessTranscript ? { harnessTranscript: () => inner.harnessTranscript?.() } : {},
|
|
9312
9372
|
...inner.harnessTranscriptSettled ? { harnessTranscriptSettled: () => inner.harnessTranscriptSettled?.() ?? Promise.resolve() } : {},
|
|
9313
9373
|
execute: (task, signal) => gateExecution(inner.execute(task, signal)),
|
|
@@ -9674,8 +9734,7 @@ const DETERMINISTIC_BRIDGE_CODES = /* @__PURE__ */ new Set([
|
|
|
9674
9734
|
*
|
|
9675
9735
|
* A provider executor reports a failed turn as a returned outcome, not a thrown error, so without
|
|
9676
9736
|
* this error a failed turn reads as a completed drive and never reaches the retry decision.
|
|
9677
|
-
*
|
|
9678
|
-
* a 53-minute turn ended `status code 524`, and another ended `Invalid API key` after a platform
|
|
9737
|
+
* A 53-minute turn ended `status code 524`, and another ended `Invalid API key` after a platform
|
|
9679
9738
|
* key expired mid-turn. A new turn succeeds in both cases.
|
|
9680
9739
|
*
|
|
9681
9740
|
* `errorCode` is the provider's machine code when it reported one. The classifier reads the code
|
|
@@ -9859,7 +9918,7 @@ function retainedAdmissionCause(error) {
|
|
|
9859
9918
|
*
|
|
9860
9919
|
* A provider SDK throws its own error classes, so an environment `create` that the platform
|
|
9861
9920
|
* refused arrives here as neither a `BackendTransportError` nor an `AgentEvalError`, and the
|
|
9862
|
-
* default sends it to `transient`.
|
|
9921
|
+
* default sends it to `transient`. A Tangle Sandbox create refused
|
|
9863
9922
|
* `HTTP 400 {"code":"CONFIG_ERROR"}` for a key whose budget was fully reserved retried 14-22
|
|
9864
9923
|
* times per node while the run showed a durable intent and no other event, so eleven of twelve
|
|
9865
9924
|
* roots sat for 25 minutes with nothing to diagnose. The status was on the error the whole time.
|
|
@@ -10685,7 +10744,7 @@ function peerMailTools(mailbox, capabilityId) {
|
|
|
10685
10744
|
*
|
|
10686
10745
|
* The worker-side receive end of the down-leg: a per-worker inbox an executor exposes as
|
|
10687
10746
|
* `Executor.deliver`. The driver's `steer_agent` / `answer_question` land here,
|
|
10688
|
-
* and the worker's agent loop takes them at two points
|
|
10747
|
+
* and the worker's agent loop takes them at two points:
|
|
10689
10748
|
*
|
|
10690
10749
|
* - QUEUED (default): the message accumulates and is taken at the next step boundary — folded
|
|
10691
10750
|
* into the conversation before the next think. A worker also takes before it may settle, so it
|
|
@@ -11078,13 +11137,15 @@ function recordLaunch(env, ids, options) {
|
|
|
11078
11137
|
dst: ids.TANGLE_RUN_ID,
|
|
11079
11138
|
attrs: {}
|
|
11080
11139
|
});
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11140
|
+
fenceRunWrite(() => {
|
|
11141
|
+
const fd = openSync(join(dir, `${host}.jsonl`), "a", 384);
|
|
11142
|
+
try {
|
|
11143
|
+
appendFileSync(fd, node);
|
|
11144
|
+
appendFileSync(fd, edge);
|
|
11145
|
+
} finally {
|
|
11146
|
+
closeSync(fd);
|
|
11147
|
+
}
|
|
11148
|
+
});
|
|
11088
11149
|
} catch {}
|
|
11089
11150
|
}
|
|
11090
11151
|
//#endregion
|
|
@@ -12925,7 +12986,7 @@ function bridgeOutputText(out) {
|
|
|
12925
12986
|
}
|
|
12926
12987
|
/**
|
|
12927
12988
|
* The leaf `createWorktreeCliExecutor` as a backend-as-data factory: a supervisor-authored
|
|
12928
|
-
* `AgentProfile` driving claude / codex / opencode on its own worktree. `budgetExempt` like
|
|
12989
|
+
* `AgentProfile` driving claude / codex / opencode / pi / kimi-code on its own worktree. `budgetExempt` like
|
|
12929
12990
|
* the other CLI leaves; the authored systemPrompt + model reach the harness via §1.5.
|
|
12930
12991
|
*/
|
|
12931
12992
|
//#endregion
|
|
@@ -13085,7 +13146,7 @@ const routerToolsSeamKey = "router-tools";
|
|
|
13085
13146
|
/**
|
|
13086
13147
|
*
|
|
13087
13148
|
* The worktree-CLI leaf executor — a supervisor-authored `AgentProfile` driving a local
|
|
13088
|
-
* coding-harness CLI (claude / codex / opencode) on its OWN git worktree, surfaced as the open
|
|
13149
|
+
* coding-harness CLI (claude / codex / opencode / pi / kimi-code) on its OWN git worktree, surfaced as the open
|
|
13089
13150
|
* `Executor<Out>` port (`./types`). It is a LEAF executor: it plugs straight into the
|
|
13090
13151
|
* `Scope`/`Supervisor` recursion and `gateOnDeliverable`, so it IS the canonical recursive path
|
|
13091
13152
|
* (no `runAgentRounds`/virtual-SandboxInstance shim in between).
|
|
@@ -15941,7 +16002,7 @@ const STOP_STATUS_POLL_MS = 1e3;
|
|
|
15941
16002
|
*
|
|
15942
16003
|
* A retained execution outlives its local stream by design, so an aborted observer can reconnect.
|
|
15943
16004
|
* Keeping its environment preserves the files; it must not keep the harness running. Measured on
|
|
15944
|
-
* Discovery: after `disco cancel`
|
|
16005
|
+
* Discovery: after `disco cancel` the kept root box ran `claude --print` for two
|
|
15945
16006
|
* more minutes, untraced and charged to the subscription, until an operator stopped the box; on
|
|
15946
16007
|
* 2026-10-03 a cancelled run kept 18 boxes whose `claude` processes ran until an operator stopped
|
|
15947
16008
|
* them. The provider's exact cancellation stops the process; the box and its files stay.
|
|
@@ -16536,7 +16597,7 @@ const WORKSPACE_CHECKPOINT_TIMEOUT_MS = 12e4;
|
|
|
16536
16597
|
* it again. */
|
|
16537
16598
|
const WORKSPACE_CHECKPOINT_ROTATION_CAPTURES_MS = 2 * 6e4;
|
|
16538
16599
|
/** Bound on creating and reconstructing the fork a checkpoint's capture reads: a Sandbox box
|
|
16539
|
-
* created from a snapshot (
|
|
16600
|
+
* created from a snapshot (19 s). The capture itself is bounded by its port. */
|
|
16540
16601
|
const WORKSPACE_CHECKPOINT_FORK_TIMEOUT_MS = 10 * 6e4;
|
|
16541
16602
|
/** Write the marker. False when the environment cannot take it, so no restore can be verified. */
|
|
16542
16603
|
async function writeWorkspaceMarker(environment, marker, signal) {
|
|
@@ -16877,7 +16938,7 @@ function stringValue(value) {
|
|
|
16877
16938
|
/**
|
|
16878
16939
|
* How long a retained stream may go without new evidence before the node publishes that it waits
|
|
16879
16940
|
* on its exact result. Silence never ends the turn (ending there failed 18 still-running attempts
|
|
16880
|
-
* as `terminal-event-lost
|
|
16941
|
+
* as `terminal-event-lost`); only the exact result or an abort does. The bound on
|
|
16881
16942
|
* a wait that never ends is the Lab keeper's hung-root re-drive after 15 minutes without a write.
|
|
16882
16943
|
*/
|
|
16883
16944
|
const RETAINED_AWAITING_RESULT_AFTER_MS = 8 * 6e4;
|
|
@@ -16892,7 +16953,7 @@ const RETAINED_TAIL_FLOW_MS = 100;
|
|
|
16892
16953
|
/**
|
|
16893
16954
|
* Why the event stream stopped short, as bounded redacted text. A settlement reason reads messages
|
|
16894
16955
|
* and `cause` links only, never an AggregateError's members, so a wrapper that omits this hides
|
|
16895
|
-
* which layer lost the stream (critics-tournament-v1-158ca88e83bf:s1
|
|
16956
|
+
* which layer lost the stream (critics-tournament-v1-158ca88e83bf:s1).
|
|
16896
16957
|
*/
|
|
16897
16958
|
function observationFailureText(failure) {
|
|
16898
16959
|
const error = failure.error;
|
|
@@ -18022,7 +18083,7 @@ var ProviderTurnSettlement = class {
|
|
|
18022
18083
|
}
|
|
18023
18084
|
/**
|
|
18024
18085
|
* A capture that fails or exceeds its deadline after settlement is a fact about the evidence,
|
|
18025
|
-
* never the turn's outcome. On Runtime 0.295.4
|
|
18086
|
+
* never the turn's outcome. On Runtime 0.295.4 a capture past its 1,200,000 ms
|
|
18026
18087
|
* deadline behind a two-slot queue shared by 34 workers threw an AbortError, the driver
|
|
18027
18088
|
* classified it terminal, and two research roots ended with 13 and 0 children settled. With no
|
|
18028
18089
|
* receipt the source stays preserved and the owner reads a retention failure; the turn is not re-run.
|
|
@@ -18758,7 +18819,7 @@ function heldForContinuation(scope) {
|
|
|
18758
18819
|
/** What a leaf is told when it continues after a refused turn. The session carries its
|
|
18759
18820
|
* conversation and the environment its files, so the instruction names neither the provider nor
|
|
18760
18821
|
* the refusal: a director told the details of a provider failure spent its children probing the
|
|
18761
|
-
* infrastructure (discovery-lab AGENTS.md
|
|
18822
|
+
* infrastructure (discovery-lab AGENTS.md). */
|
|
18762
18823
|
const LEAF_CONTINUATION_TASK = "Your previous turn was interrupted before it finished. This is the same task in the same session: your conversation so far and the files in your workspace are where you left them. Continue from where you stopped. Do not start over.";
|
|
18763
18824
|
//#endregion
|
|
18764
18825
|
//#region src/runtime/environment-provider/provider-executor-admission.ts
|
|
@@ -20022,7 +20083,7 @@ function taskToMessages(task, spec, resolvedSystem) {
|
|
|
20022
20083
|
* A router-brained agent (`harness` omitted or `cli-base`) runs its tool loop in this process, so
|
|
20023
20084
|
* its whole conversation is in the loop's `messages` and nowhere else. Before this, Runtime
|
|
20024
20085
|
* metered each turn's usage and tool-call names and kept nothing the agent said, saw, or asked a
|
|
20025
|
-
* tool to do: a 316-agent tree
|
|
20086
|
+
* tool to do: a 316-agent tree settled with 0 of 316 transcripts, and the 37 agents
|
|
20026
20087
|
* still running when its driver process stopped left no record at all (agent-runtime#1377).
|
|
20027
20088
|
*
|
|
20028
20089
|
* The recorder keeps each message once, in the order the model saw it, and serves two readers:
|
|
@@ -23649,7 +23710,7 @@ var SpawnEventIndex = class {
|
|
|
23649
23710
|
}
|
|
23650
23711
|
if (!outsideCursorNamespace(event) && this.cursors.has(event.seq)) throw new Error(`spawn journal corrupted: duplicate cursor seq ${event.seq} in tree '${this.root}'; the cursor order replay relies on is not unique`);
|
|
23651
23712
|
}
|
|
23652
|
-
/** Called
|
|
23713
|
+
/** Called after validation; a file writer discards staged state if grouped publication fails. */
|
|
23653
23714
|
add(event) {
|
|
23654
23715
|
if (!outsideCursorNamespace(event)) this.cursors.add(event.seq);
|
|
23655
23716
|
if (event.kind !== "spawned" && event.kind !== "materialized" && event.kind !== "seat-materialized" && event.kind !== "execution-bound" && event.kind !== "execution-input" && event.kind !== "execution-admitted" && event.kind !== "execution-result" && event.kind !== "execution-abandoned" && event.kind !== "environment-teardown" && event.kind !== "environment-terminal" && !closesCursorSlot(event)) return;
|
|
@@ -23796,6 +23857,7 @@ const outsideKinds = /* @__PURE__ */ new Set([
|
|
|
23796
23857
|
"seat-segment",
|
|
23797
23858
|
"seat-materialized",
|
|
23798
23859
|
"seat-paused",
|
|
23860
|
+
"run-parked",
|
|
23799
23861
|
"root-segment",
|
|
23800
23862
|
"root-reentered",
|
|
23801
23863
|
"reopened",
|
|
@@ -23815,6 +23877,81 @@ function insideCursorNamespace(ev) {
|
|
|
23815
23877
|
return !outsideKinds.has(ev.kind);
|
|
23816
23878
|
}
|
|
23817
23879
|
//#endregion
|
|
23880
|
+
//#region src/durable/jsonl-append.ts
|
|
23881
|
+
/** Commit JSONL bytes and validate their descriptor under one generation fence. @internal */
|
|
23882
|
+
function commitJsonLine(path, record, acknowledge) {
|
|
23883
|
+
const encoded = JSON.stringify(record);
|
|
23884
|
+
if (encoded === void 0) throw new TypeError("JSONL records must be JSON serializable");
|
|
23885
|
+
return fenceRunWrite(() => {
|
|
23886
|
+
const separator = prepareJsonlTail(path);
|
|
23887
|
+
const fd = openSync(path, "a");
|
|
23888
|
+
try {
|
|
23889
|
+
const bytes = Buffer.from(`${separator ? "\n" : ""}${encoded}\n`);
|
|
23890
|
+
let offset = 0;
|
|
23891
|
+
while (offset < bytes.length) {
|
|
23892
|
+
const written = writeSync(fd, bytes, offset, bytes.length - offset);
|
|
23893
|
+
if (written <= 0) throw new Error(`append-only file write made no progress at byte ${offset}`);
|
|
23894
|
+
offset += written;
|
|
23895
|
+
}
|
|
23896
|
+
fsyncSync(fd);
|
|
23897
|
+
return acknowledge?.(fd);
|
|
23898
|
+
} finally {
|
|
23899
|
+
closeSync(fd);
|
|
23900
|
+
}
|
|
23901
|
+
});
|
|
23902
|
+
}
|
|
23903
|
+
/** Recover only an uncommitted tail. Caller holds the generation fence. @internal */
|
|
23904
|
+
function prepareJsonlTail(path) {
|
|
23905
|
+
let fd;
|
|
23906
|
+
try {
|
|
23907
|
+
fd = openSync(path, "r+");
|
|
23908
|
+
} catch (error) {
|
|
23909
|
+
if (error.code === "ENOENT") return false;
|
|
23910
|
+
throw error;
|
|
23911
|
+
}
|
|
23912
|
+
try {
|
|
23913
|
+
const size = fstatSync(fd).size;
|
|
23914
|
+
if (size === 0) return false;
|
|
23915
|
+
const last = Buffer.allocUnsafe(1);
|
|
23916
|
+
readAt(fd, last, size - 1);
|
|
23917
|
+
if (last[0] === 10) return false;
|
|
23918
|
+
const chunks = [];
|
|
23919
|
+
let end = size;
|
|
23920
|
+
let tailStart = 0;
|
|
23921
|
+
while (end > 0) {
|
|
23922
|
+
const start = Math.max(0, end - 65536);
|
|
23923
|
+
const chunk = Buffer.allocUnsafe(end - start);
|
|
23924
|
+
readAt(fd, chunk, start);
|
|
23925
|
+
const newline = chunk.lastIndexOf(10);
|
|
23926
|
+
chunks.push(chunk.subarray(newline + 1));
|
|
23927
|
+
if (newline >= 0) {
|
|
23928
|
+
tailStart = start + newline + 1;
|
|
23929
|
+
break;
|
|
23930
|
+
}
|
|
23931
|
+
end = start;
|
|
23932
|
+
}
|
|
23933
|
+
try {
|
|
23934
|
+
JSON.parse(Buffer.concat(chunks.reverse()).toString("utf8"));
|
|
23935
|
+
return true;
|
|
23936
|
+
} catch (error) {
|
|
23937
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
23938
|
+
ftruncateSync(fd, tailStart);
|
|
23939
|
+
fsyncSync(fd);
|
|
23940
|
+
return false;
|
|
23941
|
+
}
|
|
23942
|
+
} finally {
|
|
23943
|
+
closeSync(fd);
|
|
23944
|
+
}
|
|
23945
|
+
}
|
|
23946
|
+
function readAt(fd, buffer, position) {
|
|
23947
|
+
let offset = 0;
|
|
23948
|
+
while (offset < buffer.length) {
|
|
23949
|
+
const read = readSync(fd, buffer, offset, buffer.length - offset, position + offset);
|
|
23950
|
+
if (read === 0) throw new Error("journal changed while preparing its append tail");
|
|
23951
|
+
offset += read;
|
|
23952
|
+
}
|
|
23953
|
+
}
|
|
23954
|
+
//#endregion
|
|
23818
23955
|
//#region src/durable/jsonl-file.ts
|
|
23819
23956
|
/** Read a fixed file prefix one record at a time, never allocating the whole journal as a string.
|
|
23820
23957
|
* A reader cannot chase concurrent appends forever. Missing files are empty only when requested;
|
|
@@ -23878,16 +24015,7 @@ function parseRecord(line, source, lineNumber, terminated, allowWhitespaceLines
|
|
|
23878
24015
|
}
|
|
23879
24016
|
}
|
|
23880
24017
|
async function appendCommittedJsonLine(path, record, acknowledge) {
|
|
23881
|
-
|
|
23882
|
-
const needsSeparator = await prepareJsonlAppend(path);
|
|
23883
|
-
const handle = await fs.open(path, "a");
|
|
23884
|
-
try {
|
|
23885
|
-
await writeAllBytes(handle, `${needsSeparator ? "\n" : ""}${JSON.stringify(record)}\n`);
|
|
23886
|
-
await handle.sync();
|
|
23887
|
-
return await acknowledge?.(handle);
|
|
23888
|
-
} finally {
|
|
23889
|
-
await handle.close();
|
|
23890
|
-
}
|
|
24018
|
+
return commitJsonLine(path, record, acknowledge);
|
|
23891
24019
|
}
|
|
23892
24020
|
/** Serialize JSONL file updates across processes and aliases using Eval's existing file lock.
|
|
23893
24021
|
* The caller owns validation and the record format. The lock path names the canonical file,
|
|
@@ -23943,74 +24071,12 @@ async function upsertCommittedJsonLine(path, record, key) {
|
|
|
23943
24071
|
allowWhitespaceLines: true
|
|
23944
24072
|
})) if (key(prior) !== id) updated.push(prior);
|
|
23945
24073
|
updated.push(snapshot);
|
|
23946
|
-
const { writeAtomicDurableFile } = await import("./
|
|
24074
|
+
const { writeAtomicDurableFile } = await import("./record-events-D93DkpAx.js").then((n) => n.i);
|
|
23947
24075
|
writeAtomicDurableFile(path, `${updated.map((row) => JSON.stringify(row)).join("\n")}\n`, { preserveMode: true });
|
|
23948
24076
|
}
|
|
23949
|
-
/**
|
|
23950
|
-
async function writeAllBytes(handle, value) {
|
|
23951
|
-
const bytes = typeof value === "string" ? Buffer.from(value) : Buffer.from(value);
|
|
23952
|
-
let offset = 0;
|
|
23953
|
-
while (offset < bytes.byteLength) {
|
|
23954
|
-
const { bytesWritten } = await handle.write(bytes, offset, bytes.byteLength - offset, null);
|
|
23955
|
-
if (bytesWritten <= 0) throw new Error(`append-only file write made no progress at byte ${offset}`);
|
|
23956
|
-
offset += bytesWritten;
|
|
23957
|
-
}
|
|
23958
|
-
}
|
|
23959
|
-
/** Prepare the tail under the journal owner's existing single-writer discipline.
|
|
23960
|
-
* Healthy appends read one byte, regardless of history size. Only recovery scans backward,
|
|
23961
|
-
* retaining a valid unterminated value or truncating an uncommitted torn tail. */
|
|
24077
|
+
/** Recover a torn tail under the same generation fence as durable publications. @internal */
|
|
23962
24078
|
async function prepareJsonlAppend(path) {
|
|
23963
|
-
|
|
23964
|
-
let handle;
|
|
23965
|
-
try {
|
|
23966
|
-
handle = await fs.open(path, "r+");
|
|
23967
|
-
} catch (error) {
|
|
23968
|
-
if (isNoEntError(error)) return false;
|
|
23969
|
-
throw error;
|
|
23970
|
-
}
|
|
23971
|
-
try {
|
|
23972
|
-
const size = (await handle.stat()).size;
|
|
23973
|
-
if (size === 0) return false;
|
|
23974
|
-
const lastByte = Buffer.allocUnsafe(1);
|
|
23975
|
-
await readAt(handle, lastByte, size - 1);
|
|
23976
|
-
if (lastByte[0] === 10) return false;
|
|
23977
|
-
const chunks = [];
|
|
23978
|
-
let end = size;
|
|
23979
|
-
let tailStart = 0;
|
|
23980
|
-
while (end > 0) {
|
|
23981
|
-
const start = Math.max(0, end - 65536);
|
|
23982
|
-
const chunk = Buffer.allocUnsafe(end - start);
|
|
23983
|
-
await readAt(handle, chunk, start);
|
|
23984
|
-
const newline = chunk.lastIndexOf(10);
|
|
23985
|
-
chunks.push(chunk.subarray(newline + 1));
|
|
23986
|
-
if (newline >= 0) {
|
|
23987
|
-
tailStart = start + newline + 1;
|
|
23988
|
-
break;
|
|
23989
|
-
}
|
|
23990
|
-
end = start;
|
|
23991
|
-
}
|
|
23992
|
-
const tail = Buffer.concat(chunks.reverse()).toString("utf8");
|
|
23993
|
-
try {
|
|
23994
|
-
JSON.parse(tail);
|
|
23995
|
-
return true;
|
|
23996
|
-
} catch (error) {
|
|
23997
|
-
if (!(error instanceof SyntaxError)) throw error;
|
|
23998
|
-
await handle.truncate(tailStart);
|
|
23999
|
-
await handle.sync();
|
|
24000
|
-
return false;
|
|
24001
|
-
}
|
|
24002
|
-
} finally {
|
|
24003
|
-
await handle.close();
|
|
24004
|
-
}
|
|
24005
|
-
}
|
|
24006
|
-
/** A short read is legal; an unexpected EOF means the owner's snapshot changed. */
|
|
24007
|
-
async function readAt(handle, buffer, position) {
|
|
24008
|
-
let offset = 0;
|
|
24009
|
-
while (offset < buffer.length) {
|
|
24010
|
-
const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, position + offset);
|
|
24011
|
-
if (bytesRead === 0) throw new Error("journal changed while preparing its append tail");
|
|
24012
|
-
offset += bytesRead;
|
|
24013
|
-
}
|
|
24079
|
+
return fenceRunWrite(() => prepareJsonlTail(path));
|
|
24014
24080
|
}
|
|
24015
24081
|
/** True for a filesystem error meaning "the file is not there yet" — the one condition an
|
|
24016
24082
|
* append-only reader treats as an empty log rather than a fault. */
|
|
@@ -24028,16 +24094,19 @@ function isNoEntError(error) {
|
|
|
24028
24094
|
*/
|
|
24029
24095
|
var FileResultBlobStore = class {
|
|
24030
24096
|
dir;
|
|
24097
|
+
writeContext = captureRunWriteContext();
|
|
24031
24098
|
constructor(dir) {
|
|
24032
24099
|
this.dir = dir;
|
|
24033
24100
|
}
|
|
24034
24101
|
async put(outRef, artifact) {
|
|
24035
|
-
|
|
24036
|
-
|
|
24037
|
-
|
|
24038
|
-
|
|
24039
|
-
|
|
24040
|
-
|
|
24102
|
+
return this.writeContext(async () => {
|
|
24103
|
+
const { text } = encodeResultBlob(outRef, artifact);
|
|
24104
|
+
const filePath = this.blobPath(outRef);
|
|
24105
|
+
assertNoSymlinkDescendant(this.dir, filePath, "result blob");
|
|
24106
|
+
await (await import("node:fs/promises")).mkdir(this.dir, { recursive: true });
|
|
24107
|
+
assertNoSymlinkDescendant(this.dir, filePath, "result blob");
|
|
24108
|
+
if (!publishExclusiveDurableFile(filePath, text, { mode: 384 })) assertContentAddress(outRef, await this.get(outRef));
|
|
24109
|
+
});
|
|
24041
24110
|
}
|
|
24042
24111
|
async get(outRef) {
|
|
24043
24112
|
const filePath = this.blobPath(outRef);
|
|
@@ -24833,6 +24902,10 @@ function noteScopeRetainedOwnerCoordination(scope) {
|
|
|
24833
24902
|
delete state.checkpointing;
|
|
24834
24903
|
});
|
|
24835
24904
|
}
|
|
24905
|
+
/** @internal The checkpoint in progress for this owner, for a test or a release to wait on. */
|
|
24906
|
+
function scopeRetainedOwnerCheckpointing(scope) {
|
|
24907
|
+
return owners.get(scope)?.checkpointing;
|
|
24908
|
+
}
|
|
24836
24909
|
async function checkpointOwnerWorkspace(scope, state) {
|
|
24837
24910
|
const { provider, args } = state;
|
|
24838
24911
|
if (provider === void 0) return;
|
|
@@ -25677,10 +25750,11 @@ const ABANDON_STOP_TIMEOUT_MS = 3e4;
|
|
|
25677
25750
|
* Abandon the owner's in-flight invocation, which the driver retry loop asks for when the same
|
|
25678
25751
|
* reconciliation keeps failing the same way (`DriverRetryRun.resolvePending`).
|
|
25679
25752
|
*
|
|
25680
|
-
* Runtime
|
|
25681
|
-
*
|
|
25682
|
-
*
|
|
25683
|
-
*
|
|
25753
|
+
* Runtime abandons only after the provider confirms the dispatched execution stopped or is no
|
|
25754
|
+
* longer live. An intent without a dispatch reference, or an unconfirmed stop, keeps the original
|
|
25755
|
+
* invocation recoverable under the same identity. The journal refuses every later admission or
|
|
25756
|
+
* result of an abandoned invocation, so only its replacement can commit a result. Answers `false`,
|
|
25757
|
+
* journaling nothing, when there is no unfinished invocation or its native stop is unconfirmed.
|
|
25684
25758
|
*/
|
|
25685
25759
|
async function abandonScopeRetainedOwnerInvocation(scope, failure, failures) {
|
|
25686
25760
|
const state = owners.get(scope);
|
|
@@ -25699,7 +25773,7 @@ async function abandonScopeRetainedOwnerInvocation(scope, failure, failures) {
|
|
|
25699
25773
|
now: args.now
|
|
25700
25774
|
});
|
|
25701
25775
|
scope.signal.throwIfAborted();
|
|
25702
|
-
|
|
25776
|
+
if (!(stop?.effect === "cancelled" || stop?.effect === "not_live")) return false;
|
|
25703
25777
|
await args.journal.appendEvent(args.rootId, {
|
|
25704
25778
|
kind: "execution-abandoned",
|
|
25705
25779
|
id: args.nodeId,
|
|
@@ -25707,7 +25781,7 @@ async function abandonScopeRetainedOwnerInvocation(scope, failure, failures) {
|
|
|
25707
25781
|
pendingCause: failure.pendingCause,
|
|
25708
25782
|
failures,
|
|
25709
25783
|
detail: errorText(errMessage(failure)).slice(0, 2048),
|
|
25710
|
-
outcome:
|
|
25784
|
+
outcome: "stopped",
|
|
25711
25785
|
...stop === void 0 ? {} : { stop: {
|
|
25712
25786
|
executionId: stop.executionId,
|
|
25713
25787
|
effect: stop.effect,
|
|
@@ -25740,8 +25814,8 @@ async function prepareScopeRetainedOwnerTask(scope, task, session = "native") {
|
|
|
25740
25814
|
}
|
|
25741
25815
|
if (state.taskRef !== void 0 && state.acceptedRef === void 0) await abandonInputAdmittedIntoDebt(state, await reconcileOwnerWorkspaceBeforeReuse(state, scope.signal));
|
|
25742
25816
|
const unusable = unusableEnvironmentIds(owned);
|
|
25743
|
-
const
|
|
25744
|
-
if (
|
|
25817
|
+
const currentEnvironment = state.admissions.find((admission) => admission.phase === "environment");
|
|
25818
|
+
if (state.acceptedRef === void 0 && currentEnvironment?.phase === "environment" && unusable.has(currentEnvironment.environmentId)) {
|
|
25745
25819
|
delete state.inputSequence;
|
|
25746
25820
|
delete state.taskRef;
|
|
25747
25821
|
state.admissions.length = 0;
|
|
@@ -26684,7 +26758,7 @@ function hasRetriableTeardowns(scope, release) {
|
|
|
26684
26758
|
* A driver's `act` returning does not stop everything that holds its scope: a supervisor tool
|
|
26685
26759
|
* whose handler outran its response fence keeps running detached (`single-flight-tools`
|
|
26686
26760
|
* `background()`) with the coordination verbs still bound, and a verb call reaches `spawn`
|
|
26687
|
-
* in-process — closing the MCP listener does not reach it.
|
|
26761
|
+
* in-process — closing the MCP listener does not reach it. Such a handler
|
|
26688
26762
|
* spawned `distill:all` 309 ms after the barrier had drained and released. The child was
|
|
26689
26763
|
* admitted, took a conserved reservation, built a sandbox, ran 12.4 s of provider work, and
|
|
26690
26764
|
* journaled its settlement 19 s after the run had already written its failure — while the live
|
|
@@ -28216,7 +28290,7 @@ async function appendSpawnEvents(journal, root, events) {
|
|
|
28216
28290
|
}
|
|
28217
28291
|
/**
|
|
28218
28292
|
* JSONL on disk. One line per record: the first record is `begin`, subsequent records
|
|
28219
|
-
* are `event`
|
|
28293
|
+
* are `event` or atomic `events` envelopes. `loadTree` replays the whole file,
|
|
28220
28294
|
* filtering by `root`, and applies the same begin-precedes-events + unique-seq
|
|
28221
28295
|
* corruption guards as the in-memory impl. Each append fsyncs so a crash between
|
|
28222
28296
|
* writes never loses an acknowledged event.
|
|
@@ -28225,6 +28299,7 @@ async function appendSpawnEvents(journal, root, events) {
|
|
|
28225
28299
|
*/
|
|
28226
28300
|
var FileSpawnJournal = class {
|
|
28227
28301
|
path;
|
|
28302
|
+
writeContext = captureRunWriteContext();
|
|
28228
28303
|
appendTail = Promise.resolve();
|
|
28229
28304
|
appendIndex;
|
|
28230
28305
|
constructor(path) {
|
|
@@ -28239,9 +28314,11 @@ var FileSpawnJournal = class {
|
|
|
28239
28314
|
if (record.kind === "begin") begun = true;
|
|
28240
28315
|
else {
|
|
28241
28316
|
if (!begun) throw new Error(`spawn journal corrupted: event for tree '${root}' precedes its begin record`);
|
|
28242
|
-
|
|
28243
|
-
|
|
28244
|
-
|
|
28317
|
+
for (const event of spawnJournalRecordEvents(record)) {
|
|
28318
|
+
index.assert(event);
|
|
28319
|
+
index.add(event);
|
|
28320
|
+
events.push(event);
|
|
28321
|
+
}
|
|
28245
28322
|
}
|
|
28246
28323
|
}
|
|
28247
28324
|
return begun ? events : void 0;
|
|
@@ -28280,6 +28357,28 @@ var FileSpawnJournal = class {
|
|
|
28280
28357
|
tree.index.add(event);
|
|
28281
28358
|
});
|
|
28282
28359
|
}
|
|
28360
|
+
async appendEvents(root, events) {
|
|
28361
|
+
const captured = detachedSnapshot(events, "spawn events");
|
|
28362
|
+
return this.serializeAppend(async () => {
|
|
28363
|
+
const state = await this.validationIndex();
|
|
28364
|
+
const tree = state.trees.get(root);
|
|
28365
|
+
if (tree === void 0) throw new Error(`appendEvents called for unknown spawn tree '${root}'; call beginTree first`);
|
|
28366
|
+
try {
|
|
28367
|
+
for (const event of captured) {
|
|
28368
|
+
tree.index.assert(event);
|
|
28369
|
+
tree.index.add(event);
|
|
28370
|
+
}
|
|
28371
|
+
state.stamp = await this.writeRecord({
|
|
28372
|
+
kind: "events",
|
|
28373
|
+
root,
|
|
28374
|
+
events: captured
|
|
28375
|
+
});
|
|
28376
|
+
} catch (error) {
|
|
28377
|
+
this.appendIndex = void 0;
|
|
28378
|
+
throw error;
|
|
28379
|
+
}
|
|
28380
|
+
});
|
|
28381
|
+
}
|
|
28283
28382
|
async validationIndex() {
|
|
28284
28383
|
const stamp = await this.fileStamp();
|
|
28285
28384
|
if (this.appendIndex && this.appendIndex.stamp === stamp) return this.appendIndex;
|
|
@@ -28293,8 +28392,10 @@ var FileSpawnJournal = class {
|
|
|
28293
28392
|
} else {
|
|
28294
28393
|
const tree = trees.get(record.root);
|
|
28295
28394
|
if (!tree) throw new Error(`spawn journal corrupted: event for tree '${record.root}' precedes its begin record`);
|
|
28296
|
-
|
|
28297
|
-
|
|
28395
|
+
for (const event of spawnJournalRecordEvents(record)) {
|
|
28396
|
+
tree.index.assert(event);
|
|
28397
|
+
tree.index.add(event);
|
|
28398
|
+
}
|
|
28298
28399
|
}
|
|
28299
28400
|
if (await this.fileStamp() !== stamp) throw new Error("spawn journal changed while rebuilding its append index");
|
|
28300
28401
|
this.appendIndex = {
|
|
@@ -28313,7 +28414,7 @@ var FileSpawnJournal = class {
|
|
|
28313
28414
|
}
|
|
28314
28415
|
}
|
|
28315
28416
|
async serializeAppend(operation) {
|
|
28316
|
-
const append = this.appendTail.then(operation);
|
|
28417
|
+
const append = this.appendTail.then(() => this.writeContext(operation));
|
|
28317
28418
|
this.appendTail = append.catch(() => void 0);
|
|
28318
28419
|
return append;
|
|
28319
28420
|
}
|
|
@@ -28322,9 +28423,9 @@ var FileSpawnJournal = class {
|
|
|
28322
28423
|
const { dirname } = await import("node:path");
|
|
28323
28424
|
try {
|
|
28324
28425
|
await fs.mkdir(dirname(this.path), { recursive: true });
|
|
28325
|
-
return await appendCommittedJsonLine(this.path, record,
|
|
28326
|
-
const stamp = journalFileStamp(
|
|
28327
|
-
if (
|
|
28426
|
+
return await appendCommittedJsonLine(this.path, record, (fd) => {
|
|
28427
|
+
const stamp = journalFileStamp(fstatSync(fd, { bigint: true }));
|
|
28428
|
+
if (journalFileStamp(statSync(this.path, { bigint: true })) !== stamp) throw new Error("spawn journal changed while acknowledging its append");
|
|
28328
28429
|
return stamp;
|
|
28329
28430
|
});
|
|
28330
28431
|
} catch (error) {
|
|
@@ -28860,10 +28961,11 @@ function workerLifecycle(eventDir, workerId) {
|
|
|
28860
28961
|
const text = line.trim();
|
|
28861
28962
|
if (!text) continue;
|
|
28862
28963
|
try {
|
|
28863
|
-
const
|
|
28864
|
-
|
|
28865
|
-
|
|
28866
|
-
|
|
28964
|
+
for (const event of spawnJournalRecordEvents(JSON.parse(text))) {
|
|
28965
|
+
if (event?.id !== workerId) continue;
|
|
28966
|
+
if (event.kind === "spawned") spawned = true;
|
|
28967
|
+
if (event.kind === "settled" || event.kind === "cancelled") terminal = true;
|
|
28968
|
+
}
|
|
28867
28969
|
} catch {}
|
|
28868
28970
|
}
|
|
28869
28971
|
return {
|
|
@@ -29966,19 +30068,18 @@ async function prepareInterruptedExecutors(opts, events, signal, now, parentId =
|
|
|
29966
30068
|
const profile = shareParsedStrings(agentProfileSchema.parse(await opts.blobs.get(node.profileRef)), parsedStrings);
|
|
29967
30069
|
const task = shareParsedStrings(await opts.blobs.get(taskRef), parsedStrings);
|
|
29968
30070
|
if (canonicalAgentProfileDigest(profile) !== node.identity.profileDigest || canonicalCandidateDigest(task) !== node.identity.taskDigest) throw new RuntimeRunStateError(`recovery inputs for '${node.id}' do not match its admitted identity`);
|
|
29969
|
-
let prepared;
|
|
29970
30071
|
if (node.ownedTreeRoot !== void 0) {
|
|
29971
30072
|
if (node.ownedTreeRoot !== nestedDriverTreeRoot(opts.runId, node.id)) throw new RuntimeRunStateError(`retained manager '${node.id}' changed its owned tree`);
|
|
29972
30073
|
const nested = await opts.journal.loadTree(node.ownedTreeRoot);
|
|
29973
30074
|
const roots = nested?.filter((event) => event.kind === "spawned" && event.parent === void 0) ?? [];
|
|
29974
30075
|
if (nested?.length && (roots.length !== 1 || contentAddress(roots[0]) !== contentAddress(ownedTreeRootSpawn(node)))) throw new RuntimeRunStateError(`retained manager '${node.id}' has conflicting subtree ownership`);
|
|
29975
|
-
prepared = prepareRetainedExecutor(opts.recoverExecutor, {
|
|
29976
|
-
spawned: node,
|
|
29977
|
-
profile,
|
|
29978
|
-
task
|
|
29979
|
-
});
|
|
29980
|
-
if (!prepared) continue;
|
|
29981
30076
|
}
|
|
30077
|
+
const prepared = prepareRetainedExecutor(opts.recoverExecutor, {
|
|
30078
|
+
spawned: node,
|
|
30079
|
+
profile,
|
|
30080
|
+
task
|
|
30081
|
+
});
|
|
30082
|
+
if (node.ownedTreeRoot !== void 0 && !prepared) continue;
|
|
29982
30083
|
const priorMaterialization = [...owned].reverse().find((event) => event.kind === "materialized" || event.kind === "seat-materialized")?.receipt;
|
|
29983
30084
|
const continuation = latestInput !== void 0 && inputs.length > 1 && node.ownedTreeRoot === void 0 ? await leafContinuation(node, owned, latestInput, opts) : latestInput !== void 0 && node.continues !== void 0 && admissions.length === 0 && node.ownedTreeRoot === void 0 ? heldContinuation(node, events, latestInput) : void 0;
|
|
29984
30085
|
recoveries.push({
|
|
@@ -31683,7 +31784,8 @@ const driverExecutorFactory = (rawSpec, ctx) => {
|
|
|
31683
31784
|
accounting = partial?.accounting;
|
|
31684
31785
|
const events = await journal.loadTree(nestedRoot).catch(() => void 0);
|
|
31685
31786
|
const settledIds = new Set(events?.filter((event) => event.kind === "settled" || event.kind === "cancelled").map((event) => event.id));
|
|
31686
|
-
|
|
31787
|
+
const terminalAdmissionRefusal = isTerminalAdmissionRefusal(err);
|
|
31788
|
+
if (driver.resultAccepted?.() === true || spec.acceptedSubmission?.() === true || events?.some((event) => event.kind === "execution-admitted" && (event.admission.phase === "dispatched" || event.id === seam.nodeId && (event.admission.phase !== "intent" || !terminalAdmissionRefusal)) || event.kind === "execution-result" || event.kind === "spawned" && event.parent !== void 0 && !settledIds.has(event.id))) throw new RetainedExecutionPendingError(err, "nested-recovery");
|
|
31687
31789
|
if (cleanupError !== void 0) throw cleanupError;
|
|
31688
31790
|
throw err;
|
|
31689
31791
|
} finally {
|
|
@@ -31750,6 +31852,11 @@ function withDriverExecutor(base) {
|
|
|
31750
31852
|
}
|
|
31751
31853
|
};
|
|
31752
31854
|
}
|
|
31855
|
+
/** Positive pre-dispatch refusal evidence; a missing dispatch record proves nothing by itself. */
|
|
31856
|
+
function isTerminalAdmissionRefusal(error) {
|
|
31857
|
+
const failure = error instanceof DriverAttemptsExhaustedError && error.stop === "terminal-error" ? error.cause : error;
|
|
31858
|
+
return (isCredentialRefusal(failure) || failure instanceof RetainedExecutionPendingError && failure.phase === "admission" && failure.pendingCause === "request-rejected") && classifyDriverFailure(failure) === "terminal";
|
|
31859
|
+
}
|
|
31753
31860
|
async function closeNestedScope(scope, controller, reason) {
|
|
31754
31861
|
if (!controller.signal.aborted) controller.abort(reason);
|
|
31755
31862
|
for (;;) if (await scope.next() === null) break;
|
|
@@ -32046,6 +32153,156 @@ async function runFinalizer(finalizer, args) {
|
|
|
32046
32153
|
return await accepted(candidate) ? candidate : void 0;
|
|
32047
32154
|
}
|
|
32048
32155
|
//#endregion
|
|
32156
|
+
//#region src/runtime/supervise/run-parking.ts
|
|
32157
|
+
/** Read the journal's bounded parking projection. Undefined means no current parking handoff. */
|
|
32158
|
+
async function readRunParking(runDir) {
|
|
32159
|
+
let raw;
|
|
32160
|
+
try {
|
|
32161
|
+
raw = await readFile(resolve(runDir, "parking.json"), "utf8");
|
|
32162
|
+
} catch (error) {
|
|
32163
|
+
if (error.code === "ENOENT") return void 0;
|
|
32164
|
+
throw error;
|
|
32165
|
+
}
|
|
32166
|
+
const record = JSON.parse(raw);
|
|
32167
|
+
if (record === null || typeof record !== "object") throw new Error("invalid run parking record");
|
|
32168
|
+
const data = record;
|
|
32169
|
+
if (data.status === "resuming") return void 0;
|
|
32170
|
+
if (data.status !== "parked" || typeof data.runId !== "string" || ![
|
|
32171
|
+
"seat-wait",
|
|
32172
|
+
"paused-root",
|
|
32173
|
+
"deadline"
|
|
32174
|
+
].includes(String(data.reason)) || typeof data.since !== "string" || !Number.isFinite(Date.parse(data.since)) || typeof data.wakeAt !== "string" || !Number.isFinite(Date.parse(data.wakeAt))) throw new Error("invalid run parking record");
|
|
32175
|
+
return Object.freeze({
|
|
32176
|
+
runId: data.runId,
|
|
32177
|
+
reason: data.reason,
|
|
32178
|
+
since: data.since,
|
|
32179
|
+
wakeAt: data.wakeAt
|
|
32180
|
+
});
|
|
32181
|
+
}
|
|
32182
|
+
/** A resumable wait, with no terminal result or failure. Catch it and let the coordinator exit. */
|
|
32183
|
+
var RunParkedError = class extends Error {
|
|
32184
|
+
runId;
|
|
32185
|
+
parking;
|
|
32186
|
+
constructor(runId, parking) {
|
|
32187
|
+
super(`run '${runId}' parked (${parking.reason}) until ${parking.wakeAt}`);
|
|
32188
|
+
this.runId = runId;
|
|
32189
|
+
this.parking = parking;
|
|
32190
|
+
this.name = "RunParkedError";
|
|
32191
|
+
}
|
|
32192
|
+
};
|
|
32193
|
+
const DEFAULT_PARK_AFTER_MS = 6e4;
|
|
32194
|
+
const parkingContext = new AsyncLocalStorage();
|
|
32195
|
+
const parkingDrains = /* @__PURE__ */ new WeakMap();
|
|
32196
|
+
/** Drain committed child work through the existing manager ledger before testing root idleness. */
|
|
32197
|
+
function bindScopeParkingDrain(scope, drain, idle) {
|
|
32198
|
+
parkingDrains.set(scope, {
|
|
32199
|
+
drain,
|
|
32200
|
+
idle
|
|
32201
|
+
});
|
|
32202
|
+
}
|
|
32203
|
+
/** Validate at intake, before any execution or ownership acquisition. */
|
|
32204
|
+
function assertRunParking(policy, durable) {
|
|
32205
|
+
if (policy === void 0) return;
|
|
32206
|
+
if (!durable) throw new ValidationError$1("supervise: parking requires runDir");
|
|
32207
|
+
if (policy === null || typeof policy !== "object" || policy.afterMs !== void 0 && (!Number.isFinite(policy.afterMs) || policy.afterMs < 0)) throw new ValidationError$1("supervise: parking.afterMs must be a nonnegative finite number");
|
|
32208
|
+
}
|
|
32209
|
+
/** Scope the handoff to one execution, preserving the original wake time on an early re-entry. */
|
|
32210
|
+
async function withRunParking(policy, runDir, runId, journal, now, signal, run) {
|
|
32211
|
+
if (policy === void 0 || runDir === void 0) return run();
|
|
32212
|
+
const events = await journal.loadTree(runId) ?? [];
|
|
32213
|
+
const previous = [...events].reverse().find((event) => event.kind === "run-parked");
|
|
32214
|
+
const transition = [...events].reverse().find((event) => event.id === runId && (event.kind === "run-parked" || event.kind === "root-reentered" || event.kind === "reopened"));
|
|
32215
|
+
const current = transition?.kind === "run-parked" ? transition : void 0;
|
|
32216
|
+
if (current !== void 0 && Date.parse(current.wakeAt) > now() && !signal?.aborted) {
|
|
32217
|
+
await writeParkingProjection(runDir, runId, current);
|
|
32218
|
+
throw new RunParkedError(runId, parkingRecordOf(current));
|
|
32219
|
+
}
|
|
32220
|
+
if (previous !== void 0) await writeAtomicDurableFile(resolve(runDir, "parking.json"), JSON.stringify({
|
|
32221
|
+
status: "resuming",
|
|
32222
|
+
runId,
|
|
32223
|
+
...parkingRecordOf(previous),
|
|
32224
|
+
resumedAt: new Date(now()).toISOString()
|
|
32225
|
+
}));
|
|
32226
|
+
return parkingContext.run({
|
|
32227
|
+
runDir,
|
|
32228
|
+
runId,
|
|
32229
|
+
journal,
|
|
32230
|
+
now,
|
|
32231
|
+
afterMs: policy.afterMs ?? DEFAULT_PARK_AFTER_MS
|
|
32232
|
+
}, run);
|
|
32233
|
+
}
|
|
32234
|
+
/**
|
|
32235
|
+
* Sleep through the existing wait path. A root with no live descendants may hand off after its
|
|
32236
|
+
* idle threshold; children and roots with active work keep their normal wait. No timer survives
|
|
32237
|
+
* the handoff, and no provider work is cancelled or terminal settlement written for parking.
|
|
32238
|
+
*/
|
|
32239
|
+
async function sleepScopeWait(scope, ms, signal, reason) {
|
|
32240
|
+
if (ms <= 0 || signal.aborted) return;
|
|
32241
|
+
const context = parkingContext.getStore();
|
|
32242
|
+
const onlyRootWait = () => context !== void 0 && scope.view.root === context.runId && parkingDrains.get(scope)?.idle() !== false && scope.workerCapacity.unconfirmed.length === 0 && !(scope.observeTree?.() ?? scope.view).nodes.some((node) => node.id !== context.runId && isLiveNodeStatus(node.status));
|
|
32243
|
+
if (context === void 0 || scope.view.root !== context.runId || ms <= context.afterMs) return sleep(ms, signal, false);
|
|
32244
|
+
const since = context.now();
|
|
32245
|
+
const deadline = scope.budget.deadlineMs;
|
|
32246
|
+
const wakeAt = Math.min(since + ms, deadline > 0 ? deadline : Number.POSITIVE_INFINITY);
|
|
32247
|
+
if (wakeAt - since <= context.afterMs) return sleep(ms, signal, false);
|
|
32248
|
+
let idleSince = onlyRootWait() ? since : void 0;
|
|
32249
|
+
for (;;) {
|
|
32250
|
+
const remaining = Math.max(0, wakeAt - context.now());
|
|
32251
|
+
if (remaining <= context.afterMs) return sleep(remaining, signal, false);
|
|
32252
|
+
const checkMs = context.afterMs || (idleSince === void 0 ? DEFAULT_PARK_AFTER_MS : 0);
|
|
32253
|
+
await sleep(Math.min(checkMs, remaining), signal, false);
|
|
32254
|
+
if (signal.aborted) return;
|
|
32255
|
+
await parkingDrains.get(scope)?.drain();
|
|
32256
|
+
if (!onlyRootWait()) {
|
|
32257
|
+
idleSince = void 0;
|
|
32258
|
+
continue;
|
|
32259
|
+
}
|
|
32260
|
+
if (idleSince === void 0) {
|
|
32261
|
+
idleSince = context.now();
|
|
32262
|
+
continue;
|
|
32263
|
+
}
|
|
32264
|
+
if (context.now() - idleSince < context.afterMs) continue;
|
|
32265
|
+
const events = await context.journal.loadTree(context.runId) ?? [];
|
|
32266
|
+
if (signal.aborted) return;
|
|
32267
|
+
const ownerEvents = events.filter((event) => event.id === context.runId);
|
|
32268
|
+
const input = [...ownerEvents].reverse().find((event) => event.kind === "execution-input");
|
|
32269
|
+
const invocation = input === void 0 ? [] : ownerEvents.slice(ownerEvents.indexOf(input));
|
|
32270
|
+
if (invocation.some((event) => event.kind === "execution-admitted") && !invocation.some((event) => event.kind === "execution-result" || event.kind === "execution-abandoned" && event.outcome === "stopped") || !onlyRootWait()) {
|
|
32271
|
+
idleSince = void 0;
|
|
32272
|
+
continue;
|
|
32273
|
+
}
|
|
32274
|
+
const parking = {
|
|
32275
|
+
reason: deadline > 0 && wakeAt === deadline ? "deadline" : reason,
|
|
32276
|
+
since: new Date(idleSince).toISOString(),
|
|
32277
|
+
wakeAt: new Date(wakeAt).toISOString()
|
|
32278
|
+
};
|
|
32279
|
+
closeScopeAdmission(scope);
|
|
32280
|
+
await context.journal.appendEvent(context.runId, {
|
|
32281
|
+
kind: "run-parked",
|
|
32282
|
+
id: context.runId,
|
|
32283
|
+
...parking,
|
|
32284
|
+
seq: events.filter((event) => event.kind === "run-parked").length,
|
|
32285
|
+
at: new Date(context.now()).toISOString()
|
|
32286
|
+
});
|
|
32287
|
+
await writeParkingProjection(context.runDir, context.runId, parking);
|
|
32288
|
+
throw new RunParkedError(context.runId, parking);
|
|
32289
|
+
}
|
|
32290
|
+
}
|
|
32291
|
+
async function writeParkingProjection(runDir, runId, parking) {
|
|
32292
|
+
await writeAtomicDurableFile(resolve(runDir, "parking.json"), JSON.stringify({
|
|
32293
|
+
status: "parked",
|
|
32294
|
+
runId,
|
|
32295
|
+
...parkingRecordOf(parking)
|
|
32296
|
+
}));
|
|
32297
|
+
}
|
|
32298
|
+
function parkingRecordOf(record) {
|
|
32299
|
+
return {
|
|
32300
|
+
reason: record.reason,
|
|
32301
|
+
since: record.since,
|
|
32302
|
+
wakeAt: record.wakeAt
|
|
32303
|
+
};
|
|
32304
|
+
}
|
|
32305
|
+
//#endregion
|
|
32049
32306
|
//#region src/durable/spawn-journal/provider-model-evidence.ts
|
|
32050
32307
|
/**
|
|
32051
32308
|
* Aggregate provider-served model evidence across one recursively owned journal forest.
|
|
@@ -32675,7 +32932,7 @@ async function recordRootSegment(opts, events, at, fresh) {
|
|
|
32675
32932
|
}
|
|
32676
32933
|
/**
|
|
32677
32934
|
* Append one `root-reentered` record: this process is supervising a run an earlier process drove.
|
|
32678
|
-
*
|
|
32935
|
+
* After a host reboot the re-entered root ran two
|
|
32679
32936
|
* barren continuations and the run settled `no-result-selected`, with three workers still open in
|
|
32680
32937
|
* the journal and no record that a restart had happened.
|
|
32681
32938
|
*/
|
|
@@ -32874,7 +33131,7 @@ async function joinRunChildren(join, settleGraceMs) {
|
|
|
32874
33131
|
}
|
|
32875
33132
|
/**
|
|
32876
33133
|
* A first teardown that failed or answered late is not the provider's last word, and a run that
|
|
32877
|
-
* settles over it leaves the sandbox running:
|
|
33134
|
+
* settles over it leaves the sandbox running: cancelling 20 Discovery lanes
|
|
32878
33135
|
* left 2 workers running. Ask again until confirmed or out of time.
|
|
32879
33136
|
*/
|
|
32880
33137
|
async function confirmRetriableTeardowns(join, releasing) {
|
|
@@ -33192,6 +33449,7 @@ async function executeRoot(root) {
|
|
|
33192
33449
|
};
|
|
33193
33450
|
let executionAborted = controller.signal.aborted;
|
|
33194
33451
|
let allChildrenDownAtSettle = false;
|
|
33452
|
+
let parked = false;
|
|
33195
33453
|
try {
|
|
33196
33454
|
await startScopeRecoveries(scope);
|
|
33197
33455
|
actOutcome = {
|
|
@@ -33199,6 +33457,10 @@ async function executeRoot(root) {
|
|
|
33199
33457
|
out: await runAbortable(root.run, controller.signal, "supervisor aborted")
|
|
33200
33458
|
};
|
|
33201
33459
|
} catch (error) {
|
|
33460
|
+
if (error instanceof RunParkedError && error.runId === opts.runId) {
|
|
33461
|
+
parked = true;
|
|
33462
|
+
throw error;
|
|
33463
|
+
}
|
|
33202
33464
|
actOutcome = {
|
|
33203
33465
|
ok: false,
|
|
33204
33466
|
error
|
|
@@ -33209,26 +33471,31 @@ async function executeRoot(root) {
|
|
|
33209
33471
|
allChildrenDownAtSettle = allSpawnedChildrenDown(runTree(scope));
|
|
33210
33472
|
if (!controller.signal.aborted && deadline.atMs > 0 && now() >= deadline.atMs) deadline.exceeded = true;
|
|
33211
33473
|
deadline.clear();
|
|
33212
|
-
|
|
33213
|
-
|
|
33214
|
-
|
|
33215
|
-
|
|
33216
|
-
|
|
33217
|
-
ok
|
|
33218
|
-
|
|
33219
|
-
|
|
33220
|
-
|
|
33221
|
-
|
|
33222
|
-
|
|
33223
|
-
|
|
33224
|
-
|
|
33225
|
-
ok
|
|
33226
|
-
|
|
33227
|
-
|
|
33228
|
-
|
|
33229
|
-
|
|
33230
|
-
|
|
33231
|
-
|
|
33474
|
+
if (!parked) {
|
|
33475
|
+
const settleGraceMs = !controller.signal.aborted ? boundedSettleGrace(opts.childSettleGraceMs, deadline.atMs, now) : 0;
|
|
33476
|
+
try {
|
|
33477
|
+
await joinRunChildren(join, settleGraceMs);
|
|
33478
|
+
} catch (error) {
|
|
33479
|
+
if (actOutcome?.ok !== false) actOutcome = {
|
|
33480
|
+
ok: false,
|
|
33481
|
+
error
|
|
33482
|
+
};
|
|
33483
|
+
}
|
|
33484
|
+
if (!persistence.failed) try {
|
|
33485
|
+
await finalizeScopeOwnerMaterialization(scope);
|
|
33486
|
+
} catch (error) {
|
|
33487
|
+
if (actOutcome?.ok !== false) actOutcome = {
|
|
33488
|
+
ok: false,
|
|
33489
|
+
error
|
|
33490
|
+
};
|
|
33491
|
+
}
|
|
33492
|
+
if (persistence.failed) {
|
|
33493
|
+
await waitForScopeChildren(scope);
|
|
33494
|
+
await persistence.drain();
|
|
33495
|
+
}
|
|
33496
|
+
} else {
|
|
33497
|
+
await scopeRetainedOwnerCheckpointing(scope);
|
|
33498
|
+
await scopeRetainedOwnerSettled(scope);
|
|
33232
33499
|
}
|
|
33233
33500
|
executionAborted ||= cascade.aborted();
|
|
33234
33501
|
cascade.detach();
|
|
@@ -33318,6 +33585,6 @@ async function noWinner(settled, rejection) {
|
|
|
33318
33585
|
};
|
|
33319
33586
|
}
|
|
33320
33587
|
//#endregion
|
|
33321
|
-
export {
|
|
33588
|
+
export { resolveSpawnResourcePaths as $, mapSandboxToolEvent as $i, HarnessTurnFailedError as $n, sandboxProfileMaterialization as $r, providerAsSandboxClient as $t, beginScopeOwnerAttempt as A, cappedDoublingMs as Ai, toOtelAttributes as An, readCodexRolloutSession as Ar, createExecutor as At, assertRecursiveReservationPolicy as B, executorFailure as Bi, PEER_MAIL_WIRE_KEY as Bn, LOCAL_HARNESSES as Br, TERMINAL_DECISIONS as Bt, interactiveAdmissionSeamKey as C, projectSandboxOutcome as Ci, createOpenInferenceFileExporter as Cn, bridgeAdmissionRefusal as Cr, readCommittedJsonLines as Ct, recoverRetainedInteractiveRun as D, RetainedExecutionPendingError as Di, loopEventToOtelSpan as Dn, addHarnessUsage as Dr, createExecutorRegistry as Dt, reconnectRetainedInteractiveRun as E, settlementFailureCause as Ei, generateSpanId as En, ROUTER_PRICE_SOURCE as Er, insideCursorNamespace as Et, coordinationMcpAlias as F, TRACE_ROOT_SCHEMA as Fi, INBOX_RECEIPT_KEY as Fn, signalAbortError as Fr, assertBoxlessPromptOptions as Ft, meterRuntimeOwnedAccounting as G, spendFromUsageEvents as Gi, peerMailVerbNames as Gn, controlProfileMaterialization as Gr, runCodeMode as Gt, freeSlots as H, createBudgetPool as Hi, createPeerMailbox as Hn, terminateProcessTreeAndConfirm as Hr, codeModeArguments as Ht, coordinationProfileToolPrefix as I, TRACE_SUMMARY_SCHEMA as Ii, createInbox as In, bridgeRuntimeAttachmentsKey as Ir, readPromptOptions as It, recordScopeOwnerDriverAttempt as J, defaultRedactor as Ji, createActivityLog as Jn, profileMaterializationAxes$1 as Jr, routerBrain as Jt, meterRuntimeOwnedProviderAttempt as K, spendFromUsageTotals as Ki, taskToPrompt$1 as Kn, defineProfileMaterializationContract as Kr, toolResultText as Kt, providerVisibleProfile as L, detachedFrozen as Li, failPendingAfter as Ln, bridgeStopSignalKey as Lr, createSandboxForSpec as Lt, recordScopeOwnerMaterialization as M, unavailablePauseMs as Mi, createRuntimeStreamEventCollector as Mn, RunCancellationReason as Mr, DEFAULT_SANDBOX_STEERING_MAX_TURNS as Mt, restoreScopeOwnerAcceptedExecution as N, unavailableResumeAt as Ni, sanitizeKnowledgeReadinessReport as Nn, linkAbort as Nr, createSteerableSandboxSession as Nt, startRetainedInteractiveRun as O, registerRetainedExecutorPreparation as Oi, padSpanId as On, createCodexRolloutStoreReader as Or, bindReusableExecutorExecutionId as Ot, scopeOwnerExecutorNodeContext as P, unavailableSignalOfFailure as Pi, sanitizeRuntimeStreamEvent as Pn, runAbortable as Pr, runAgentRounds as Pt, environmentReader as Q, mapSandboxEvent as Qi, DriverAttemptsExhaustedError as Qn, sandboxActProfileMaterialization as Qr, LEAF_CONTINUATION_TASK as Qt, runtimeGraphMetadataKey as R, detachedSnapshot as Ri, AUTHORITY_MARKERS as Rn, runSettledCommand as Rr, createSandboxLineage as Rt, workerTraceAnalysisStore as S, executableAgentSpecSnapshot as Si, buildRuntimeEventOtelSpans as Sn, isFiniteNumber as Sr, readCommittedJsonFile as St, readWorkerInteractiveBinding as T, runtimeFailureCause as Ti, flatOtelSpan as Tn, priceTokens as Tr, withJsonlFileLock as Tt, queueOf as U, meterUsageEvent as Ui, isPeerMailEnvelope as Un, assertProfileMaterialization as Ur, codeModeModelOutput as Ut, deriveNodeExecutionIdentity as V, errMessage as Vi, claimsAuthority as Vn, harnessInvocation as Vr, defaultSelectWinner as Vt, rollingDispatch as W, newUsageTotals as Wi, peerMailTools as Wn, assertProfileMaterializes as Wr, createCodeModeTools as Wt, prepareScopeRetainedOwnerSeatSwitch as X, resolveRedactor as Xi, isLiveNodeStatus as Xn, promptModelProfileMaterialization as Xr, resolveAgentEnvironmentProvider as Xt, recordScopeOwnerPause as Y, defaultRedactorIdentityMaterial as Yi, readWorkerProgress as Yn, promptControlProfileMaterialization as Yr, createAgentEnvironmentProviderRegistry as Yt, scopeRetainedOwnerResourceReader as Z, createSandboxToolPartState as Zi, isTerminalNodeStatus as Zn, renderUnsupported as Zr, providerAsExecutor as Zt, withDriverExecutor as _, runtimeOwnedPendingExecutorMaterialization as _i, WORKER_TRACE_PROPAGATION as _n, admitContinuationPolicy as _r, InMemorySpawnJournal as _t, assertRunParking as a, notifySandboxEventObserver as aa, authoredProfileDigest as ai, destroyInteractiveEnvironment as an, upstreamUnavailableSignal as ar, beginScopeRetainedOwnerDrive as at, isTraceAnalysisStore as b, unknownMaterializationReceipt as bi, buildLoopOtelSpans as bn, createContinuationKeeper as br, isNoEntError as bt, sleepScopeWait as c, awaitAbortable$1 as ca, knownExecutionBindingReceipt as ci, harnessTranscriptArtifact as cn, authoredSeatStages as cr, scopeRetainedOwnerRestorePoint as ct, runFinalizer as d, providerMessageText as da, providerAttemptEvidence as di, resolveHarnessTranscriptCapture as dn, CheckUnavailableError as dr, bindScopeRetainedOwnerProvider as dt, terminalTextFromSandboxEvent as ea, unsupportedProfileDimensions as ei, reconnectRetainedRun as en, abandonablePending as er, abandonScopeRetainedOwnerInvocation as et, runTree as f, recordRuntimeOwnedDriveHarnessProviderEvidence as fi, retainHarnessTranscript as fn, gateFactoryOnDeliverable as fr, scopeRetainedOwnerContext as ft, isDriverSpec as g, runtimeOwnedExecutorProviderEvidence as gi, createInPlaceCliExecutor as gn, CONTINUATIONS_DIR as gr, InMemoryResultBlobStore as gt, driverExecutorFactory as h, runtimeOwnedExecutorMaterialization as hi, createWorktreeCliExecutor as hn, verdictFromJudgeScore as hr, materializeTreeView as ht, RunParkedError as i, extractLlmCallEvent as ia, authoredAgentIdentity as ii, retainedCreateMaterial as in, undispatchedCredentialExit as ir, scopeRetainedOwnerResult as it, noteScopeOwnerPlannedExecution as j, jitteredMs as ji, createRuntimeEventCollector as jn, createPushTraceSource as jr, snapshotExecutorConfig as jt, FileSpawnJournal as k, retainedExecutorSeamKey as ki, padTraceId as kn, harnessUsageIsEmpty as kr, captureReusableExecutorConfig as kt, withRunParking as l, promptFromAgentTurnInput as la, knownMaterializationReceipt as li, persistHarnessTranscript as ln, seatExecutionProfile as lr, noteScopeRetainedOwnerCoordination as lt, driverChild as m, runtimeOwnedExecutorExecutionBinding as mi, openSlotGroup as mn, mapExecutorResult as mr, loadSpawnForest as mt, createSupervisor as n, createSandboxTurnEventCollector as na, attestRuntimeOwnedPendingExecutor as ni, startRetainedRun as nn, classifyDriverFailure as nr, prepareScopeRetainedOwnerTask as nt, bindScopeParkingDrain as o, sumSandboxUsage as oa, finalizeRuntimeOwnedPendingExecutor as oi, environmentGone as on, SeatChain as or, scopeRetainedOwnerTurnEnded as ot, createRootHandle as p, runtimeOwnedDriveHarnessProviderEvidence as pi, createWorkerSlots as pn, gateOnDeliverable as pr, scopeRetainedOwnerJournalRoot as pt, recordScopeOwnerBarrenPause as q, assertValidBudget as qi, DEFAULT_STALL_AFTER_MS as qn, fullProfileMaterialization as qr, createRouterTranscript as qt, assertResumeLimits as r, createSandboxUsageLedger as ra, attestRuntimeOwnedScopeOwner as ri, startRetainedRunInEnvironment as rn, summarizeDriverAttempts as rr, scopeRetainedOwnerPriorSpend as rt, readRunParking as s, decodeHarnessUsage as sa, inheritRuntimeOwnedExecutorAttestation as si, captureHarnessTranscript as sn, SeatChainExhaustedError as sr, reconcileScopeRetainedOwnerEnvironment as st, DEFAULT_MAX_DEPTH as t, canonicalStreamEventFromSandboxEvent as ta, worktreeCliProfileMaterialization as ti, recoverRetainedRun as tn, causedByPartialFailure as tr, consumeScopeRetainedOwnerResult as tt, bestDelivered as u, promptOptionsFromAgentTurnInput as ua, newExecutionAttemptId as ui, readHarnessTranscript as un, subscriptionUsageLimitSignal as ur, bindScopeRetainedOwnerEnvironmentId as ut, createScope as v, runtimeOwnedScopeOwnerRuntime as vi, createPropagatingTraceEmitter as vn, bestComposite as vr, FileResultBlobStore as vt, attachWorker as w, readSandboxOutcome as wi, createOtelExporter as wn, bridgeModelRouteRefusal as wr, upsertCommittedJsonLine as wt, parseWorkerToolTraceArtifact as x, executableAgentProfileSnapshot as xi, buildLoopSpanNodes as xn, failedItems as xr, prepareJsonlAppend as xt, replaySpawnTree as y, unknownExecutionBindingReceipt as yi, readTraceContextFromEnv as yn, checkVerdictOf as yr, appendCommittedJsonLine as yt, settledToIteration as z, contentAddress as zi, DEFAULT_PEER_MAIL_LIMITS as zn, runWorktreeHarness as zr, acquireSandbox as zt };
|
|
33322
33589
|
|
|
33323
|
-
//# sourceMappingURL=supervisor-
|
|
33590
|
+
//# sourceMappingURL=supervisor-wS9Ehz_x.js.map
|