@tangle-network/agent-runtime 0.91.0 → 0.92.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/agent.d.ts +3 -3
- package/dist/agent.js +106 -25
- package/dist/agent.js.map +1 -1
- package/dist/{mcp-serve-verifier-XsX8rkB9.d.ts → agentic-generator-B8oeE2Yv.d.ts} +6 -33
- package/dist/analyst-loop.d.ts +1 -1
- package/dist/candidate-execution/index.d.ts +104 -0
- package/dist/candidate-execution/index.js +34 -0
- package/dist/candidate-execution/index.js.map +1 -0
- package/dist/chunk-3D2RHC4K.js +73 -0
- package/dist/chunk-3D2RHC4K.js.map +1 -0
- package/dist/chunk-3MDZX7YU.js +125 -0
- package/dist/chunk-3MDZX7YU.js.map +1 -0
- package/dist/chunk-4FPXIMSI.js +659 -0
- package/dist/chunk-4FPXIMSI.js.map +1 -0
- package/dist/chunk-6O73TRHW.js +142 -0
- package/dist/chunk-6O73TRHW.js.map +1 -0
- package/dist/chunk-A62TP7SK.js +4784 -0
- package/dist/chunk-A62TP7SK.js.map +1 -0
- package/dist/{chunk-AD7JW4QG.js → chunk-BVVRQ4YC.js} +23 -1231
- package/dist/chunk-BVVRQ4YC.js.map +1 -0
- package/dist/chunk-FDJ7AHXG.js +1229 -0
- package/dist/chunk-FDJ7AHXG.js.map +1 -0
- package/dist/{chunk-FF77IBQM.js → chunk-FRBHUNQ7.js} +2 -141
- package/dist/chunk-FRBHUNQ7.js.map +1 -0
- package/dist/chunk-J2K6WIG6.js +2172 -0
- package/dist/chunk-J2K6WIG6.js.map +1 -0
- package/dist/{chunk-JRS3YSRZ.js → chunk-LQQPGRKT.js} +2 -2
- package/dist/{chunk-IOUUITQA.js → chunk-P6B3Z7PR.js} +3 -3
- package/dist/chunk-PH65PR4F.js +860 -0
- package/dist/chunk-PH65PR4F.js.map +1 -0
- package/dist/{chunk-7ON74BQO.js → chunk-R5GWDTM3.js} +2 -2
- package/dist/{chunk-DWWII6N2.js → chunk-TKJ3Q6CQ.js} +2 -2
- package/dist/{chunk-NC66AM3S.js → chunk-UO2L5VTP.js} +32 -1413
- package/dist/chunk-UO2L5VTP.js.map +1 -0
- package/dist/{chunk-BZF3KQ6G.js → chunk-VSWBYWFK.js} +4 -122
- package/dist/chunk-VSWBYWFK.js.map +1 -0
- package/dist/{completion-gate-DkAnUmpb.d.ts → completion-gate-BLaiN0-X.d.ts} +1 -1
- package/dist/{coordination-rRj5hjJK.d.ts → coordination-DxJ83oZA.d.ts} +12 -5
- package/dist/environment-provider.d.ts +2 -2
- package/dist/environment-provider.js +2 -1
- package/dist/improve-CUVCq7xg.d.ts +152 -0
- package/dist/{improvement-adapter-CDR8QNVM.d.ts → improvement-adapter-BieWeK5J.d.ts} +16 -0
- package/dist/index.d.ts +27 -1092
- package/dist/index.js +108 -6491
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +160 -13
- package/dist/intelligence.js +534 -59
- package/dist/intelligence.js.map +1 -1
- package/dist/knowledge.d.ts +6 -6
- package/dist/knowledge.js +6 -4
- package/dist/lifecycle.d.ts +2 -1
- package/dist/lifecycle.js +5 -3
- package/dist/lifecycle.js.map +1 -1
- package/dist/{loop-runner-bin-DTbZVGfM.d.ts → loop-runner-bin-kKUNGLyV.d.ts} +2 -2
- package/dist/loop-runner-bin.d.ts +5 -5
- package/dist/loop-runner-bin.js +8 -5
- package/dist/loops.d.ts +16 -16
- package/dist/loops.js +47 -41
- package/dist/mcp/bin.js +6 -4
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +8 -8
- package/dist/mcp/index.js +9 -6
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp-serve-verifier-Bg4C3p5S.d.ts +34 -0
- package/dist/{openai-tools-C4ZfUD4L.d.ts → openai-tools-E3woykz9.d.ts} +1 -1
- package/dist/prepare-Z08a4heC.d.ts +713 -0
- package/dist/profiles.d.ts +1 -1
- package/dist/{router-client-DJImUDlm.d.ts → sanitize-C9go6tXj.d.ts} +113 -1
- package/dist/{structural-rollout-MwlpgQ-6.d.ts → structural-rollout-DHGDbhvR.d.ts} +3 -3
- package/dist/{supervise-DPmYPk0j.d.ts → supervise-T2pazU3G.d.ts} +4 -4
- package/dist/{types-SyuwunY_.d.ts → types-B00NtbCs.d.ts} +1 -1
- package/dist/{types-eMNgWgFi.d.ts → types-DAdIm4AC.d.ts} +1 -1
- package/dist/{worktree-fanout-BDFQIO-Y.d.ts → worktree-fanout-BUb2Ag02.d.ts} +3 -3
- package/package.json +11 -6
- package/skills/build-with-agent-runtime/SKILL.md +1 -1
- package/dist/chunk-AD7JW4QG.js.map +0 -1
- package/dist/chunk-BZF3KQ6G.js.map +0 -1
- package/dist/chunk-FF77IBQM.js.map +0 -1
- package/dist/chunk-IVGYLCFH.js +0 -381
- package/dist/chunk-IVGYLCFH.js.map +0 -1
- package/dist/chunk-NC66AM3S.js.map +0 -1
- /package/dist/{chunk-JRS3YSRZ.js.map → chunk-LQQPGRKT.js.map} +0 -0
- /package/dist/{chunk-IOUUITQA.js.map → chunk-P6B3Z7PR.js.map} +0 -0
- /package/dist/{chunk-7ON74BQO.js.map → chunk-R5GWDTM3.js.map} +0 -0
- /package/dist/{chunk-DWWII6N2.js.map → chunk-TKJ3Q6CQ.js.map} +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FileAgentCandidateExecutionClaimStore,
|
|
3
|
+
createProtectedAgentCandidateModelPort,
|
|
4
|
+
disposePreparedAgentCandidateExecution,
|
|
5
|
+
recoverExpiredAgentCandidateExecution
|
|
6
|
+
} from "../chunk-PH65PR4F.js";
|
|
7
|
+
import {
|
|
8
|
+
CANDIDATE_TRACE_ENV,
|
|
9
|
+
CANDIDATE_TRACE_TAGS,
|
|
10
|
+
InMemoryAgentCandidateExecutionClaimStore,
|
|
11
|
+
candidateExecutionClaim,
|
|
12
|
+
executePreparedAgentCandidate,
|
|
13
|
+
persistCandidateOutputArtifact,
|
|
14
|
+
prepareAgentCandidateExecution,
|
|
15
|
+
verifyAgentCandidateBundle
|
|
16
|
+
} from "../chunk-A62TP7SK.js";
|
|
17
|
+
import "../chunk-3D2RHC4K.js";
|
|
18
|
+
import "../chunk-3MDZX7YU.js";
|
|
19
|
+
import "../chunk-DGUM43GV.js";
|
|
20
|
+
export {
|
|
21
|
+
CANDIDATE_TRACE_ENV,
|
|
22
|
+
CANDIDATE_TRACE_TAGS,
|
|
23
|
+
FileAgentCandidateExecutionClaimStore,
|
|
24
|
+
InMemoryAgentCandidateExecutionClaimStore,
|
|
25
|
+
candidateExecutionClaim,
|
|
26
|
+
createProtectedAgentCandidateModelPort,
|
|
27
|
+
disposePreparedAgentCandidateExecution,
|
|
28
|
+
executePreparedAgentCandidate,
|
|
29
|
+
persistCandidateOutputArtifact,
|
|
30
|
+
prepareAgentCandidateExecution,
|
|
31
|
+
recoverExpiredAgentCandidateExecution,
|
|
32
|
+
verifyAgentCandidateBundle
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/durable/spawn-journal.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
function contentAddress(artifact) {
|
|
4
|
+
const hex = createHash("sha256").update(stableStringify(artifact), "utf-8").digest("hex");
|
|
5
|
+
return `sha256:${hex}`;
|
|
6
|
+
}
|
|
7
|
+
function stableStringify(value) {
|
|
8
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
9
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
10
|
+
const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
11
|
+
return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
|
|
12
|
+
}
|
|
13
|
+
var InMemoryResultBlobStore = class {
|
|
14
|
+
blobs = /* @__PURE__ */ new Map();
|
|
15
|
+
async put(outRef, artifact) {
|
|
16
|
+
assertContentAddress(outRef, artifact);
|
|
17
|
+
this.blobs.set(outRef, artifact);
|
|
18
|
+
}
|
|
19
|
+
async get(outRef) {
|
|
20
|
+
return this.blobs.has(outRef) ? this.blobs.get(outRef) : void 0;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function assertContentAddress(outRef, artifact) {
|
|
24
|
+
const expected = contentAddress(artifact);
|
|
25
|
+
if (outRef !== expected) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`blob outRef '${outRef}' does not match the artifact content hash '${expected}'; a content-addressed store refuses a mismatched ref (breaks the replay invariant)`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
var InMemorySpawnJournal = class {
|
|
32
|
+
trees = /* @__PURE__ */ new Map();
|
|
33
|
+
async loadTree(root) {
|
|
34
|
+
const tree = this.trees.get(root);
|
|
35
|
+
if (!tree) return void 0;
|
|
36
|
+
return tree.events.map((ev) => ({ ...ev }));
|
|
37
|
+
}
|
|
38
|
+
async beginTree(root, at) {
|
|
39
|
+
const existing = this.trees.get(root);
|
|
40
|
+
if (existing) {
|
|
41
|
+
if (existing.begunAt !== at) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`spawn tree '${root}' already begun at ${existing.begunAt}; refusing to overwrite with ${at}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.trees.set(root, { begunAt: at, events: [] });
|
|
49
|
+
}
|
|
50
|
+
async appendEvent(root, ev) {
|
|
51
|
+
const tree = this.trees.get(root);
|
|
52
|
+
if (!tree) {
|
|
53
|
+
throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`);
|
|
54
|
+
}
|
|
55
|
+
assertSeqUnique(root, tree.events, ev);
|
|
56
|
+
tree.events.push({ ...ev });
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function assertSeqUnique(root, events, ev) {
|
|
60
|
+
if (ev.kind === "spawned" || ev.kind === "metered") return;
|
|
61
|
+
if (events.some((e) => e.kind !== "spawned" && e.kind !== "metered" && e.seq === ev.seq)) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`spawn journal corrupted: duplicate cursor seq ${ev.seq} in tree '${root}'; the cursor order replay relies on is not unique`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export {
|
|
69
|
+
contentAddress,
|
|
70
|
+
InMemoryResultBlobStore,
|
|
71
|
+
InMemorySpawnJournal
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=chunk-3D2RHC4K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/durable/spawn-journal.ts"],"sourcesContent":["/**\n *\n * Event-sourced spawn journal for the recursive execution atom (build steps 3 + 7).\n *\n * The supervision tree is journaled as an append-only event log: every `spawned`,\n * `settled`, and `cancelled` is recorded AFTER it is observed-committed (never\n * speculative), mirroring `ConversationJournal`'s begin/append/load shape. The log\n * holds only the THIN decision record — ids, parentage, budget, the spend a decision\n * consumed, and a content-addressed `outRef`. The payloads the driver branched on\n * (the `out` artifacts) live in a separate `ResultBlobStore`, keyed by `outRef`, so\n * the journal stays small (decisions) and replay rehydrates the exact `Settled` from\n * the blob store (evidence). This is the decision/payload split the replay argument\n * rests on (B1/B2).\n *\n * Replay determinism (B2): `seq` is the monotonic cursor order `scope.next()` yielded\n * each settlement — NOT wall-clock. `replaySpawnTree` sorts strictly by `seq` before\n * touching the blob store, so the order in which rehydration `get`s resolve can never\n * reorder the replayed `Settled[]`; the result is identical regardless of blob latency.\n *\n * @experimental\n */\n\nimport { createHash } from 'node:crypto'\nimport type {\n NodeId,\n NodeSnapshot,\n NodeStatus,\n ResultBlobStore,\n Runtime,\n Settled,\n SpawnEvent,\n SpawnJournal,\n Spend,\n TreeView,\n} from '../runtime/supervise/types'\nimport { zeroTokenUsage } from '../runtime/util'\n\n// ── Content addressing ──────────────────────────────────────────────────────\n\n/**\n * Mint the content-addressed `outRef` for a result artifact: `sha256:<hex>` over a\n * stable JSON encoding. Producers call this to derive the `outRef` they journal and\n * `put`; the FS/in-mem stores re-derive it on `put` to verify the supplied ref\n * matches (fail loud on a mismatch — a forged ref breaks the replay invariant).\n *\n * Stable encoding: object keys are sorted recursively so two structurally-equal\n * artifacts hash identically regardless of key insertion order.\n */\nexport function contentAddress(artifact: unknown): string {\n const hex = createHash('sha256').update(stableStringify(artifact), 'utf-8').digest('hex')\n return `sha256:${hex}`\n}\n\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'null'\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(',')}}`\n}\n\n// ── Result blob store ─────────────────────────────────────────────────────────\n\n/**\n * In-memory `ResultBlobStore`. Content-addressed: `put` verifies the supplied\n * `outRef` matches the artifact's hash so a stale/forged ref fails loud rather than\n * silently rehydrating the wrong payload. Idempotent on an identical re-put.\n */\nexport class InMemoryResultBlobStore implements ResultBlobStore {\n private readonly blobs = new Map<string, unknown>()\n\n async put(outRef: string, artifact: unknown): Promise<void> {\n assertContentAddress(outRef, artifact)\n this.blobs.set(outRef, artifact)\n }\n\n async get(outRef: string): Promise<unknown | undefined> {\n return this.blobs.has(outRef) ? this.blobs.get(outRef) : undefined\n }\n}\n\n/**\n * FS `ResultBlobStore`. One JSON file per artifact under `dir`, named by a\n * filesystem-safe encoding of the `outRef` (`sha256:<hex>` → `sha256-<hex>.json`).\n * `put` fsyncs so a crash between writes never loses an acknowledged blob.\n */\nexport class FileResultBlobStore implements ResultBlobStore {\n constructor(private readonly dir: string) {}\n\n async put(outRef: string, artifact: unknown): Promise<void> {\n assertContentAddress(outRef, artifact)\n const fs = await import('node:fs/promises')\n await fs.mkdir(this.dir, { recursive: true })\n const fh = await fs.open(this.blobPath(outRef), 'w')\n try {\n await fh.write(JSON.stringify(artifact))\n await fh.sync()\n } finally {\n await fh.close()\n }\n }\n\n async get(outRef: string): Promise<unknown | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.blobPath(outRef), 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n return JSON.parse(text)\n }\n\n private blobPath(outRef: string): string {\n return `${this.dir}/${outRef.replace(/:/g, '-')}.json`\n }\n}\n\nfunction assertContentAddress(outRef: string, artifact: unknown): void {\n const expected = contentAddress(artifact)\n if (outRef !== expected) {\n throw new Error(\n `blob outRef '${outRef}' does not match the artifact content hash '${expected}'; ` +\n 'a content-addressed store refuses a mismatched ref (breaks the replay invariant)',\n )\n }\n}\n\n// ── Spawn journal ──────────────────────────────────────────────────────────────\n\n/**\n * In-memory `SpawnJournal`. Appends are observed-committed only; the impl enforces\n * the corruption guards a durable replay rests on:\n * - an event before `beginTree` is a corrupted tree (fail loud),\n * - a duplicate `seq` within a tree is a corrupted cursor (fail loud) — two\n * settlements cannot share the cursor position replay orders by.\n */\nexport class InMemorySpawnJournal implements SpawnJournal {\n private readonly trees = new Map<NodeId, { begunAt: string; events: SpawnEvent[] }>()\n\n async loadTree(root: NodeId): Promise<SpawnEvent[] | undefined> {\n const tree = this.trees.get(root)\n if (!tree) return undefined\n return tree.events.map((ev) => ({ ...ev }))\n }\n\n async beginTree(root: NodeId, at: string): Promise<void> {\n const existing = this.trees.get(root)\n if (existing) {\n if (existing.begunAt !== at) {\n throw new Error(\n `spawn tree '${root}' already begun at ${existing.begunAt}; refusing to overwrite with ${at}`,\n )\n }\n return\n }\n this.trees.set(root, { begunAt: at, events: [] })\n }\n\n async appendEvent(root: NodeId, ev: SpawnEvent): Promise<void> {\n const tree = this.trees.get(root)\n if (!tree) {\n throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`)\n }\n assertSeqUnique(root, tree.events, ev)\n tree.events.push({ ...ev })\n }\n}\n\n/**\n * JSONL on disk. One line per record: the first record is `begin`, subsequent records\n * are `event` envelopes wrapping a `SpawnEvent`. `loadTree` replays the whole file,\n * filtering by `root`, and applies the same begin-precedes-events + unique-seq\n * corruption guards as the in-memory impl. Each append fsyncs so a crash between\n * writes never loses an acknowledged event.\n */\nexport class FileSpawnJournal implements SpawnJournal {\n constructor(private readonly path: string) {}\n\n async loadTree(root: NodeId): Promise<SpawnEvent[] | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.path, 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n const lines = text.split('\\n').filter((line) => line.length > 0)\n let begun = false\n const events: SpawnEvent[] = []\n for (const line of lines) {\n const record = JSON.parse(line) as SpawnJournalRecord\n if (record.root !== root) continue\n if (record.kind === 'begin') {\n begun = true\n } else {\n if (!begun) {\n throw new Error(\n `spawn journal corrupted: event for tree '${root}' precedes its begin record`,\n )\n }\n assertSeqUnique(root, events, record.event)\n events.push(record.event)\n }\n }\n return begun ? events : undefined\n }\n\n async beginTree(root: NodeId, at: string): Promise<void> {\n const existing = await this.loadTreeBegin(root)\n if (existing) {\n if (existing !== at) {\n throw new Error(\n `spawn tree '${root}' already begun in ${this.path} at ${existing}; refusing to overwrite with ${at}`,\n )\n }\n return\n }\n await this.appendRecord({ kind: 'begin', root, at })\n }\n\n async appendEvent(root: NodeId, ev: SpawnEvent): Promise<void> {\n const events = await this.loadTree(root)\n if (events === undefined) {\n throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`)\n }\n assertSeqUnique(root, events, ev)\n await this.appendRecord({ kind: 'event', root, event: ev })\n }\n\n private async loadTreeBegin(root: NodeId): Promise<string | undefined> {\n const fs = await import('node:fs/promises')\n let text: string\n try {\n text = await fs.readFile(this.path, 'utf8')\n } catch (err) {\n if (isNoEntError(err)) return undefined\n throw err\n }\n const lines = text.split('\\n').filter((line) => line.length > 0)\n for (const line of lines) {\n const record = JSON.parse(line) as SpawnJournalRecord\n if (record.root === root && record.kind === 'begin') return record.at\n }\n return undefined\n }\n\n private async appendRecord(record: SpawnJournalRecord): Promise<void> {\n const fs = await import('node:fs/promises')\n const path = await import('node:path')\n await fs.mkdir(path.dirname(this.path), { recursive: true })\n const fh = await fs.open(this.path, 'a')\n try {\n await fh.write(`${JSON.stringify(record)}\\n`)\n await fh.sync()\n } finally {\n await fh.close()\n }\n }\n}\n\ntype SpawnJournalRecord =\n | { kind: 'begin'; root: NodeId; at: string }\n | { kind: 'event'; root: NodeId; event: SpawnEvent }\n\n/**\n * Two `seq` namespaces share the journal: a `spawned` event's `seq` is the spawn ordinal\n * (the order children were created), and a `settled`/`cancelled` event's `seq` is the\n * monotonic CURSOR order `scope.next()` yielded that settlement (B2). The uniqueness\n * replay rests on is the cursor namespace — two settlements cannot share the position\n * replay orders by — so the guard checks only settled/cancelled events. A `spawned`\n * ordinal legitimately equals a later `settled` cursor seq and is not a collision.\n */\nfunction assertSeqUnique(root: NodeId, events: SpawnEvent[], ev: SpawnEvent): void {\n // `spawned` (ordinal namespace) and `metered` (informational spend, no settlement order) live\n // outside the cursor-uniqueness namespace replay relies on.\n if (ev.kind === 'spawned' || ev.kind === 'metered') return\n if (events.some((e) => e.kind !== 'spawned' && e.kind !== 'metered' && e.seq === ev.seq)) {\n throw new Error(\n `spawn journal corrupted: duplicate cursor seq ${ev.seq} in tree '${root}'; ` +\n 'the cursor order replay relies on is not unique',\n )\n }\n}\n\n// ── Replay executor (build step 7) ───────────────────────────────────────────────\n\n/**\n * Re-feed a journaled spawn tree in strict `seq` order, rehydrating each settled\n * child's `out` from the blob store by `outRef`, and return the `Settled[]` exactly\n * as `scope.next()` originally delivered them.\n *\n * Determinism (B2): the events are sorted by `seq` BEFORE any blob `get`, so the\n * replay order is the recorded cursor order regardless of how fast each rehydration\n * resolves. `at` (wall-clock) is never a replay input. Fail loud on a tree that was\n * never begun, a settled-done event missing its `outRef`, or a blob the store can't\n * rehydrate — a silent gap would let `act` branch on the wrong evidence.\n */\nexport async function replaySpawnTree(\n journal: SpawnJournal,\n blobs: ResultBlobStore,\n root: NodeId,\n): Promise<Settled<unknown>[]> {\n const events = await journal.loadTree(root)\n if (events === undefined) {\n throw new Error(`replaySpawnTree: no journaled tree for root '${root}'`)\n }\n const ordered = [...events].sort((a, b) => a.seq - b.seq)\n const labels = new Map<NodeId, string>()\n for (const ev of ordered) {\n if (ev.kind === 'spawned') labels.set(ev.id, ev.label)\n }\n const settled: Settled<unknown>[] = []\n for (const ev of ordered) {\n if (ev.kind === 'spawned') continue\n if (ev.kind === 'metered') continue // a spend record, not a settlement — irrelevant to replay\n if (ev.kind === 'cancelled') {\n settled.push({\n kind: 'down',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'cancelled'),\n reason: ev.reason,\n infra: false,\n restartCount: 0,\n seq: ev.seq,\n })\n continue\n }\n if (ev.status === 'down') {\n settled.push({\n kind: 'down',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'failed'),\n reason: ev.verdict?.notes ?? 'child down',\n infra: ev.infra === true,\n restartCount: 0,\n seq: ev.seq,\n })\n continue\n }\n if (ev.outRef === undefined) {\n throw new Error(\n `replaySpawnTree: settled-done event for '${ev.id}' (seq ${ev.seq}) has no outRef; ` +\n 'cannot rehydrate the result the driver branched on',\n )\n }\n const out = await blobs.get(ev.outRef)\n if (out === undefined) {\n throw new Error(\n `replaySpawnTree: blob store has no artifact for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`,\n )\n }\n settled.push({\n kind: 'done',\n handle: replayHandle(ev.id, labels.get(ev.id) ?? ev.id, 'done'),\n out,\n outRef: ev.outRef,\n verdict: ev.verdict,\n spent: ev.spent,\n seq: ev.seq,\n })\n }\n return settled\n}\n\nfunction replayHandle(id: NodeId, label: string, status: NodeStatus) {\n return {\n id,\n label,\n status,\n abort() {\n throw new Error(`cannot abort node '${id}': replayed handles are terminal, not live`)\n },\n }\n}\n\n/**\n * Materialize the live tree (`TreeView`) from a journaled event list for resume. Folds\n * `spawned`/`settled`/`cancelled` into a per-node snapshot in `seq` order, then adds each\n * `metered` event's driver-inference spend onto its node in a separate additive pass — so the\n * resumed view matches what `scope.view` showed at the recorded cursor position.\n */\nexport function materializeTreeView(events: SpawnEvent[]): TreeView {\n const nodes = new Map<NodeId, MutableSnapshot>()\n let root: NodeId | undefined\n // `spawned` (ordinal namespace) and `settled`/`cancelled` (cursor namespace) carry\n // overlapping `seq` values, so create every node before any update — process spawns in\n // ordinal order, then settlements/cancellations in cursor order. A settle/cancel for an\n // un-spawned node is a corrupted log (fail loud via requireNode).\n const spawns = events\n .filter((ev): ev is Extract<SpawnEvent, { kind: 'spawned' }> => ev.kind === 'spawned')\n .sort((a, b) => a.seq - b.seq)\n const settlements = events\n .filter((ev) => ev.kind !== 'spawned' && ev.kind !== 'metered')\n .sort((a, b) => a.seq - b.seq)\n for (const ev of spawns) {\n if (ev.parent === undefined && root === undefined) root = ev.id\n nodes.set(ev.id, {\n id: ev.id,\n parent: ev.parent,\n label: ev.label,\n status: 'pending',\n runtime: ev.runtime,\n budget: ev.budget,\n spent: zeroSpend(),\n })\n }\n for (const ev of settlements) {\n if (ev.kind === 'settled') {\n const node = requireNode(nodes, ev.id)\n node.status = ev.status === 'done' ? 'done' : 'failed'\n node.spent = ev.spent\n node.outRef = ev.outRef\n } else {\n const node = requireNode(nodes, ev.id)\n node.status = 'cancelled'\n }\n }\n // Driver inference: a separate pass so it accumulates ONTO the settled child-work base (no\n // dependence on metered-vs-settled seq order) without touching node status.\n for (const ev of events) {\n if (ev.kind !== 'metered') continue\n const node = requireNode(nodes, ev.id)\n node.spent = addJournalSpend(node.spent, ev.spend)\n }\n const snapshots = [...nodes.values()].map(freezeSnapshot)\n return {\n root: root ?? snapshots[0]?.id ?? '',\n nodes: snapshots,\n inFlight: snapshots.filter((n) => n.status === 'running' || n.status === 'acquiring').length,\n }\n}\n\ninterface MutableSnapshot {\n id: NodeId\n parent?: NodeId\n label: string\n status: NodeStatus\n runtime: Runtime\n budget: NodeSnapshot['budget']\n spent: Spend\n outRef?: string\n}\n\nfunction zeroSpend(): Spend {\n return { iterations: 0, tokens: zeroTokenUsage(), usd: 0, ms: 0 }\n}\n\n/** Add a `metered` spend record onto a node's accumulated spend (per channel). */\nfunction addJournalSpend(a: Spend, b: Spend): Spend {\n return {\n iterations: a.iterations + b.iterations,\n tokens: { input: a.tokens.input + b.tokens.input, output: a.tokens.output + b.tokens.output },\n usd: a.usd + b.usd,\n ms: a.ms + b.ms,\n }\n}\n\nfunction requireNode(nodes: Map<NodeId, MutableSnapshot>, id: NodeId): MutableSnapshot {\n const node = nodes.get(id)\n if (!node) {\n throw new Error(`spawn journal corrupted: settle/cancel for node '${id}' with no prior spawn`)\n }\n return node\n}\n\nfunction freezeSnapshot(node: MutableSnapshot): NodeSnapshot {\n return {\n id: node.id,\n parent: node.parent,\n label: node.label,\n status: node.status,\n runtime: node.runtime,\n budget: node.budget,\n spent: node.spent,\n outRef: node.outRef,\n }\n}\n\nfunction isNoEntError(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'code' in err &&\n (err as { code: unknown }).code === 'ENOENT'\n )\n}\n"],"mappings":";AAsBA,SAAS,kBAAkB;AA0BpB,SAAS,eAAe,UAA2B;AACxD,QAAM,MAAM,WAAW,QAAQ,EAAE,OAAO,gBAAgB,QAAQ,GAAG,OAAO,EAAE,OAAO,KAAK;AACxF,SAAO,UAAU,GAAG;AACtB;AAEA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO,KAAK,UAAU,KAAK,KAAK;AACjF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,MAAM,IAAI,eAAe,EAAE,KAAK,GAAG,CAAC;AACzE,QAAM,UAAU,OAAO,QAAQ,KAAgC,EAC5D,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,EACjC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE;AAClD,SAAO,IAAI,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAC5F;AASO,IAAM,0BAAN,MAAyD;AAAA,EAC7C,QAAQ,oBAAI,IAAqB;AAAA,EAElD,MAAM,IAAI,QAAgB,UAAkC;AAC1D,yBAAqB,QAAQ,QAAQ;AACrC,SAAK,MAAM,IAAI,QAAQ,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAM,IAAI,QAA8C;AACtD,WAAO,KAAK,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,MAAM,IAAI;AAAA,EAC3D;AACF;AAwCA,SAAS,qBAAqB,QAAgB,UAAyB;AACrE,QAAM,WAAW,eAAe,QAAQ;AACxC,MAAI,WAAW,UAAU;AACvB,UAAM,IAAI;AAAA,MACR,gBAAgB,MAAM,+CAA+C,QAAQ;AAAA,IAE/E;AAAA,EACF;AACF;AAWO,IAAM,uBAAN,MAAmD;AAAA,EACvC,QAAQ,oBAAI,IAAuD;AAAA,EAEpF,MAAM,SAAS,MAAiD;AAC9D,UAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,KAAK,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,UAAU,MAAc,IAA2B;AACvD,UAAM,WAAW,KAAK,MAAM,IAAI,IAAI;AACpC,QAAI,UAAU;AACZ,UAAI,SAAS,YAAY,IAAI;AAC3B,cAAM,IAAI;AAAA,UACR,eAAe,IAAI,sBAAsB,SAAS,OAAO,gCAAgC,EAAE;AAAA,QAC7F;AAAA,MACF;AACA;AAAA,IACF;AACA,SAAK,MAAM,IAAI,MAAM,EAAE,SAAS,IAAI,QAAQ,CAAC,EAAE,CAAC;AAAA,EAClD;AAAA,EAEA,MAAM,YAAY,MAAc,IAA+B;AAC7D,UAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,8CAA8C,IAAI,yBAAyB;AAAA,IAC7F;AACA,oBAAgB,MAAM,KAAK,QAAQ,EAAE;AACrC,SAAK,OAAO,KAAK,EAAE,GAAG,GAAG,CAAC;AAAA,EAC5B;AACF;AA2GA,SAAS,gBAAgB,MAAc,QAAsB,IAAsB;AAGjF,MAAI,GAAG,SAAS,aAAa,GAAG,SAAS,UAAW;AACpD,MAAI,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,SAAS,aAAa,EAAE,QAAQ,GAAG,GAAG,GAAG;AACxF,UAAM,IAAI;AAAA,MACR,iDAAiD,GAAG,GAAG,aAAa,IAAI;AAAA,IAE1E;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// src/runtime/util.ts
|
|
2
|
+
async function deleteBoxSafe(box) {
|
|
3
|
+
if (!box || typeof box.delete !== "function") return true;
|
|
4
|
+
try {
|
|
5
|
+
await box.delete();
|
|
6
|
+
return true;
|
|
7
|
+
} catch {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function randomSuffix(len = 8) {
|
|
12
|
+
return Math.random().toString(36).slice(2, 2 + len);
|
|
13
|
+
}
|
|
14
|
+
function randomUuid() {
|
|
15
|
+
return crypto.randomUUID();
|
|
16
|
+
}
|
|
17
|
+
function abortError() {
|
|
18
|
+
const err = new Error("aborted");
|
|
19
|
+
err.name = "AbortError";
|
|
20
|
+
return err;
|
|
21
|
+
}
|
|
22
|
+
function throwAbort() {
|
|
23
|
+
throw abortError();
|
|
24
|
+
}
|
|
25
|
+
function throwIfAborted(signal) {
|
|
26
|
+
if (signal?.aborted) throw abortError();
|
|
27
|
+
}
|
|
28
|
+
function isAbortError(err) {
|
|
29
|
+
return err instanceof Error && err.name === "AbortError";
|
|
30
|
+
}
|
|
31
|
+
function sleep(ms, signal) {
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
if (signal?.aborted) {
|
|
34
|
+
resolve();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let onAbort;
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
if (onAbort && signal) signal.removeEventListener("abort", onAbort);
|
|
40
|
+
resolve();
|
|
41
|
+
}, ms);
|
|
42
|
+
if (signal) {
|
|
43
|
+
onAbort = () => {
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
resolve();
|
|
46
|
+
};
|
|
47
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function withTimeout(promise, ms) {
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
const timer = setTimeout(() => resolve(void 0), ms);
|
|
54
|
+
promise.then(
|
|
55
|
+
(value) => {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
resolve(value);
|
|
58
|
+
},
|
|
59
|
+
() => {
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
resolve(void 0);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function stringifySafe(value, opts = {}) {
|
|
67
|
+
let s;
|
|
68
|
+
try {
|
|
69
|
+
if (typeof value === "string") {
|
|
70
|
+
s = value;
|
|
71
|
+
} else {
|
|
72
|
+
const json = opts.pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);
|
|
73
|
+
s = json ?? String(value);
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
s = String(value);
|
|
77
|
+
}
|
|
78
|
+
if (opts.max !== void 0 && s.length > opts.max) return `${s.slice(0, opts.max)}\u2026`;
|
|
79
|
+
return s;
|
|
80
|
+
}
|
|
81
|
+
function zeroTokenUsage() {
|
|
82
|
+
return { input: 0, output: 0 };
|
|
83
|
+
}
|
|
84
|
+
function addTokenUsage(acc, delta) {
|
|
85
|
+
acc.input += delta.input ?? 0;
|
|
86
|
+
acc.output += delta.output ?? 0;
|
|
87
|
+
}
|
|
88
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
89
|
+
const bound = Math.max(1, Math.floor(limit));
|
|
90
|
+
const results = new Array(items.length);
|
|
91
|
+
let next = 0;
|
|
92
|
+
let failed = false;
|
|
93
|
+
const worker = async () => {
|
|
94
|
+
while (!failed) {
|
|
95
|
+
const i = next;
|
|
96
|
+
next += 1;
|
|
97
|
+
if (i >= items.length) return;
|
|
98
|
+
try {
|
|
99
|
+
results[i] = await fn(items[i], i);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
failed = true;
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const workerCount = Math.min(bound, items.length);
|
|
107
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
108
|
+
return results;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
deleteBoxSafe,
|
|
113
|
+
randomSuffix,
|
|
114
|
+
randomUuid,
|
|
115
|
+
throwAbort,
|
|
116
|
+
throwIfAborted,
|
|
117
|
+
isAbortError,
|
|
118
|
+
sleep,
|
|
119
|
+
withTimeout,
|
|
120
|
+
stringifySafe,
|
|
121
|
+
zeroTokenUsage,
|
|
122
|
+
addTokenUsage,
|
|
123
|
+
mapWithConcurrency
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=chunk-3MDZX7YU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/util.ts"],"sourcesContent":["/**\n *\n * Internal loop-kernel utilities shared across the kernel, drivers, and the\n * sandbox-acquire layer. Not part of the public barrel surface.\n *\n * @experimental\n */\n\nimport type { SandboxInstance } from '@tangle-network/sandbox'\nimport type { LoopTokenUsage } from './types'\n\n/**\n * Best-effort sandbox delete. Skips instances without a `delete` (test fakes);\n * swallows errors (the platform reaps on expiry). Returns `false` when delete\n * threw, `true` otherwise, so callers can surface a leak if they choose.\n */\nexport async function deleteBoxSafe(box: SandboxInstance | undefined): Promise<boolean> {\n if (!box || typeof (box as { delete?: unknown }).delete !== 'function') return true\n try {\n await box.delete()\n return true\n } catch {\n return false\n }\n}\n\n/** Short base36 id for trace correlation. Not cryptographic, not collision-free. */\nexport function randomSuffix(len = 8): string {\n return Math.random()\n .toString(36)\n .slice(2, 2 + len)\n}\n\n/** Collision-resistant id for sandbox naming (find-by-name recovery must be unique). */\nexport function randomUuid(): string {\n return crypto.randomUUID()\n}\n\n/** Construct an AbortError. Downstream code pattern-matches on `err.name`. */\nexport function abortError(): Error {\n const err = new Error('aborted')\n err.name = 'AbortError'\n return err\n}\n\n/** Throw an AbortError. */\nexport function throwAbort(): never {\n throw abortError()\n}\n\n/** Throw if the signal is already aborted; otherwise no-op. */\nexport function throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw abortError()\n}\n\n/** True for any error whose `name` is `AbortError` (the cross-kernel abort contract). */\nexport function isAbortError(err: unknown): boolean {\n return err instanceof Error && err.name === 'AbortError'\n}\n\n/**\n * Sleep that resolves early on abort and always clears its timer so it never\n * keeps the event loop alive. Resolves (does not reject) on abort — callers\n * re-check the signal explicitly after the sleep.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve()\n return\n }\n let onAbort: (() => void) | undefined\n const timer = setTimeout(() => {\n if (onAbort && signal) signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n if (signal) {\n onAbort = () => {\n clearTimeout(timer)\n resolve()\n }\n signal.addEventListener('abort', onAbort, { once: true })\n }\n })\n}\n\n/**\n * Race a promise against a timeout. Resolves with the value if it settles in\n * time, otherwise resolves with `undefined`. Always clears the timer.\n */\nexport function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T | undefined> {\n return new Promise<T | undefined>((resolve) => {\n const timer = setTimeout(() => resolve(undefined), ms)\n promise.then(\n (value) => {\n clearTimeout(timer)\n resolve(value)\n },\n () => {\n clearTimeout(timer)\n resolve(undefined)\n },\n )\n })\n}\n\ninterface StringifyOptions {\n /** Pretty-print with 2-space indent. Default false (compact). */\n pretty?: boolean\n /** Truncate to this many chars, appending `…`. Default unbounded. */\n max?: number\n}\n\n/**\n * `JSON.stringify` with a `String()` fallback on throw (cyclic / non-JSON).\n * Strings pass through unstringified so a preview of a string output is the\n * string itself, not a quoted re-encoding.\n */\nexport function stringifySafe(value: unknown, opts: StringifyOptions = {}): string {\n let s: string\n try {\n if (typeof value === 'string') {\n s = value\n } else {\n const json = opts.pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value)\n s = json ?? String(value)\n }\n } catch {\n s = String(value)\n }\n if (opts.max !== undefined && s.length > opts.max) return `${s.slice(0, opts.max)}…`\n return s\n}\n\n/** A fresh zero token-usage accumulator. */\nexport function zeroTokenUsage(): LoopTokenUsage {\n return { input: 0, output: 0 }\n}\n\n/** Add `delta` into `acc` in place. Missing fields count as zero. */\nexport function addTokenUsage(acc: LoopTokenUsage, delta: Partial<LoopTokenUsage>): void {\n acc.input += delta.input ?? 0\n acc.output += delta.output ?? 0\n}\n\n/**\n * Map `items` through `fn` with at most `limit` calls in flight at once,\n * preserving input order in the result. On the first `fn` rejection no NEW\n * items are picked up; already-in-flight calls are awaited, then the first\n * error is rethrown. `limit` is clamped to ≥ 1.\n *\n * Used where a burst of provisioning (e.g. forking N child boxes) must respect\n * the loop's concurrency bound instead of firing all N at once.\n */\nexport async function mapWithConcurrency<T, R>(\n items: readonly T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const bound = Math.max(1, Math.floor(limit))\n const results = new Array<R>(items.length)\n let next = 0\n let failed = false\n const worker = async (): Promise<void> => {\n while (!failed) {\n const i = next\n next += 1\n if (i >= items.length) return\n try {\n results[i] = await fn(items[i] as T, i)\n } catch (err) {\n failed = true\n throw err\n }\n }\n }\n const workerCount = Math.min(bound, items.length)\n await Promise.all(Array.from({ length: workerCount }, () => worker()))\n return results\n}\n"],"mappings":"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","names":[]}
|