@tangle-network/agent-runtime 0.337.2 → 0.338.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-DRHM55Oo.d.ts → activation-CsbNax2X.d.ts} +92 -4
- package/dist/activation-kbkAuSmY.js +889 -0
- package/dist/activation-kbkAuSmY.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -6
- package/dist/agent.js.map +1 -1
- package/dist/{bundle-BPGjESee.js → bundle-DM60AI2B.js} +2 -2
- package/dist/{bundle-BPGjESee.js.map → bundle-DM60AI2B.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +2 -2
- package/dist/candidate-execution/index.js +4 -5
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/content-digest-sBTLujlK.js +9 -0
- package/dist/content-digest-sBTLujlK.js.map +1 -0
- package/dist/{delegate-B-T_ZB50.js → delegate-Se1YZKMb.js} +2 -2
- package/dist/{delegate-B-T_ZB50.js.map → delegate-Se1YZKMb.js.map} +1 -1
- package/dist/{coordination-driver-BHkFVqIq.js → driver-control-acknowledgers-T2a1Ouay.js} +4514 -4440
- package/dist/driver-control-acknowledgers-T2a1Ouay.js.map +1 -0
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +223 -227
- package/dist/durable.js.map +1 -1
- package/dist/{graph-C4RFlWAJ.js → graph-CY0wH838.js} +65 -18
- package/dist/graph-CY0wH838.js.map +1 -0
- package/dist/{graph-registry-DAI6KNXB.js → graph-registry-By0tUj4S.js} +16 -15
- package/dist/graph-registry-By0tUj4S.js.map +1 -0
- package/dist/{improvement-cycle-D1I4hQvf.js → improve-CWGBT13K.js} +75 -1220
- package/dist/improve-CWGBT13K.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +10 -13
- package/dist/index.js.map +1 -1
- package/dist/{integrations-DopfCC2a.d.ts → integrations-6xttbPi9.d.ts} +3 -3
- package/dist/integrations-dFi-ALk7.js.map +1 -1
- package/dist/intelligence.d.ts +7 -94
- package/dist/intelligence.js +505 -13
- package/dist/intelligence.js.map +1 -1
- package/dist/kernel.d.ts +2 -2
- package/dist/kernel.js +13 -12
- package/dist/{loop-runner-bin-DOuBIJ2O.d.ts → loop-runner-bin-CFnrAHpl.d.ts} +2 -2
- package/dist/{loop-runner-bin-Dv5QvYDH.js → loop-runner-bin-CdPlhy9g.js} +3 -3
- package/dist/{loop-runner-bin-Dv5QvYDH.js.map → loop-runner-bin-CdPlhy9g.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/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +7 -3
- package/dist/mcp/index.js +6 -8
- package/dist/mcp/index.js.map +1 -1
- package/dist/{openai-tools-Oxk4KQrY.d.ts → openai-tools-zh2I_uD7.d.ts} +2 -2
- package/dist/platform.d.ts +7 -2
- package/dist/platform.js +16 -8
- package/dist/platform.js.map +1 -1
- package/dist/{prepare-CER-ZkPp.js → prepare-Bt0IouPq.js} +1241 -586
- package/dist/prepare-Bt0IouPq.js.map +1 -0
- package/dist/{profile-gNUsHNIJ.js → profile-Do-5xO_D.js} +89 -3
- package/dist/profile-Do-5xO_D.js.map +1 -0
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +1 -3
- package/dist/profiles.js.map +1 -1
- package/dist/{protected-model-port-BhpQRTw-.d.ts → protected-model-port-DGxQ8_YM.d.ts} +3 -3
- package/dist/{provision-supervisor-DGegCUH4.js → provision-supervisor-0jMufp4h.js} +12 -9
- package/dist/provision-supervisor-0jMufp4h.js.map +1 -0
- package/dist/record-value-B6bwJxLa.js +12 -0
- package/dist/record-value-B6bwJxLa.js.map +1 -0
- package/dist/{run-layout-Cu8H7aeh.js → run-cancellation-BoW5Sg9Y.js} +174 -95
- package/dist/run-cancellation-BoW5Sg9Y.js.map +1 -0
- package/dist/{runtime-BOGpotnH.js → runtime-D37zRSs7.js} +431 -621
- package/dist/runtime-D37zRSs7.js.map +1 -0
- package/dist/{sandbox-profile-compat-QTkLe1Z6.js → sandbox-profile-compat-xSoVtdWw.js} +690 -697
- package/dist/sandbox-profile-compat-xSoVtdWw.js.map +1 -0
- package/dist/search-executor-DmgUm5p7.js +1916 -0
- package/dist/search-executor-DmgUm5p7.js.map +1 -0
- package/dist/{server-hZWM-G8w.js → server-DQHJszfk.js} +4 -4
- package/dist/server-DQHJszfk.js.map +1 -0
- package/dist/{search-executor-Cm1WZmL-.js → structural-rollout-DAvIE8mw.js} +2261 -3984
- package/dist/structural-rollout-DAvIE8mw.js.map +1 -0
- package/dist/{supervise-CvAKVfue.js → supervise-WuPAwfPh.js} +7793 -5338
- package/dist/supervise-WuPAwfPh.js.map +1 -0
- package/dist/{supervisor-Rz8AGpYb.js → supervisor-CPG1I9UN.js} +26590 -27196
- package/dist/supervisor-CPG1I9UN.js.map +1 -0
- package/dist/testing.d.ts +226 -1
- package/dist/testing.js +13 -14
- package/dist/testing.js.map +1 -1
- package/dist/{top-app-BaMw1W2z.js → top-app-C55Wa7uy.js} +339 -337
- package/dist/top-app-C55Wa7uy.js.map +1 -0
- package/dist/tui/bin.js +1 -1
- package/dist/tui/index.d.ts +17 -15
- package/dist/tui/index.js +2 -2
- package/dist/{types-Dl5L4r8Z.d.ts → types-CrNWif8-.d.ts} +17410 -17173
- package/dist/{workspace-streams-JLjh5DC6.d.ts → workspace-streams-BZZds1Fw.d.ts} +18 -16
- package/package.json +2 -2
- package/skills/agent-graphs/SKILL.md +10 -3
- package/skills/agent-graphs/references/authoring.md +17 -0
- package/skills/profile-authoring/SKILL.md +3 -3
- package/skills/supervise/SKILL.md +2 -2
- package/dist/activation-BDP6Eivv.js +0 -234
- package/dist/activation-BDP6Eivv.js.map +0 -1
- package/dist/coordination-driver-BHkFVqIq.js.map +0 -1
- package/dist/graph-C4RFlWAJ.js.map +0 -1
- package/dist/graph-registry-DAI6KNXB.js.map +0 -1
- package/dist/improvement-cycle-D1I4hQvf.js.map +0 -1
- package/dist/prepare-CER-ZkPp.js.map +0 -1
- package/dist/profile-gNUsHNIJ.js.map +0 -1
- package/dist/protected-model-port-BuRsviSL.js +0 -766
- package/dist/protected-model-port-BuRsviSL.js.map +0 -1
- package/dist/provision-supervisor-DGegCUH4.js.map +0 -1
- package/dist/run-layout-Cu8H7aeh.js.map +0 -1
- package/dist/runtime-BOGpotnH.js.map +0 -1
- package/dist/sandbox-profile-compat-QTkLe1Z6.js.map +0 -1
- package/dist/search-executor-Cm1WZmL-.js.map +0 -1
- package/dist/server-hZWM-G8w.js.map +0 -1
- package/dist/supervise-CvAKVfue.js.map +0 -1
- package/dist/supervisor-Rz8AGpYb.js.map +0 -1
- package/dist/top-app-BaMw1W2z.js.map +0 -1
|
@@ -1,456 +1,94 @@
|
|
|
1
1
|
import { o as writeAtomicDurableFile } from "./durable-file-B_eJr6Mb.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Et as readPromptOptions, Gi as executableAgentSpecSnapshot, H as rollingDispatch, Ht as routerBrain, L as settledToIteration, Ma as notifySandboxEventObserver, Nt as defaultSelectWinner, Ot as createSandboxLineage, P as coordinationProfileToolPrefix, Tt as assertBoxlessPromptOptions, Wi as executableAgentProfileSnapshot, Wr as runAbortable, _r as verdictFromJudgeScore, _t as createExecutorRegistry, bt as createExecutor, ca as contentAddress, dn as createWorktreeCliExecutor, gr as mapExecutorResult, gt as insideCursorNamespace, hr as gateOnDeliverable, ka as createSandboxTurnEventCollector, mr as CheckUnavailableError, mt as InMemorySpawnJournal, n as createSupervisor, oa as detachedFrozen, p as withDriverExecutor, pt as InMemoryResultBlobStore, sa as detachedSnapshot, v as isTraceAnalysisStore, wt as runAgentRounds } from "./supervisor-CPG1I9UN.js";
|
|
3
3
|
import { i as ConfigError, m as ValidationError, n as AnalystError, s as PlannerError } from "./errors-DodWX-cb.js";
|
|
4
|
-
import {
|
|
5
|
-
import { $ as
|
|
6
|
-
import { a as readCommittedJsonLines, i as readCommittedJsonFile, n as isNoEntError, o as upsertCommittedJsonLine, s as withJsonlFileLock, t as appendCommittedJsonLine } from "./jsonl-file-DBv31uPi.js";
|
|
4
|
+
import { A as observe, D as sample, E as runAgentic, M as profileChatClient, O as ObservationError, T as refine, j as renderReport, v as loadAuthoredStrategy, x as strategyAuthorContract, y as requestStrategySource } from "./structural-rollout-DAvIE8mw.js";
|
|
5
|
+
import { $ as hasCompleteCacheBreakdown, F as canonicalCandidateDigest$1, G as addSpend, J as cloneSpend, M as markPutStreamVerified, Q as fnv1a32Hex, Tt as armDeadlineTimer, V as sha256Bytes$1, Z as errorMessage, ct as stringifySafe, et as isAbortError, it as randomSuffix, nt as mapWithConcurrency, pt as zeroSpend, q as chargedTokens, st as sleep, tt as isAsyncIterable, w as captureMaterializedWorkspace, x as WorkspaceScanLimitError, z as immutableCandidateValue } from "./sandbox-profile-compat-xSoVtdWw.js";
|
|
7
6
|
import { c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, p as canonicalObservedModelParts, t as assertExecutableAgentProfile, v as harnessRunsAgent } from "./model-policy-CyCUwHed.js";
|
|
8
7
|
import { i as notifyRuntimeHookEvent } from "./runtime-hooks-tXpAarhW.js";
|
|
8
|
+
import { a as readCommittedJsonLines, i as readCommittedJsonFile, n as isNoEntError, o as upsertCommittedJsonLine, s as withJsonlFileLock, t as appendCommittedJsonLine } from "./jsonl-file-DBv31uPi.js";
|
|
9
|
+
import { S as foldCoordinationRecords, y as createInMemoryRunContext } from "./driver-control-acknowledgers-T2a1Ouay.js";
|
|
10
|
+
import { B as runBrainLoop, t as supervise } from "./supervise-WuPAwfPh.js";
|
|
11
|
+
import { a as reconcileInterruptedSearchCalls, c as searchExecutor, r as dedicatedLane, x as runtimeShipDecision } from "./search-executor-DmgUm5p7.js";
|
|
9
12
|
import { i as redactProtectedValue, r as redactProtectedReason } from "./protected-redaction-DFCeo4vg.js";
|
|
10
|
-
import
|
|
11
|
-
import { r as
|
|
12
|
-
import
|
|
13
|
-
import "./
|
|
14
|
-
import "./
|
|
15
|
-
import "./delegate-B-T_ZB50.js";
|
|
16
|
-
import "./graph-C4RFlWAJ.js";
|
|
13
|
+
import "./run-cancellation-BoW5Sg9Y.js";
|
|
14
|
+
import { a as graphRunsFor, d as recordGraphRun, i as graphRegistry, l as lookupGraph, p as taskShapeDigest, r as graphFromStored, t as digestOfGraph } from "./graph-registry-By0tUj4S.js";
|
|
15
|
+
import "./provision-supervisor-0jMufp4h.js";
|
|
16
|
+
import "./delegate-Se1YZKMb.js";
|
|
17
|
+
import "./graph-CY0wH838.js";
|
|
17
18
|
import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, sha256Bytes, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
|
|
18
19
|
import { CODING_HARNESSES, DEFAULT_TRACE_ANALYST_KINDS, InMemoryTraceStore, OUTPUT_VALUE, benjaminiHochberg, buildTrajectory, computeFindingId as computeFindingId$1, confidenceInterval, createTraceAnalyst, expandProfileAxes, makeFinding as makeFinding$1, pairedBootstrap, paretoFrontier, wilcoxonSignedRank, wilson } from "@tangle-network/agent-eval";
|
|
19
20
|
import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
|
|
21
|
+
import { collectAgentResponseText } from "@tangle-network/sandbox";
|
|
20
22
|
import { redact } from "@tangle-network/agent-eval/traces";
|
|
21
23
|
import { z } from "zod";
|
|
22
24
|
import { createHash, createHmac, randomUUID } from "node:crypto";
|
|
23
|
-
import { appendFileSync, chmodSync, constants, copyFileSync,
|
|
25
|
+
import { appendFileSync, chmodSync, constants, copyFileSync, lstatSync, mkdirSync, mkdtempSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
24
26
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
25
27
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
26
28
|
import { chmod, link, lstat, mkdir, mkdtemp, open, opendir, readFile, readdir, readlink, realpath, rename, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
27
|
-
import { tmpdir } from "node:os";
|
|
28
29
|
import { isDeepStrictEqual, promisify } from "node:util";
|
|
30
|
+
import { tmpdir } from "node:os";
|
|
29
31
|
import { Readable } from "node:stream";
|
|
30
|
-
import { collectAgentResponseText } from "@tangle-network/sandbox";
|
|
31
32
|
import { SearchRecorder, asha, beam, createRunCostLedger, estimateNode, fsCampaignStorage, openSearchLedger, renderSearchSummary, runProfileMatrix, runSearch, searchClaimReserveUsd, searchModelIdentity, surfaceDiff } from "@tangle-network/agent-eval/campaign";
|
|
32
33
|
import { defineEvaluationClaim, summarizeEvaluationUnits } from "@tangle-network/agent-eval/experiment";
|
|
33
34
|
import { createInterface } from "node:readline";
|
|
34
35
|
import { Worker } from "node:worker_threads";
|
|
35
|
-
import { pathToFileURL } from "node:url";
|
|
36
36
|
import { gzipSync } from "node:zlib";
|
|
37
37
|
import { stuckLoopView, toolWasteView } from "@tangle-network/agent-eval/pipelines";
|
|
38
|
-
//#region src/runtime/
|
|
39
|
-
const exactProcessProviderMarker = "agent-runtime.exact-process-provider";
|
|
40
|
-
const exactProcessEgressMarker = "agent-runtime.exact-process-egress";
|
|
38
|
+
//#region src/runtime/http-mcp-client.ts
|
|
41
39
|
/**
|
|
42
|
-
*
|
|
40
|
+
* `connectHttpMcp` — the remote (streamable HTTP) MCP client, sibling of
|
|
41
|
+
* `connectStdioMcp`. Same connection contract (`tools`, `callTool`, `close`),
|
|
42
|
+
* same error semantics (a JSON-RPC error / `isError` result is the agent's
|
|
43
|
+
* `ERROR: …` outcome; a transport fault or timeout throws), no child process —
|
|
44
|
+
* which is the point: this is the MCP path for environments that cannot spawn
|
|
45
|
+
* stdio servers (Workers, browser-context agents, locked-down sandboxes) and
|
|
46
|
+
* for servers that only exist as endpoints (a remote Hindsight, a hosted MCP).
|
|
43
47
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
48
|
+
* Transport: MCP "streamable HTTP" (protocol 2025-03-26 / 2025-06-18). Every
|
|
49
|
+
* request is a POST with `Accept: application/json, text/event-stream`; the
|
|
50
|
+
* server may answer either shape, so both are parsed. A server-assigned
|
|
51
|
+
* `Mcp-Session-Id` response header is captured and replayed on every later
|
|
52
|
+
* request (and the DELETE on close) — stateful servers refuse without it,
|
|
53
|
+
* stateless ones simply never send it.
|
|
54
|
+
*
|
|
55
|
+
* Auth headers can be protected values: they are sent to the server but never
|
|
56
|
+
* allowed back out — error messages and tool results are redacted against the
|
|
57
|
+
* exact protected values, mirroring `connectStdioMcp`'s protectedEnv handling.
|
|
46
58
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
metadata,
|
|
67
|
-
idempotencyKey: requiredText(input.idempotencyKey, "exact-process idempotency key")
|
|
68
|
-
}, {
|
|
69
|
-
...input.provisionTimeoutMs === void 0 ? {} : { timeoutMs: positiveInteger$1(input.provisionTimeoutMs, "provision timeout") },
|
|
70
|
-
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
71
|
-
});
|
|
72
|
-
try {
|
|
73
|
-
throwIfAborted(input.signal);
|
|
74
|
-
assertExactSandboxMetadata(sandbox, metadata);
|
|
75
|
-
await assertExactSandboxEgress(sandbox, egressPolicy);
|
|
76
|
-
} catch (error) {
|
|
77
|
-
await discardInvalidSandbox(sandbox, error);
|
|
78
|
-
}
|
|
79
|
-
return sandboxAsExactProcessEnvironment(sandbox, name);
|
|
80
|
-
},
|
|
81
|
-
async get(id) {
|
|
82
|
-
const sandbox = await client.get(id);
|
|
83
|
-
if (!sandbox || !isExactSandbox(sandbox, name)) return null;
|
|
84
|
-
await assertExactSandboxEgress(sandbox, egressFromMetadata(sandbox.metadata));
|
|
85
|
-
return sandboxAsExactProcessEnvironment(sandbox, name);
|
|
86
|
-
},
|
|
87
|
-
async list(query) {
|
|
88
|
-
assertNoProviderOptions(query?.providerOptions);
|
|
89
|
-
const sandboxes = await client.list();
|
|
90
|
-
return Promise.all(sandboxes.filter((sandbox) => isExactSandbox(sandbox, name)).filter((sandbox) => metadataMatches(sandbox.metadata, query?.metadata)).map(async (sandbox) => {
|
|
91
|
-
await assertExactSandboxEgress(sandbox, egressFromMetadata(sandbox.metadata));
|
|
92
|
-
return sandboxAsExactProcessEnvironment(sandbox, name);
|
|
93
|
-
}));
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
capabilities: exactProcessOnlyCapabilities,
|
|
97
|
-
async create() {
|
|
98
|
-
throw new Error(`agent environment provider "${name}" supports exactProcess.create() only`);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
function sandboxAsExactProcessEnvironment(sandbox, provider) {
|
|
103
|
-
return {
|
|
104
|
-
id: requiredText(sandbox.id, "Sandbox id"),
|
|
105
|
-
provider,
|
|
106
|
-
...sandbox.metadata ? { metadata: sandbox.metadata } : {},
|
|
107
|
-
process: {
|
|
108
|
-
async list() {
|
|
109
|
-
return (await sandbox.process.list()).map((status) => exactProcessStatus(status));
|
|
110
|
-
},
|
|
111
|
-
async get(pid) {
|
|
112
|
-
const process = await sandbox.process.get(pid);
|
|
113
|
-
return process ? sandboxProcessAsExactProcess(process) : null;
|
|
114
|
-
},
|
|
115
|
-
async spawn(input, options) {
|
|
116
|
-
return sandboxProcessAsExactProcess(await afterAbortCheck(options?.signal, () => sandbox.process.spawnExact(input.executable, [...input.args], {
|
|
117
|
-
cwd: input.cwd,
|
|
118
|
-
env: { ...input.env },
|
|
119
|
-
inheritEnv: false,
|
|
120
|
-
...input.stdin === void 0 ? {} : { stdin: input.stdin },
|
|
121
|
-
timeoutMs: input.timeoutMs
|
|
122
|
-
})));
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
async writeFile(path, bytes, options) {
|
|
126
|
-
if (sandbox.fs.supportsWriteMode !== true) throw new Error("Tangle Sandbox does not declare exact file-mode support");
|
|
127
|
-
await afterAbortCheck(options.signal, () => sandbox.fs.write(path, Buffer.from(bytes).toString("base64"), {
|
|
128
|
-
encoding: "base64",
|
|
129
|
-
mode: fileMode(options.mode)
|
|
130
|
-
}));
|
|
131
|
-
},
|
|
132
|
-
async readFile(path, options) {
|
|
133
|
-
const maxBytes = nonnegativeInteger(options.maxBytes, "exact-process file read maximum");
|
|
134
|
-
const initialSize = nonnegativeInteger((await afterAbortCheck(options.signal, () => sandbox.fs.stat(path))).size, `Tangle Sandbox file size for "${path}"`);
|
|
135
|
-
if (initialSize > maxBytes) throw new Error(`Tangle Sandbox file "${path}" exceeds the ${maxBytes}-byte exact read maximum`);
|
|
136
|
-
const result = await afterAbortCheck(options.signal, () => sandbox.fs.readBatch([path], { encoding: "base64" }));
|
|
137
|
-
const failure = result.errors.find((entry) => entry.path === path);
|
|
138
|
-
if (failure) throw new Error(`Tangle Sandbox failed to read "${path}": ${failure.error}`);
|
|
139
|
-
const files = result.files.filter((entry) => entry.path === path);
|
|
140
|
-
if (files.length !== 1) throw new Error(`Tangle Sandbox returned ${files.length} files for exact read "${path}"`);
|
|
141
|
-
const file = files[0];
|
|
142
|
-
if (file.encoding !== "base64") throw new Error(`Tangle Sandbox returned non-binary content for exact read "${path}"`);
|
|
143
|
-
const size = nonnegativeInteger(file.size, `Tangle Sandbox file size for "${path}"`);
|
|
144
|
-
if (size !== initialSize) throw new Error(`Tangle Sandbox file "${path}" changed during exact read`);
|
|
145
|
-
if (size > maxBytes) throw new Error(`Tangle Sandbox file "${path}" exceeds the ${maxBytes}-byte exact read maximum`);
|
|
146
|
-
const bytes = Buffer.from(file.content, "base64");
|
|
147
|
-
if (bytes.byteLength !== size || bytes.toString("base64") !== file.content) throw new Error(`Tangle Sandbox returned an invalid binary payload for exact read "${path}"`);
|
|
148
|
-
return Uint8Array.from(bytes);
|
|
149
|
-
},
|
|
150
|
-
async destroy() {
|
|
151
|
-
await sandbox.delete();
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
function sandboxProcessAsExactProcess(process) {
|
|
156
|
-
const pid = positiveInteger$1(process.pid, "Tangle Sandbox process pid");
|
|
157
|
-
return {
|
|
158
|
-
pid,
|
|
159
|
-
async status() {
|
|
160
|
-
return exactProcessStatus(await process.status(), pid);
|
|
161
|
-
},
|
|
162
|
-
async wait() {
|
|
163
|
-
const waitExitCode = await process.wait();
|
|
164
|
-
if (!Number.isSafeInteger(waitExitCode)) throw new Error("Tangle Sandbox process wait returned an invalid exit code");
|
|
165
|
-
const status = exactProcessStatus(await process.status(), pid);
|
|
166
|
-
if (status.running || !status.termination) throw new Error("Tangle Sandbox process wait returned before terminal status");
|
|
167
|
-
if (status.termination.kind === "exit" && status.termination.exitCode !== waitExitCode) throw new Error("Tangle Sandbox process wait and status disagree on exit code");
|
|
168
|
-
return status.termination;
|
|
169
|
-
},
|
|
170
|
-
async kill() {
|
|
171
|
-
await process.kill("SIGKILL", { tree: true });
|
|
172
|
-
},
|
|
173
|
-
async *stdout() {
|
|
174
|
-
yield* process.stdout();
|
|
175
|
-
},
|
|
176
|
-
async *stderr() {
|
|
177
|
-
yield* process.stderr();
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function exactProcessStatus(status, expectedPid) {
|
|
182
|
-
const pid = positiveInteger$1(status.pid, "Tangle Sandbox process pid");
|
|
183
|
-
if (expectedPid !== void 0 && pid !== expectedPid) throw new Error("Tangle Sandbox process status changed process identity");
|
|
184
|
-
if (typeof status.running !== "boolean") throw new Error("Tangle Sandbox process status is missing running state");
|
|
185
|
-
if (!Number.isSafeInteger(status.exitCode)) throw new Error("Tangle Sandbox process status is missing an integer exit code");
|
|
186
|
-
const exitSignal = optionalText(status.exitSignal, "Tangle Sandbox process exit signal");
|
|
187
|
-
if (status.running) {
|
|
188
|
-
if (status.exitCode !== -1) throw new Error("Tangle Sandbox running process must report exit code -1");
|
|
189
|
-
if (exitSignal) throw new Error("Tangle Sandbox running process must not report an exit signal");
|
|
190
|
-
return {
|
|
191
|
-
pid,
|
|
192
|
-
running: true,
|
|
193
|
-
exitCode: -1
|
|
194
|
-
};
|
|
59
|
+
const HTTP_MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
60
|
+
/** A remote MCP endpoint refused the connection before the handshake completed. */
|
|
61
|
+
var McpConnectFault = class extends Error {
|
|
62
|
+
status;
|
|
63
|
+
constructor(message, status) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.status = status;
|
|
66
|
+
this.name = "McpConnectFault";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const SSE_DATA_LINE = /^data:\s?(.*)$/s;
|
|
70
|
+
function parseSseBody(body, wantId) {
|
|
71
|
+
for (const chunk of body.split(/\r?\n\r?\n/)) for (const line of chunk.split(/\r?\n/)) {
|
|
72
|
+
const match = SSE_DATA_LINE.exec(line);
|
|
73
|
+
if (!match) continue;
|
|
74
|
+
try {
|
|
75
|
+
const parsed = JSON.parse(match[1] ?? "");
|
|
76
|
+
if (parsed.id === wantId) return parsed;
|
|
77
|
+
} catch {}
|
|
195
78
|
}
|
|
196
|
-
const termination = exitSignal ? {
|
|
197
|
-
kind: "signal",
|
|
198
|
-
signal: exitSignal
|
|
199
|
-
} : status.exitCode >= 0 ? {
|
|
200
|
-
kind: "exit",
|
|
201
|
-
exitCode: status.exitCode
|
|
202
|
-
} : void 0;
|
|
203
|
-
if (!termination) throw new Error("Tangle Sandbox stopped process has no terminal reason");
|
|
204
|
-
return {
|
|
205
|
-
pid,
|
|
206
|
-
running: false,
|
|
207
|
-
exitCode: status.exitCode,
|
|
208
|
-
...exitSignal ? { exitSignal } : {},
|
|
209
|
-
termination
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
function exactMetadata(metadata, provider, egressPolicy) {
|
|
213
|
-
for (const marker of [exactProcessProviderMarker, exactProcessEgressMarker]) if (Object.hasOwn(metadata, marker)) throw new Error(`exact-process metadata must not set "${marker}"`);
|
|
214
|
-
return {
|
|
215
|
-
...metadata,
|
|
216
|
-
[exactProcessProviderMarker]: provider,
|
|
217
|
-
[exactProcessEgressMarker]: serializeEgressPolicy(egressPolicy)
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
function isExactSandbox(sandbox, provider) {
|
|
221
|
-
return sandbox.metadata?.[exactProcessProviderMarker] === provider;
|
|
222
|
-
}
|
|
223
|
-
function metadataMatches(metadata, expected) {
|
|
224
|
-
return expected === void 0 || Object.entries(expected).every(([key, value]) => isDeepStrictEqual(metadata?.[key], value));
|
|
225
79
|
}
|
|
226
|
-
function
|
|
227
|
-
|
|
80
|
+
function redactValuesFrom(text, values) {
|
|
81
|
+
let out = text;
|
|
82
|
+
for (const value of values) if (value.length > 0) out = out.split(value).join("[redacted]");
|
|
83
|
+
return out;
|
|
228
84
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
85
|
+
/** Connect to a remote MCP endpoint: initialize, list tools, return the live connection. */
|
|
86
|
+
async function connectHttpMcp(spec) {
|
|
87
|
+
let endpoint;
|
|
232
88
|
try {
|
|
233
|
-
|
|
234
|
-
if (!parsed || typeof parsed !== "object") throw new Error("expected egress object");
|
|
235
|
-
const policy = parsed;
|
|
236
|
-
if (policy.mode === "blocked" && policy.allowDomains === void 0) return { mode: "blocked" };
|
|
237
|
-
if (policy.mode === "strict" && policy.includeImplicitDomains === false && Array.isArray(policy.allowDomains) && policy.allowDomains.every((domain) => typeof domain === "string")) {
|
|
238
|
-
const allowDomains = sortedDomains(policy.allowDomains);
|
|
239
|
-
if (new Set(allowDomains).size === allowDomains.length) return {
|
|
240
|
-
mode: "strict",
|
|
241
|
-
allowDomains,
|
|
242
|
-
includeImplicitDomains: false
|
|
243
|
-
};
|
|
244
|
-
}
|
|
89
|
+
endpoint = new URL(spec.url);
|
|
245
90
|
} catch {
|
|
246
|
-
throw new
|
|
247
|
-
}
|
|
248
|
-
throw new Error("Tangle Sandbox exact-process environment has invalid egress metadata");
|
|
249
|
-
}
|
|
250
|
-
async function assertExactSandboxEgress(sandbox, expected) {
|
|
251
|
-
const actual = (await sandbox.egress.get()).policy;
|
|
252
|
-
if (actual.mode !== expected.mode) throw new Error(`Tangle Sandbox egress mismatch: expected ${expected.mode}, received ${actual.mode}`);
|
|
253
|
-
if (expected.mode === "blocked") {
|
|
254
|
-
const allowDomains = actual.allowDomains;
|
|
255
|
-
if (actual.mode === "blocked" && (allowDomains === void 0 || Array.isArray(allowDomains) && allowDomains.length === 0)) return;
|
|
256
|
-
throw new Error("Tangle Sandbox blocked egress retained an allowlist");
|
|
257
|
-
}
|
|
258
|
-
if (actual.mode !== "strict") throw new Error("Tangle Sandbox did not return strict egress policy");
|
|
259
|
-
const expectedDomains = sortedDomains(expected.allowDomains);
|
|
260
|
-
if (!isDeepStrictEqual(sortedDomains(actual.allowDomains ?? []), expectedDomains)) throw new Error("Tangle Sandbox strict egress differs from the exact allowlist");
|
|
261
|
-
if (actual.includeImplicitDomains !== false) throw new Error("Tangle Sandbox strict egress retained implicit domains");
|
|
262
|
-
}
|
|
263
|
-
function sandboxEgressPolicy(input) {
|
|
264
|
-
if (input.mode === "blocked") return { mode: "blocked" };
|
|
265
|
-
const allowDomains = input.allowDomains.map((domain) => requiredText(domain, "strict egress domain"));
|
|
266
|
-
if (new Set(allowDomains).size !== allowDomains.length) throw new Error("strict egress domains must not contain duplicates");
|
|
267
|
-
return {
|
|
268
|
-
mode: "strict",
|
|
269
|
-
allowDomains,
|
|
270
|
-
includeImplicitDomains: false
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
function serializeEgressPolicy(policy) {
|
|
274
|
-
return JSON.stringify(policy.mode === "blocked" ? { mode: "blocked" } : {
|
|
275
|
-
mode: "strict",
|
|
276
|
-
allowDomains: sortedDomains(policy.allowDomains),
|
|
277
|
-
includeImplicitDomains: false
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
function sandboxResources(input) {
|
|
281
|
-
const cpuCores = positiveNumber(input.resources.cpu, "exact-process cpu");
|
|
282
|
-
const memoryMB = positiveInteger$1(input.resources.memoryMb, "exact-process memory");
|
|
283
|
-
const diskMb = positiveInteger$1(input.resources.diskMb, "exact-process disk");
|
|
284
|
-
if (diskMb % 1024 !== 0) throw new Error("Tangle Sandbox exact-process disk must be a whole GiB");
|
|
285
|
-
return {
|
|
286
|
-
cpuCores,
|
|
287
|
-
memoryMB,
|
|
288
|
-
diskGB: diskMb / 1024
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
function sandboxLifetimeSeconds(maxLifetimeMs) {
|
|
292
|
-
const milliseconds = positiveInteger$1(maxLifetimeMs, "exact-process maximum lifetime");
|
|
293
|
-
if (milliseconds % 1e3 !== 0) throw new Error("Tangle Sandbox exact-process maximum lifetime must be a whole number of seconds");
|
|
294
|
-
return milliseconds / 1e3;
|
|
295
|
-
}
|
|
296
|
-
function fileMode(value) {
|
|
297
|
-
const mode = nonnegativeInteger(value, "exact-process file mode");
|
|
298
|
-
if (mode > 4095) throw new Error("exact-process file mode exceeds POSIX mode bits");
|
|
299
|
-
return mode;
|
|
300
|
-
}
|
|
301
|
-
function assertNoProviderOptions(providerOptions) {
|
|
302
|
-
if (providerOptions && Object.keys(providerOptions).length > 0) throw new Error("Tangle Sandbox exact-process provider does not accept providerOptions");
|
|
303
|
-
}
|
|
304
|
-
function exactProcessOnlyCapabilities() {
|
|
305
|
-
return {
|
|
306
|
-
profile: {
|
|
307
|
-
namedProfiles: false,
|
|
308
|
-
systemPrompt: {
|
|
309
|
-
replace: false,
|
|
310
|
-
append: false
|
|
311
|
-
},
|
|
312
|
-
instructions: false,
|
|
313
|
-
tools: false,
|
|
314
|
-
permissions: false,
|
|
315
|
-
mcp: false,
|
|
316
|
-
subagents: false,
|
|
317
|
-
resources: {
|
|
318
|
-
files: false,
|
|
319
|
-
instructions: false,
|
|
320
|
-
tools: false,
|
|
321
|
-
skills: false,
|
|
322
|
-
agents: false,
|
|
323
|
-
commands: false
|
|
324
|
-
},
|
|
325
|
-
hooks: false,
|
|
326
|
-
modes: false,
|
|
327
|
-
runtimeUpdate: false,
|
|
328
|
-
validation: false
|
|
329
|
-
},
|
|
330
|
-
streaming: {
|
|
331
|
-
live: false,
|
|
332
|
-
replay: false,
|
|
333
|
-
detach: false,
|
|
334
|
-
turnIdempotency: false
|
|
335
|
-
},
|
|
336
|
-
sessions: {
|
|
337
|
-
continue: false,
|
|
338
|
-
list: false,
|
|
339
|
-
messages: false
|
|
340
|
-
},
|
|
341
|
-
workspace: {
|
|
342
|
-
read: false,
|
|
343
|
-
write: false,
|
|
344
|
-
exec: false,
|
|
345
|
-
git: false,
|
|
346
|
-
upload: false,
|
|
347
|
-
download: false
|
|
348
|
-
},
|
|
349
|
-
branching: {
|
|
350
|
-
checkpoint: false,
|
|
351
|
-
fork: false
|
|
352
|
-
},
|
|
353
|
-
placement: false,
|
|
354
|
-
usage: false,
|
|
355
|
-
confidential: false,
|
|
356
|
-
exactProcess: { egress: ["blocked", "strict"] }
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
async function discardInvalidSandbox(sandbox, cause) {
|
|
360
|
-
try {
|
|
361
|
-
await sandbox.delete();
|
|
362
|
-
} catch (destroyError) {
|
|
363
|
-
throw new AggregateError([cause, destroyError], "Tangle Sandbox exact-process creation failed and cleanup failed");
|
|
364
|
-
}
|
|
365
|
-
throw cause;
|
|
366
|
-
}
|
|
367
|
-
function sortedDomains(domains) {
|
|
368
|
-
return [...domains].sort((left, right) => left.localeCompare(right));
|
|
369
|
-
}
|
|
370
|
-
function requiredText(value, label) {
|
|
371
|
-
if (typeof value !== "string" || !value.trim()) throw new Error(`${label} must be a non-empty string`);
|
|
372
|
-
return value;
|
|
373
|
-
}
|
|
374
|
-
function optionalText(value, label) {
|
|
375
|
-
if (value === void 0) return void 0;
|
|
376
|
-
return requiredText(value, label);
|
|
377
|
-
}
|
|
378
|
-
function positiveNumber(value, label) {
|
|
379
|
-
if (!Number.isFinite(value) || value <= 0) throw new Error(`${label} must be positive`);
|
|
380
|
-
return value;
|
|
381
|
-
}
|
|
382
|
-
function positiveInteger$1(value, label) {
|
|
383
|
-
if (!Number.isSafeInteger(value) || value < 1) throw new Error(`${label} must be a positive integer`);
|
|
384
|
-
return value;
|
|
385
|
-
}
|
|
386
|
-
function nonnegativeInteger(value, label) {
|
|
387
|
-
if (!Number.isSafeInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer`);
|
|
388
|
-
return value;
|
|
389
|
-
}
|
|
390
|
-
function throwIfAborted(signal) {
|
|
391
|
-
signal?.throwIfAborted();
|
|
392
|
-
}
|
|
393
|
-
async function afterAbortCheck(signal, operation) {
|
|
394
|
-
throwIfAborted(signal);
|
|
395
|
-
const result = await operation();
|
|
396
|
-
throwIfAborted(signal);
|
|
397
|
-
return result;
|
|
398
|
-
}
|
|
399
|
-
//#endregion
|
|
400
|
-
//#region src/runtime/http-mcp-client.ts
|
|
401
|
-
/**
|
|
402
|
-
* `connectHttpMcp` — the remote (streamable HTTP) MCP client, sibling of
|
|
403
|
-
* `connectStdioMcp`. Same connection contract (`tools`, `callTool`, `close`),
|
|
404
|
-
* same error semantics (a JSON-RPC error / `isError` result is the agent's
|
|
405
|
-
* `ERROR: …` outcome; a transport fault or timeout throws), no child process —
|
|
406
|
-
* which is the point: this is the MCP path for environments that cannot spawn
|
|
407
|
-
* stdio servers (Workers, browser-context agents, locked-down sandboxes) and
|
|
408
|
-
* for servers that only exist as endpoints (a remote Hindsight, a hosted MCP).
|
|
409
|
-
*
|
|
410
|
-
* Transport: MCP "streamable HTTP" (protocol 2025-03-26 / 2025-06-18). Every
|
|
411
|
-
* request is a POST with `Accept: application/json, text/event-stream`; the
|
|
412
|
-
* server may answer either shape, so both are parsed. A server-assigned
|
|
413
|
-
* `Mcp-Session-Id` response header is captured and replayed on every later
|
|
414
|
-
* request (and the DELETE on close) — stateful servers refuse without it,
|
|
415
|
-
* stateless ones simply never send it.
|
|
416
|
-
*
|
|
417
|
-
* Auth headers can be protected values: they are sent to the server but never
|
|
418
|
-
* allowed back out — error messages and tool results are redacted against the
|
|
419
|
-
* exact protected values, mirroring `connectStdioMcp`'s protectedEnv handling.
|
|
420
|
-
*/
|
|
421
|
-
const HTTP_MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
422
|
-
/** A remote MCP endpoint refused the connection before the handshake completed. */
|
|
423
|
-
var McpConnectFault = class extends Error {
|
|
424
|
-
status;
|
|
425
|
-
constructor(message, status) {
|
|
426
|
-
super(message);
|
|
427
|
-
this.status = status;
|
|
428
|
-
this.name = "McpConnectFault";
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
const SSE_DATA_LINE = /^data:\s?(.*)$/s;
|
|
432
|
-
function parseSseBody(body, wantId) {
|
|
433
|
-
for (const chunk of body.split(/\r?\n\r?\n/)) for (const line of chunk.split(/\r?\n/)) {
|
|
434
|
-
const match = SSE_DATA_LINE.exec(line);
|
|
435
|
-
if (!match) continue;
|
|
436
|
-
try {
|
|
437
|
-
const parsed = JSON.parse(match[1] ?? "");
|
|
438
|
-
if (parsed.id === wantId) return parsed;
|
|
439
|
-
} catch {}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
function redactValuesFrom(text, values) {
|
|
443
|
-
let out = text;
|
|
444
|
-
for (const value of values) if (value.length > 0) out = out.split(value).join("[redacted]");
|
|
445
|
-
return out;
|
|
446
|
-
}
|
|
447
|
-
/** Connect to a remote MCP endpoint: initialize, list tools, return the live connection. */
|
|
448
|
-
async function connectHttpMcp(spec) {
|
|
449
|
-
let endpoint;
|
|
450
|
-
try {
|
|
451
|
-
endpoint = new URL(spec.url);
|
|
452
|
-
} catch {
|
|
453
|
-
throw new ValidationError(`connectHttpMcp: invalid MCP endpoint URL: ${spec.url}`);
|
|
91
|
+
throw new ValidationError(`connectHttpMcp: invalid MCP endpoint URL: ${spec.url}`);
|
|
454
92
|
}
|
|
455
93
|
if (endpoint.protocol !== "https:" && endpoint.hostname !== "localhost" && endpoint.hostname !== "127.0.0.1") throw new ValidationError(`connectHttpMcp: refusing non-HTTPS MCP endpoint ${endpoint.origin} (localhost excepted) — a bearer or api key on plain HTTP would cross the network in the clear`);
|
|
456
94
|
const fetchImpl = spec.fetchImpl ?? fetch;
|
|
@@ -6398,196 +6036,6 @@ function hashText(value) {
|
|
|
6398
6036
|
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
6399
6037
|
}
|
|
6400
6038
|
//#endregion
|
|
6401
|
-
//#region src/runtime/authored-code.ts
|
|
6402
|
-
/**
|
|
6403
|
-
* The ONE lint over model-authored source.
|
|
6404
|
-
*
|
|
6405
|
-
* Authored optimization strategies use this static contract lint. General Runtime code-mode
|
|
6406
|
-
* scripts execute in the isolated QuickJS/WASM engine instead of relying on source lint.
|
|
6407
|
-
*
|
|
6408
|
-
* A LINT, NOT A SANDBOX — it reads text and cannot constrain what running code does, and trivial
|
|
6409
|
-
* concatenation defeats any token match. Its only job is refusing the obvious escapes so a typo or
|
|
6410
|
-
* a lazy model does not run; it is never the security boundary. Isolation, where required, is the
|
|
6411
|
-
* execution boundary's job (a jailed runner, a sandboxed loader), never this check's.
|
|
6412
|
-
*/
|
|
6413
|
-
/** Refuse the obvious escapes in authored source. See the module doc for what this is NOT. */
|
|
6414
|
-
function assertAuthoredCode(code, options = {}) {
|
|
6415
|
-
const context = options.context ?? "authored code";
|
|
6416
|
-
const allowed = options.allowedImports ?? [];
|
|
6417
|
-
for (const line of code.split("\n")) {
|
|
6418
|
-
if (!/^\s*import\s/.test(line)) continue;
|
|
6419
|
-
if (!allowed.some((specifier) => line.includes(`'${specifier}'`) || line.includes(`"${specifier}"`))) throw new ValidationError(`${context} rejected: foreign import — ${line.trim().slice(0, 120)}${allowed.length === 0 ? " (no import is allowed here)" : ` (allowed: ${allowed.join(", ")})`}`);
|
|
6420
|
-
}
|
|
6421
|
-
for (const [pattern, what] of [
|
|
6422
|
-
[/\brequire\s*\(/, "require()"],
|
|
6423
|
-
[/\bimport\s*\(/, "dynamic import()"],
|
|
6424
|
-
[/\beval\s*\(/, "eval()"],
|
|
6425
|
-
[/new\s+Function\s*\(/, "new Function()"],
|
|
6426
|
-
[/\bprocess\s*[.[]/, "process access"],
|
|
6427
|
-
[/\bglobalThis\s*[.[]/, "globalThis access"],
|
|
6428
|
-
[/\bfetch\s*\(/, "network access"],
|
|
6429
|
-
[/child_process|node:fs|node:net|node:http|worker_threads/, "node builtin access"]
|
|
6430
|
-
]) if (pattern.test(code)) throw new ValidationError(`${context} rejected: ${what}`);
|
|
6431
|
-
}
|
|
6432
|
-
//#endregion
|
|
6433
|
-
//#region src/runtime/strategy-author.ts
|
|
6434
|
-
/**
|
|
6435
|
-
* authorStrategy — the agent-authored layer as a package primitive (software-3.0): an
|
|
6436
|
-
* LLM reads a benchmark's per-task LOSSES + the defineStrategy contract and writes a NEW
|
|
6437
|
-
* optimization strategy as code; the caller gates it like any human-built candidate
|
|
6438
|
-
* (runBenchmark + a frozen holdout).
|
|
6439
|
-
*
|
|
6440
|
-
* Brokered shot()/critique() calls spend through the Supervisor's conserved pool.
|
|
6441
|
-
* Source validation checks obvious forbidden operations; it is not an execution sandbox.
|
|
6442
|
-
* Code that uses other execution paths can access state or spend outside that pool.
|
|
6443
|
-
* Callers must provide isolation when authored code requires an enforced boundary.
|
|
6444
|
-
*
|
|
6445
|
-
* The authored module is written to `outDir` and dynamically imported — run under a
|
|
6446
|
-
* TS-capable loader (tsx) since models often emit type annotations.
|
|
6447
|
-
*/
|
|
6448
|
-
/** The compressed consumable a skill carries: everything an author needs to emit a loop. */
|
|
6449
|
-
const strategyAuthorContract = `
|
|
6450
|
-
You author an OPTIMIZATION STRATEGY for an agentic loop system. A strategy decides how to
|
|
6451
|
-
spend a compute budget to beat a task's deployable check. You compose exactly two steps:
|
|
6452
|
-
|
|
6453
|
-
shot(spec?: { handle?, messages?, steer?, profile?, tools? }): Promise<ShotResult | null>
|
|
6454
|
-
Runs ONE worker attempt (a bounded tool loop) over an artifact.
|
|
6455
|
-
- omit handle => the shot opens its OWN fresh artifact and closes it after (a sample).
|
|
6456
|
-
- pass handle => the shot CONTINUES that artifact (state accumulates across shots).
|
|
6457
|
-
- messages => the carried conversation (pass the previous ShotResult.messages to continue).
|
|
6458
|
-
- steer => a corrective instruction injected before the shot.
|
|
6459
|
-
- profile => a complete AgentProfile — give THIS shot its own instructions,
|
|
6460
|
-
model, skills, tools, hooks, and subagents. Include name, harness, and
|
|
6461
|
-
model: { provider, default }; put standing instructions in prompt.systemPrompt.
|
|
6462
|
-
For example: { ...opts.workerProfile, name: 'researcher',
|
|
6463
|
-
prompt: { ...opts.workerProfile.prompt,
|
|
6464
|
-
systemPrompt: 'Inspect the evidence before proposing a change.' } }.
|
|
6465
|
-
Choose an available model from the current execution setup. Omit profile to use
|
|
6466
|
-
the worker's exact profile. Every shot spends from the same conserved budget.
|
|
6467
|
-
- tools => string[] — restrict THIS shot to a subset of the task's tools by
|
|
6468
|
-
name (focus an explore shot on read-only tools, an execute shot on write tools).
|
|
6469
|
-
Restriction-only; unknown names make the shot fail. ALWAYS select from
|
|
6470
|
-
await listTools(handle) — never hardcode. Omitted => the shot sees every tool.
|
|
6471
|
-
ShotResult = { messages, score (0..1 on the task's check), passes, total, completions, toolErrors }
|
|
6472
|
-
Returns null if the attempt failed infra-wise.
|
|
6473
|
-
|
|
6474
|
-
critique(messages): Promise<string | null>
|
|
6475
|
-
A firewalled trace-analyst reads the attempt's trajectory and returns ONE corrective
|
|
6476
|
-
instruction (or null when it judges the work complete). Costs ~1 completion.
|
|
6477
|
-
|
|
6478
|
-
consult(messages, instruction): Promise<string | null>
|
|
6479
|
-
The RAW analyst channel: the same firewalled critic answers YOUR instruction over the
|
|
6480
|
-
trajectory verbatim (no reformatting) — use it when you need a specific reply format
|
|
6481
|
-
(a decision, a prediction). Costs ~1 completion.
|
|
6482
|
-
|
|
6483
|
-
surface.open(task) / surface.close(handle)
|
|
6484
|
-
Open a persistent artifact you manage yourself (remember to close in a finally).
|
|
6485
|
-
close is idempotent — closing an already-closed handle is a safe no-op.
|
|
6486
|
-
|
|
6487
|
-
listTools(handle): Promise<Array<{ name, description? }>>
|
|
6488
|
-
The tools THIS task actually offers. TOOL SETS VARY PER TASK — if you restrict a
|
|
6489
|
-
shot with \`tools\`, you MUST pick names from await listTools(handle); hardcoding
|
|
6490
|
-
names from an example kills your shots on every task whose tools differ.
|
|
6491
|
-
|
|
6492
|
-
Rules:
|
|
6493
|
-
- ALWAYS await every shot/critique/surface call — a floating promise that rejects
|
|
6494
|
-
crashes the whole benchmark run.
|
|
6495
|
-
- Stay within ~budget total shots; every shot/critique spends from a conserved pool.
|
|
6496
|
-
- For a FRESH attempt OMIT \`messages\` entirely (never pass \`[]\` — an empty array is a
|
|
6497
|
-
fresh conversation too, but be explicit). To CONTINUE, pass the previous
|
|
6498
|
-
ShotResult.messages unchanged.
|
|
6499
|
-
- Return { score, resolved, completions, progression, shots } — score = the BEST checkpoint
|
|
6500
|
-
you reached (keep-best, never final-state), progression = score after each shot.
|
|
6501
|
-
- The module must be EXACTLY this shape (no other imports, no commentary outside code):
|
|
6502
|
-
|
|
6503
|
-
import { defineStrategy } from '@tangle-network/agent-runtime/kernel'
|
|
6504
|
-
export default defineStrategy('your-strategy-name', async ({ surface, task, opts, budget, shot, critique, listTools }) => {
|
|
6505
|
-
// your composition (listTools comes from the destructured context — it is NOT a global)
|
|
6506
|
-
})
|
|
6507
|
-
`;
|
|
6508
|
-
/** Standing behavior callers put in the strategy-author AgentProfile. */
|
|
6509
|
-
const strategyAuthorSystemPrompt = "You are a senior researcher authoring optimization strategies for agent loops: you read per-task losses like experimental data, form a mechanism-level hypothesis, and author the one composition that tests it. Output exactly one fenced ```ts code block and nothing else.";
|
|
6510
|
-
/** Static CONTRACT lint over an authored strategy module — the module-boundary
|
|
6511
|
-
* enforcement of the harness's two measurement invariants:
|
|
6512
|
-
* - author blindness: the only import allowed is the kernel surface. A body that could
|
|
6513
|
-
* reach the filesystem, network, or process could read or mutate verifier/artifact
|
|
6514
|
-
* state outside the brokered shots, and the harness-verified score would stop
|
|
6515
|
-
* meaning "what the shots achieved".
|
|
6516
|
-
* - conserved dose: no out-of-band compute (fetch/require/eval) — every unit a
|
|
6517
|
-
* strategy spends is metered by the Supervisor's pool, which is what makes
|
|
6518
|
-
* equal-budget comparisons between strategies valid.
|
|
6519
|
-
* A lint, not a sandbox: its job is keeping the benchmark numbers interpretable. */
|
|
6520
|
-
function assertStrategyContract(code) {
|
|
6521
|
-
assertAuthoredCode(code, { allowedImports: ["@tangle-network/agent-runtime/kernel"] });
|
|
6522
|
-
}
|
|
6523
|
-
/** Ask the author for a strategy module. A failed call throws; a reply without a fenced
|
|
6524
|
-
* module is `code: null`. With `fallbackProfile`, the fallback gets one attempt when the
|
|
6525
|
-
* primary call fails or its reply carries no module. */
|
|
6526
|
-
async function requestStrategySource(opts) {
|
|
6527
|
-
const turns = [];
|
|
6528
|
-
const attempt = async (profile) => {
|
|
6529
|
-
const res = await profileChatClient({
|
|
6530
|
-
profile,
|
|
6531
|
-
executor: opts.executor,
|
|
6532
|
-
context: "strategy author"
|
|
6533
|
-
}).chat({ messages: [{
|
|
6534
|
-
role: "user",
|
|
6535
|
-
content: `${opts.contract ?? strategyAuthorContract}\n\nBASELINE RESULTS on the "${opts.environmentName}" environment (budget=${opts.budget}) — the per-task losses are your gradient:\n${opts.lossesJson}\n\nAuthor ONE new strategy that you expect to beat the baselines on THIS environment at the same budget.\n${strategyAuthorMethod}\n\nOutput only the module code block.`
|
|
6536
|
-
}] }, { ...opts.signal ? { signal: opts.signal } : {} });
|
|
6537
|
-
turns.push({
|
|
6538
|
-
content: res.content,
|
|
6539
|
-
model: res.model,
|
|
6540
|
-
inputTokens: res.usage.promptTokens,
|
|
6541
|
-
outputTokens: res.usage.completionTokens,
|
|
6542
|
-
tokensKnown: res.usage.captured !== false,
|
|
6543
|
-
costUsd: res.costUsd
|
|
6544
|
-
});
|
|
6545
|
-
return res.content.match(/```(?:ts|typescript)?\s*\n([\s\S]*?)```/)?.[1] ?? null;
|
|
6546
|
-
};
|
|
6547
|
-
try {
|
|
6548
|
-
const code = await attempt(opts.profile);
|
|
6549
|
-
if (code !== null || !opts.fallbackProfile) return {
|
|
6550
|
-
code,
|
|
6551
|
-
turns
|
|
6552
|
-
};
|
|
6553
|
-
} catch (primaryError) {
|
|
6554
|
-
if (!opts.fallbackProfile) throw primaryError;
|
|
6555
|
-
}
|
|
6556
|
-
return {
|
|
6557
|
-
code: await attempt(opts.fallbackProfile),
|
|
6558
|
-
turns
|
|
6559
|
-
};
|
|
6560
|
-
}
|
|
6561
|
-
/** Lint an authored module, write it under `outDir` at a name its content fixes, and import
|
|
6562
|
-
* its default Strategy. The same source always loads from the same file. Throws when the
|
|
6563
|
-
* module breaks the contract or exports no Strategy. */
|
|
6564
|
-
async function loadAuthoredStrategy(code, outDir) {
|
|
6565
|
-
assertStrategyContract(code);
|
|
6566
|
-
const file = join(outDir, `strategy-${sha256Bytes$1(Buffer.from(code, "utf8")).slice(7)}.mts`);
|
|
6567
|
-
if (!existsSync(file)) {
|
|
6568
|
-
mkdirSync(outDir, { recursive: true });
|
|
6569
|
-
const partial = `${file}.${process.pid}.tmp`;
|
|
6570
|
-
writeFileSync(partial, code);
|
|
6571
|
-
renameSync(partial, file);
|
|
6572
|
-
}
|
|
6573
|
-
const mod = await import(pathToFileURL(file).href);
|
|
6574
|
-
if (!mod.default || typeof mod.default.driver !== "function" || !mod.default.name) throw new Error(`authorStrategy: ${file} does not export a default Strategy`);
|
|
6575
|
-
return {
|
|
6576
|
-
strategy: mod.default,
|
|
6577
|
-
file
|
|
6578
|
-
};
|
|
6579
|
-
}
|
|
6580
|
-
/** Author + load a strategy from losses. Throws when the author emits no loadable module;
|
|
6581
|
-
* with `fallbackProfile` set, the fallback gets one attempt first. */
|
|
6582
|
-
async function authorStrategy(opts) {
|
|
6583
|
-
const { code, turns } = await requestStrategySource(opts);
|
|
6584
|
-
if (code === null) throw new Error(`authorStrategy: no code block in the author's reply: ${(turns.at(-1)?.content ?? "").slice(0, 300)}`);
|
|
6585
|
-
return {
|
|
6586
|
-
...await loadAuthoredStrategy(code, opts.outDir),
|
|
6587
|
-
code
|
|
6588
|
-
};
|
|
6589
|
-
}
|
|
6590
|
-
//#endregion
|
|
6591
6039
|
//#region src/runtime/strategy-evolution.ts
|
|
6592
6040
|
/**
|
|
6593
6041
|
* runStrategyEvolution: strategy search on Eval's search kernel (`runSearch`).
|
|
@@ -6623,10 +6071,10 @@ const NO_MODULE = "the author reply carried no fenced ts module";
|
|
|
6623
6071
|
/** Evolve a strategy on the search kernel and claim once on the sealed test split. */
|
|
6624
6072
|
async function runStrategyEvolution(cfg) {
|
|
6625
6073
|
const root = cfg.root ?? refine;
|
|
6626
|
-
const budget = positiveInteger("budget", cfg.budget ?? 3);
|
|
6627
|
-
const concurrency = positiveInteger("concurrency", cfg.concurrency ?? 3);
|
|
6074
|
+
const budget = positiveInteger$1("budget", cfg.budget ?? 3);
|
|
6075
|
+
const concurrency = positiveInteger$1("concurrency", cfg.concurrency ?? 3);
|
|
6628
6076
|
const maxExpansions = nonNegativeInteger("maxExpansions", cfg.maxExpansions ?? 4);
|
|
6629
|
-
const maxAttempts = positiveInteger("maxAttempts", cfg.maxAttempts ?? 3);
|
|
6077
|
+
const maxAttempts = positiveInteger$1("maxAttempts", cfg.maxAttempts ?? 3);
|
|
6630
6078
|
const seed = nonNegativeInteger("seed", cfg.seed ?? 42);
|
|
6631
6079
|
const cellUsd = dollars("cellUsd", cfg.cellUsd) ?? 0;
|
|
6632
6080
|
const maxUsd = dollars("maxUsd", cfg.maxUsd);
|
|
@@ -7213,7 +6661,7 @@ function shareText(error) {
|
|
|
7213
6661
|
function compare(left, right) {
|
|
7214
6662
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
7215
6663
|
}
|
|
7216
|
-
function positiveInteger(name, value) {
|
|
6664
|
+
function positiveInteger$1(name, value) {
|
|
7217
6665
|
if (!Number.isSafeInteger(value) || value < 1) throw new ConfigError(`evolution: ${name} must be a positive integer`);
|
|
7218
6666
|
return value;
|
|
7219
6667
|
}
|
|
@@ -7477,7 +6925,7 @@ function graphDesignerExtraTools(env) {
|
|
|
7477
6925
|
})();
|
|
7478
6926
|
if (name === "designer_history") return (async () => {
|
|
7479
6927
|
const args = asRecord(raw ?? {}, "designer_history");
|
|
7480
|
-
const { listGraphRuns } = await import("./graph-registry-
|
|
6928
|
+
const { listGraphRuns } = await import("./graph-registry-By0tUj4S.js").then((n) => n.o);
|
|
7481
6929
|
const all = await listGraphRuns(registry);
|
|
7482
6930
|
return { runs: (args.taskShape === void 0 ? all : all.filter((row) => row.taskDigest === taskShapeDigest(asRecord(args.taskShape, "designer_history.taskShape")))).map(summarize) };
|
|
7483
6931
|
})();
|
|
@@ -7488,7 +6936,7 @@ function graphDesignerExtraTools(env) {
|
|
|
7488
6936
|
if (mode === "replay") {
|
|
7489
6937
|
const digest = args.graphDigest;
|
|
7490
6938
|
if (typeof digest !== "string" || digest.length === 0) throw new ValidationError("designer_run_graph: replay mode requires graphDigest from lookup");
|
|
7491
|
-
const { loadGraph } = await import("./graph-registry-
|
|
6939
|
+
const { loadGraph } = await import("./graph-registry-By0tUj4S.js").then((n) => n.o);
|
|
7492
6940
|
const stored = await loadGraph(registry, digest);
|
|
7493
6941
|
if (!stored) throw new ValidationError(`designer_run_graph: no stored graph ${digest.slice(0, 12)} — re-lookup`);
|
|
7494
6942
|
const graph = env.bindCheck(graphFromStored(stored, () => {
|
|
@@ -9112,6 +8560,368 @@ function fsSurfaceReader(root) {
|
|
|
9112
8560
|
};
|
|
9113
8561
|
}
|
|
9114
8562
|
//#endregion
|
|
8563
|
+
//#region src/runtime/tangle-sandbox-exact-process-provider.ts
|
|
8564
|
+
const exactProcessProviderMarker = "agent-runtime.exact-process-provider";
|
|
8565
|
+
const exactProcessEgressMarker = "agent-runtime.exact-process-egress";
|
|
8566
|
+
/**
|
|
8567
|
+
* Adapt Tangle Sandbox's managed control runtime to Runtime's exact-process provider.
|
|
8568
|
+
*
|
|
8569
|
+
* The adapter deliberately exposes no ordinary agent environment: an exact experiment
|
|
8570
|
+
* must start a fresh Sandbox with no managed agent and launch its declared argv directly.
|
|
8571
|
+
*/
|
|
8572
|
+
function createTangleSandboxExactProcessProvider(client, options = {}) {
|
|
8573
|
+
const name = options.name ?? "tangle-sandbox-exact-process";
|
|
8574
|
+
if (!name.trim()) throw new Error("Tangle Sandbox exact-process provider name must not be empty");
|
|
8575
|
+
return {
|
|
8576
|
+
name,
|
|
8577
|
+
exactProcess: {
|
|
8578
|
+
async create(input) {
|
|
8579
|
+
throwIfAborted(input.signal);
|
|
8580
|
+
assertNoProviderOptions(input.providerOptions);
|
|
8581
|
+
const egressPolicy = sandboxEgressPolicy(input.egress);
|
|
8582
|
+
const metadata = exactMetadata(input.metadata, name, egressPolicy);
|
|
8583
|
+
const sandbox = await client.create({
|
|
8584
|
+
environment: requiredText(input.image, "exact-process image"),
|
|
8585
|
+
agent: false,
|
|
8586
|
+
bare: false,
|
|
8587
|
+
ephemeral: true,
|
|
8588
|
+
egressPolicy,
|
|
8589
|
+
resources: sandboxResources(input),
|
|
8590
|
+
maxLifetimeSeconds: sandboxLifetimeSeconds(input.maxLifetimeMs),
|
|
8591
|
+
metadata,
|
|
8592
|
+
idempotencyKey: requiredText(input.idempotencyKey, "exact-process idempotency key")
|
|
8593
|
+
}, {
|
|
8594
|
+
...input.provisionTimeoutMs === void 0 ? {} : { timeoutMs: positiveInteger(input.provisionTimeoutMs, "provision timeout") },
|
|
8595
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
8596
|
+
});
|
|
8597
|
+
try {
|
|
8598
|
+
throwIfAborted(input.signal);
|
|
8599
|
+
assertExactSandboxMetadata(sandbox, metadata);
|
|
8600
|
+
await assertExactSandboxEgress(sandbox, egressPolicy);
|
|
8601
|
+
} catch (error) {
|
|
8602
|
+
await discardInvalidSandbox(sandbox, error);
|
|
8603
|
+
}
|
|
8604
|
+
return sandboxAsExactProcessEnvironment(sandbox, name);
|
|
8605
|
+
},
|
|
8606
|
+
async get(id) {
|
|
8607
|
+
const sandbox = await client.get(id);
|
|
8608
|
+
if (!sandbox || !isExactSandbox(sandbox, name)) return null;
|
|
8609
|
+
await assertExactSandboxEgress(sandbox, egressFromMetadata(sandbox.metadata));
|
|
8610
|
+
return sandboxAsExactProcessEnvironment(sandbox, name);
|
|
8611
|
+
},
|
|
8612
|
+
async list(query) {
|
|
8613
|
+
assertNoProviderOptions(query?.providerOptions);
|
|
8614
|
+
const sandboxes = await client.list();
|
|
8615
|
+
return Promise.all(sandboxes.filter((sandbox) => isExactSandbox(sandbox, name)).filter((sandbox) => metadataMatches(sandbox.metadata, query?.metadata)).map(async (sandbox) => {
|
|
8616
|
+
await assertExactSandboxEgress(sandbox, egressFromMetadata(sandbox.metadata));
|
|
8617
|
+
return sandboxAsExactProcessEnvironment(sandbox, name);
|
|
8618
|
+
}));
|
|
8619
|
+
}
|
|
8620
|
+
},
|
|
8621
|
+
capabilities: exactProcessOnlyCapabilities,
|
|
8622
|
+
async create() {
|
|
8623
|
+
throw new Error(`agent environment provider "${name}" supports exactProcess.create() only`);
|
|
8624
|
+
}
|
|
8625
|
+
};
|
|
8626
|
+
}
|
|
8627
|
+
function sandboxAsExactProcessEnvironment(sandbox, provider) {
|
|
8628
|
+
return {
|
|
8629
|
+
id: requiredText(sandbox.id, "Sandbox id"),
|
|
8630
|
+
provider,
|
|
8631
|
+
...sandbox.metadata ? { metadata: sandbox.metadata } : {},
|
|
8632
|
+
process: {
|
|
8633
|
+
async list() {
|
|
8634
|
+
return (await sandbox.process.list()).map((status) => exactProcessStatus(status));
|
|
8635
|
+
},
|
|
8636
|
+
async get(pid) {
|
|
8637
|
+
const process = await sandbox.process.get(pid);
|
|
8638
|
+
return process ? sandboxProcessAsExactProcess(process) : null;
|
|
8639
|
+
},
|
|
8640
|
+
async spawn(input, options) {
|
|
8641
|
+
return sandboxProcessAsExactProcess(await afterAbortCheck(options?.signal, () => sandbox.process.spawnExact(input.executable, [...input.args], {
|
|
8642
|
+
cwd: input.cwd,
|
|
8643
|
+
env: { ...input.env },
|
|
8644
|
+
inheritEnv: false,
|
|
8645
|
+
...input.stdin === void 0 ? {} : { stdin: input.stdin },
|
|
8646
|
+
timeoutMs: input.timeoutMs
|
|
8647
|
+
})));
|
|
8648
|
+
}
|
|
8649
|
+
},
|
|
8650
|
+
async writeFile(path, bytes, options) {
|
|
8651
|
+
if (sandbox.fs.supportsWriteMode !== true) throw new Error("Tangle Sandbox does not declare exact file-mode support");
|
|
8652
|
+
await afterAbortCheck(options.signal, () => sandbox.fs.write(path, Buffer.from(bytes).toString("base64"), {
|
|
8653
|
+
encoding: "base64",
|
|
8654
|
+
mode: fileMode(options.mode)
|
|
8655
|
+
}));
|
|
8656
|
+
},
|
|
8657
|
+
async readFile(path, options) {
|
|
8658
|
+
const maxBytes = nonnegativeInteger(options.maxBytes, "exact-process file read maximum");
|
|
8659
|
+
const initialSize = nonnegativeInteger((await afterAbortCheck(options.signal, () => sandbox.fs.stat(path))).size, `Tangle Sandbox file size for "${path}"`);
|
|
8660
|
+
if (initialSize > maxBytes) throw new Error(`Tangle Sandbox file "${path}" exceeds the ${maxBytes}-byte exact read maximum`);
|
|
8661
|
+
const result = await afterAbortCheck(options.signal, () => sandbox.fs.readBatch([path], { encoding: "base64" }));
|
|
8662
|
+
const failure = result.errors.find((entry) => entry.path === path);
|
|
8663
|
+
if (failure) throw new Error(`Tangle Sandbox failed to read "${path}": ${failure.error}`);
|
|
8664
|
+
const files = result.files.filter((entry) => entry.path === path);
|
|
8665
|
+
if (files.length !== 1) throw new Error(`Tangle Sandbox returned ${files.length} files for exact read "${path}"`);
|
|
8666
|
+
const file = files[0];
|
|
8667
|
+
if (file.encoding !== "base64") throw new Error(`Tangle Sandbox returned non-binary content for exact read "${path}"`);
|
|
8668
|
+
const size = nonnegativeInteger(file.size, `Tangle Sandbox file size for "${path}"`);
|
|
8669
|
+
if (size !== initialSize) throw new Error(`Tangle Sandbox file "${path}" changed during exact read`);
|
|
8670
|
+
if (size > maxBytes) throw new Error(`Tangle Sandbox file "${path}" exceeds the ${maxBytes}-byte exact read maximum`);
|
|
8671
|
+
const bytes = Buffer.from(file.content, "base64");
|
|
8672
|
+
if (bytes.byteLength !== size || bytes.toString("base64") !== file.content) throw new Error(`Tangle Sandbox returned an invalid binary payload for exact read "${path}"`);
|
|
8673
|
+
return Uint8Array.from(bytes);
|
|
8674
|
+
},
|
|
8675
|
+
async destroy() {
|
|
8676
|
+
await sandbox.delete();
|
|
8677
|
+
}
|
|
8678
|
+
};
|
|
8679
|
+
}
|
|
8680
|
+
function sandboxProcessAsExactProcess(process) {
|
|
8681
|
+
const pid = positiveInteger(process.pid, "Tangle Sandbox process pid");
|
|
8682
|
+
return {
|
|
8683
|
+
pid,
|
|
8684
|
+
async status() {
|
|
8685
|
+
return exactProcessStatus(await process.status(), pid);
|
|
8686
|
+
},
|
|
8687
|
+
async wait() {
|
|
8688
|
+
const waitExitCode = await process.wait();
|
|
8689
|
+
if (!Number.isSafeInteger(waitExitCode)) throw new Error("Tangle Sandbox process wait returned an invalid exit code");
|
|
8690
|
+
const status = exactProcessStatus(await process.status(), pid);
|
|
8691
|
+
if (status.running || !status.termination) throw new Error("Tangle Sandbox process wait returned before terminal status");
|
|
8692
|
+
if (status.termination.kind === "exit" && status.termination.exitCode !== waitExitCode) throw new Error("Tangle Sandbox process wait and status disagree on exit code");
|
|
8693
|
+
return status.termination;
|
|
8694
|
+
},
|
|
8695
|
+
async kill() {
|
|
8696
|
+
await process.kill("SIGKILL", { tree: true });
|
|
8697
|
+
},
|
|
8698
|
+
async *stdout() {
|
|
8699
|
+
yield* process.stdout();
|
|
8700
|
+
},
|
|
8701
|
+
async *stderr() {
|
|
8702
|
+
yield* process.stderr();
|
|
8703
|
+
}
|
|
8704
|
+
};
|
|
8705
|
+
}
|
|
8706
|
+
function exactProcessStatus(status, expectedPid) {
|
|
8707
|
+
const pid = positiveInteger(status.pid, "Tangle Sandbox process pid");
|
|
8708
|
+
if (expectedPid !== void 0 && pid !== expectedPid) throw new Error("Tangle Sandbox process status changed process identity");
|
|
8709
|
+
if (typeof status.running !== "boolean") throw new Error("Tangle Sandbox process status is missing running state");
|
|
8710
|
+
if (!Number.isSafeInteger(status.exitCode)) throw new Error("Tangle Sandbox process status is missing an integer exit code");
|
|
8711
|
+
const exitSignal = optionalText(status.exitSignal, "Tangle Sandbox process exit signal");
|
|
8712
|
+
if (status.running) {
|
|
8713
|
+
if (status.exitCode !== -1) throw new Error("Tangle Sandbox running process must report exit code -1");
|
|
8714
|
+
if (exitSignal) throw new Error("Tangle Sandbox running process must not report an exit signal");
|
|
8715
|
+
return {
|
|
8716
|
+
pid,
|
|
8717
|
+
running: true,
|
|
8718
|
+
exitCode: -1
|
|
8719
|
+
};
|
|
8720
|
+
}
|
|
8721
|
+
const termination = exitSignal ? {
|
|
8722
|
+
kind: "signal",
|
|
8723
|
+
signal: exitSignal
|
|
8724
|
+
} : status.exitCode >= 0 ? {
|
|
8725
|
+
kind: "exit",
|
|
8726
|
+
exitCode: status.exitCode
|
|
8727
|
+
} : void 0;
|
|
8728
|
+
if (!termination) throw new Error("Tangle Sandbox stopped process has no terminal reason");
|
|
8729
|
+
return {
|
|
8730
|
+
pid,
|
|
8731
|
+
running: false,
|
|
8732
|
+
exitCode: status.exitCode,
|
|
8733
|
+
...exitSignal ? { exitSignal } : {},
|
|
8734
|
+
termination
|
|
8735
|
+
};
|
|
8736
|
+
}
|
|
8737
|
+
function exactMetadata(metadata, provider, egressPolicy) {
|
|
8738
|
+
for (const marker of [exactProcessProviderMarker, exactProcessEgressMarker]) if (Object.hasOwn(metadata, marker)) throw new Error(`exact-process metadata must not set "${marker}"`);
|
|
8739
|
+
return {
|
|
8740
|
+
...metadata,
|
|
8741
|
+
[exactProcessProviderMarker]: provider,
|
|
8742
|
+
[exactProcessEgressMarker]: serializeEgressPolicy(egressPolicy)
|
|
8743
|
+
};
|
|
8744
|
+
}
|
|
8745
|
+
function isExactSandbox(sandbox, provider) {
|
|
8746
|
+
return sandbox.metadata?.[exactProcessProviderMarker] === provider;
|
|
8747
|
+
}
|
|
8748
|
+
function metadataMatches(metadata, expected) {
|
|
8749
|
+
return expected === void 0 || Object.entries(expected).every(([key, value]) => isDeepStrictEqual(metadata?.[key], value));
|
|
8750
|
+
}
|
|
8751
|
+
function assertExactSandboxMetadata(sandbox, expected) {
|
|
8752
|
+
if (!metadataMatches(sandbox.metadata, expected)) throw new Error("Tangle Sandbox did not persist exact-process metadata");
|
|
8753
|
+
}
|
|
8754
|
+
function egressFromMetadata(metadata) {
|
|
8755
|
+
const encoded = metadata?.[exactProcessEgressMarker];
|
|
8756
|
+
if (typeof encoded !== "string") throw new Error("Tangle Sandbox exact-process environment is missing egress metadata");
|
|
8757
|
+
try {
|
|
8758
|
+
const parsed = JSON.parse(encoded);
|
|
8759
|
+
if (!parsed || typeof parsed !== "object") throw new Error("expected egress object");
|
|
8760
|
+
const policy = parsed;
|
|
8761
|
+
if (policy.mode === "blocked" && policy.allowDomains === void 0) return { mode: "blocked" };
|
|
8762
|
+
if (policy.mode === "strict" && policy.includeImplicitDomains === false && Array.isArray(policy.allowDomains) && policy.allowDomains.every((domain) => typeof domain === "string")) {
|
|
8763
|
+
const allowDomains = sortedDomains(policy.allowDomains);
|
|
8764
|
+
if (new Set(allowDomains).size === allowDomains.length) return {
|
|
8765
|
+
mode: "strict",
|
|
8766
|
+
allowDomains,
|
|
8767
|
+
includeImplicitDomains: false
|
|
8768
|
+
};
|
|
8769
|
+
}
|
|
8770
|
+
} catch {
|
|
8771
|
+
throw new Error("Tangle Sandbox exact-process environment has invalid egress metadata");
|
|
8772
|
+
}
|
|
8773
|
+
throw new Error("Tangle Sandbox exact-process environment has invalid egress metadata");
|
|
8774
|
+
}
|
|
8775
|
+
async function assertExactSandboxEgress(sandbox, expected) {
|
|
8776
|
+
const actual = (await sandbox.egress.get()).policy;
|
|
8777
|
+
if (actual.mode !== expected.mode) throw new Error(`Tangle Sandbox egress mismatch: expected ${expected.mode}, received ${actual.mode}`);
|
|
8778
|
+
if (expected.mode === "blocked") {
|
|
8779
|
+
const allowDomains = actual.allowDomains;
|
|
8780
|
+
if (actual.mode === "blocked" && (allowDomains === void 0 || Array.isArray(allowDomains) && allowDomains.length === 0)) return;
|
|
8781
|
+
throw new Error("Tangle Sandbox blocked egress retained an allowlist");
|
|
8782
|
+
}
|
|
8783
|
+
if (actual.mode !== "strict") throw new Error("Tangle Sandbox did not return strict egress policy");
|
|
8784
|
+
const expectedDomains = sortedDomains(expected.allowDomains);
|
|
8785
|
+
if (!isDeepStrictEqual(sortedDomains(actual.allowDomains ?? []), expectedDomains)) throw new Error("Tangle Sandbox strict egress differs from the exact allowlist");
|
|
8786
|
+
if (actual.includeImplicitDomains !== false) throw new Error("Tangle Sandbox strict egress retained implicit domains");
|
|
8787
|
+
}
|
|
8788
|
+
function sandboxEgressPolicy(input) {
|
|
8789
|
+
if (input.mode === "blocked") return { mode: "blocked" };
|
|
8790
|
+
const allowDomains = input.allowDomains.map((domain) => requiredText(domain, "strict egress domain"));
|
|
8791
|
+
if (new Set(allowDomains).size !== allowDomains.length) throw new Error("strict egress domains must not contain duplicates");
|
|
8792
|
+
return {
|
|
8793
|
+
mode: "strict",
|
|
8794
|
+
allowDomains,
|
|
8795
|
+
includeImplicitDomains: false
|
|
8796
|
+
};
|
|
8797
|
+
}
|
|
8798
|
+
function serializeEgressPolicy(policy) {
|
|
8799
|
+
return JSON.stringify(policy.mode === "blocked" ? { mode: "blocked" } : {
|
|
8800
|
+
mode: "strict",
|
|
8801
|
+
allowDomains: sortedDomains(policy.allowDomains),
|
|
8802
|
+
includeImplicitDomains: false
|
|
8803
|
+
});
|
|
8804
|
+
}
|
|
8805
|
+
function sandboxResources(input) {
|
|
8806
|
+
const cpuCores = positiveNumber(input.resources.cpu, "exact-process cpu");
|
|
8807
|
+
const memoryMB = positiveInteger(input.resources.memoryMb, "exact-process memory");
|
|
8808
|
+
const diskMb = positiveInteger(input.resources.diskMb, "exact-process disk");
|
|
8809
|
+
if (diskMb % 1024 !== 0) throw new Error("Tangle Sandbox exact-process disk must be a whole GiB");
|
|
8810
|
+
return {
|
|
8811
|
+
cpuCores,
|
|
8812
|
+
memoryMB,
|
|
8813
|
+
diskGB: diskMb / 1024
|
|
8814
|
+
};
|
|
8815
|
+
}
|
|
8816
|
+
function sandboxLifetimeSeconds(maxLifetimeMs) {
|
|
8817
|
+
const milliseconds = positiveInteger(maxLifetimeMs, "exact-process maximum lifetime");
|
|
8818
|
+
if (milliseconds % 1e3 !== 0) throw new Error("Tangle Sandbox exact-process maximum lifetime must be a whole number of seconds");
|
|
8819
|
+
return milliseconds / 1e3;
|
|
8820
|
+
}
|
|
8821
|
+
function fileMode(value) {
|
|
8822
|
+
const mode = nonnegativeInteger(value, "exact-process file mode");
|
|
8823
|
+
if (mode > 4095) throw new Error("exact-process file mode exceeds POSIX mode bits");
|
|
8824
|
+
return mode;
|
|
8825
|
+
}
|
|
8826
|
+
function assertNoProviderOptions(providerOptions) {
|
|
8827
|
+
if (providerOptions && Object.keys(providerOptions).length > 0) throw new Error("Tangle Sandbox exact-process provider does not accept providerOptions");
|
|
8828
|
+
}
|
|
8829
|
+
function exactProcessOnlyCapabilities() {
|
|
8830
|
+
return {
|
|
8831
|
+
profile: {
|
|
8832
|
+
namedProfiles: false,
|
|
8833
|
+
systemPrompt: {
|
|
8834
|
+
replace: false,
|
|
8835
|
+
append: false
|
|
8836
|
+
},
|
|
8837
|
+
instructions: false,
|
|
8838
|
+
tools: false,
|
|
8839
|
+
permissions: false,
|
|
8840
|
+
mcp: false,
|
|
8841
|
+
subagents: false,
|
|
8842
|
+
resources: {
|
|
8843
|
+
files: false,
|
|
8844
|
+
instructions: false,
|
|
8845
|
+
tools: false,
|
|
8846
|
+
skills: false,
|
|
8847
|
+
agents: false,
|
|
8848
|
+
commands: false
|
|
8849
|
+
},
|
|
8850
|
+
hooks: false,
|
|
8851
|
+
modes: false,
|
|
8852
|
+
runtimeUpdate: false,
|
|
8853
|
+
validation: false
|
|
8854
|
+
},
|
|
8855
|
+
streaming: {
|
|
8856
|
+
live: false,
|
|
8857
|
+
replay: false,
|
|
8858
|
+
detach: false,
|
|
8859
|
+
turnIdempotency: false
|
|
8860
|
+
},
|
|
8861
|
+
sessions: {
|
|
8862
|
+
continue: false,
|
|
8863
|
+
list: false,
|
|
8864
|
+
messages: false
|
|
8865
|
+
},
|
|
8866
|
+
workspace: {
|
|
8867
|
+
read: false,
|
|
8868
|
+
write: false,
|
|
8869
|
+
exec: false,
|
|
8870
|
+
git: false,
|
|
8871
|
+
upload: false,
|
|
8872
|
+
download: false
|
|
8873
|
+
},
|
|
8874
|
+
branching: {
|
|
8875
|
+
checkpoint: false,
|
|
8876
|
+
fork: false
|
|
8877
|
+
},
|
|
8878
|
+
placement: false,
|
|
8879
|
+
usage: false,
|
|
8880
|
+
confidential: false,
|
|
8881
|
+
exactProcess: { egress: ["blocked", "strict"] }
|
|
8882
|
+
};
|
|
8883
|
+
}
|
|
8884
|
+
async function discardInvalidSandbox(sandbox, cause) {
|
|
8885
|
+
try {
|
|
8886
|
+
await sandbox.delete();
|
|
8887
|
+
} catch (destroyError) {
|
|
8888
|
+
throw new AggregateError([cause, destroyError], "Tangle Sandbox exact-process creation failed and cleanup failed");
|
|
8889
|
+
}
|
|
8890
|
+
throw cause;
|
|
8891
|
+
}
|
|
8892
|
+
function sortedDomains(domains) {
|
|
8893
|
+
return [...domains].sort((left, right) => left.localeCompare(right));
|
|
8894
|
+
}
|
|
8895
|
+
function requiredText(value, label) {
|
|
8896
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`${label} must be a non-empty string`);
|
|
8897
|
+
return value;
|
|
8898
|
+
}
|
|
8899
|
+
function optionalText(value, label) {
|
|
8900
|
+
if (value === void 0) return void 0;
|
|
8901
|
+
return requiredText(value, label);
|
|
8902
|
+
}
|
|
8903
|
+
function positiveNumber(value, label) {
|
|
8904
|
+
if (!Number.isFinite(value) || value <= 0) throw new Error(`${label} must be positive`);
|
|
8905
|
+
return value;
|
|
8906
|
+
}
|
|
8907
|
+
function positiveInteger(value, label) {
|
|
8908
|
+
if (!Number.isSafeInteger(value) || value < 1) throw new Error(`${label} must be a positive integer`);
|
|
8909
|
+
return value;
|
|
8910
|
+
}
|
|
8911
|
+
function nonnegativeInteger(value, label) {
|
|
8912
|
+
if (!Number.isSafeInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer`);
|
|
8913
|
+
return value;
|
|
8914
|
+
}
|
|
8915
|
+
function throwIfAborted(signal) {
|
|
8916
|
+
signal?.throwIfAborted();
|
|
8917
|
+
}
|
|
8918
|
+
async function afterAbortCheck(signal, operation) {
|
|
8919
|
+
throwIfAborted(signal);
|
|
8920
|
+
const result = await operation();
|
|
8921
|
+
throwIfAborted(signal);
|
|
8922
|
+
return result;
|
|
8923
|
+
}
|
|
8924
|
+
//#endregion
|
|
9115
8925
|
//#region src/runtime/verifier-environment.ts
|
|
9116
8926
|
const submitTool = {
|
|
9117
8927
|
type: "function",
|
|
@@ -9526,6 +9336,6 @@ function tail(s) {
|
|
|
9526
9336
|
return s.slice(-400);
|
|
9527
9337
|
}
|
|
9528
9338
|
//#endregion
|
|
9529
|
-
export {
|
|
9339
|
+
export { trajectoryReport as $, createMcpEnvironment as $t, searchSpecDigest as A, superviseDispatch as At, graphDesignerExtraTools as B, sentinelCompletion as Bt, withUntrackedArtifacts as C, harvestCorpus as Ct, assertSearchSpec as D, inlineSandboxClient as Dt, SEARCH_SPEC_CORRELATION_KEY as E, localSandboxClient as Et, profileRegistry as F, declaredCheckJudge as Ft, strategyTournament as G, renderLeaderboardMarkdown as Gt, chatWorkerSeam as H, leaderboard as Ht, profileRunsForName as I, readDeclaredCheck as It, createS3PrivateCasStore as J, SqlRunOwnershipError as Jt, SandboxRunAbortError as K, renderLeaderboardSvg as Kt, recordProfileRun as L, runIsolatedCheck as Lt, bestProfileFor as M, checkProgramDigest as Mt, loadProfile as N, declaredCheckDeliverable as Nt, compileSearchSpec as O, loopCampaignDispatch as Ot, pickBestProfile as P, declaredCheckDigest as Pt, equalKOnCost as Q, materializeLocalMcp as Qt, patchDelivered as R, completionAuthorizes as Rt, copyUntrackedIntoClone as S, HarvestError as St, createFencedSqlRunContext as T, resolveSandboxClient as Tt, createChatSessionStore as U, pairwiseSignificance as Ut, chatTransportExecutor as V, stopSentinel as Vt, runStrategyEvolution as W, renderLeaderboardHtml as Wt, runBenchmark as X, McpSpawnFault as Xt, printBenchmarkReport as Y, openSqlRunStore as Yt, createPrivateCasArtifactPort as Z, connectStdioMcp as Zt, NOTE_MAX_CHARS as _, buildSteerContext as _t, localShell as a, secretEnvOfMcpServer as an, FileCorpus as at, composeWorkerEvidence as b, observationFromRegistry as bt, createVerifierEnvironment as c, fanout as ct, fsSurfaceReader as d, panel as dt, sanitizeMcpToolSchema as en, definePersona as et, harvestSurfaceDiffs as f, pipeline as ft, EVIDENCE_MAX_CHARS as g, assertTraceDerivedFindings as gt, worktreeFanout as h, widen as ht, jjWorkspace as i, resolveSecretEnv as in, registerShape as it, connectRemoteSupervisor as j, assertDeclaredCheck as jt, searchPresets as k, loopDispatch as kt, createTangleSandboxExactProcessProvider as l, flatWidenGate as lt, failuresAnalyst as m, verify as mt, makeFinding$1 as n, mcpSecretEnvMetadataKey as nn, builtinShapes as nt, runInWorkspace as o, InMemoryCorpus as ot, analystsFromRegistry as p, selectValidWinner as pt, openSandboxRun as q, renderPairwiseMarkdown as qt, gitWorkspace as r, resolveMcpServerLaunch as rn, createShapeRegistry as rt, createWaterfallCollector as s, renderCorpusToInstructions as st, computeFindingId$1 as t, envKeyProvider as tn, runPersonified as tt, boxSurfaceReader as u, loopUntil as ut, VERIFY_TAIL_CHARS as v, createScopeAnalyst as vt, analyzeTrace as w, defineLeaderboard as wt, settledWorkerOut as x, inProcessSandboxClient as xt, closingWorkerNote as y, registryScopeAnalyst as yt, runCoderChecks as z, deterministicCompletion as zt };
|
|
9530
9340
|
|
|
9531
|
-
//# sourceMappingURL=runtime-
|
|
9341
|
+
//# sourceMappingURL=runtime-D37zRSs7.js.map
|