@nylorun/runtime 0.23.0-beta → 0.24.0-beta
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/CHANGELOG.md +148 -0
- package/README.md +79 -28
- package/dist/adapters/execution/restate.js +1 -1
- package/dist/adapters/replication/pgoutput.d.ts +2 -0
- package/dist/adapters/replication/pgoutput.js +6 -3
- package/dist/adapters/sandbox/local.d.ts +9 -1
- package/dist/adapters/sandbox/local.js +16 -4
- package/dist/adapters/sandbox/virtual.js +4 -1
- package/dist/api/a2a/endpoint.js +5 -1
- package/dist/api/a2a/routes.d.ts +2 -0
- package/dist/api/a2a/routes.js +2 -2
- package/dist/api/a2a/tasks.js +2 -1
- package/dist/api/ag-ui/endpoint.js +4 -2
- package/dist/api/ag-ui/history.js +4 -1
- package/dist/api/ag-ui/routes.d.ts +4 -1
- package/dist/api/ag-ui/routes.js +11 -10
- package/dist/api/ag-ui/translate.js +3 -2
- package/dist/api/components.d.ts +4953 -1204
- package/dist/api/components.js +25 -16
- package/dist/api/gate/keys.js +7 -1
- package/dist/api/gate/routes.d.ts +6 -0
- package/dist/api/gate/routes.js +39 -3
- package/dist/api/http/app.js +4 -4
- package/dist/api/http/define.d.ts +6 -0
- package/dist/api/http/define.js +13 -1
- package/dist/api/http/respond.js +1 -1
- package/dist/api/http/routes/artifacts.js +35 -8
- package/dist/api/http/routes/coverage.d.ts +9 -0
- package/dist/api/http/routes/coverage.js +34 -0
- package/dist/api/http/routes/environments.d.ts +11 -0
- package/dist/api/http/routes/environments.js +283 -0
- package/dist/api/http/routes/mcp.d.ts +1 -1
- package/dist/api/http/routes/mcp.js +2 -2
- package/dist/api/http/routes/me.js +1 -1
- package/dist/api/http/routes/reads.d.ts +45 -9
- package/dist/api/http/routes/reads.js +54 -5
- package/dist/api/http/routes/sessions.js +11 -6
- package/dist/api/http/routes/tenant.js +32 -10
- package/dist/api/openapi.js +31 -26
- package/dist/artifacts/disk.d.ts +59 -0
- package/dist/artifacts/disk.js +563 -0
- package/dist/artifacts/export.d.ts +1 -1
- package/dist/artifacts/export.js +2 -3
- package/dist/artifacts/folders.d.ts +6 -3
- package/dist/artifacts/folders.js +17 -12
- package/dist/artifacts/service.d.ts +2 -1
- package/dist/artifacts/service.js +6 -1
- package/dist/artifacts/workspace.d.ts +1 -1
- package/dist/artifacts/workspace.js +1 -1
- package/dist/core/flow-host.d.ts +2 -3
- package/dist/core/flow-host.js +3 -0
- package/dist/core/provider.d.ts +3 -2
- package/dist/core/provider.js +5 -37
- package/dist/core/sandbox-routes.d.ts +2 -21
- package/dist/core/sandbox-routes.js +10 -43
- package/dist/execution/types.d.ts +1 -1
- package/dist/gates/contract.d.ts +3 -24
- package/dist/gates/contract.js +1 -36
- package/dist/gates/egress-credentials.d.ts +9 -0
- package/dist/gates/egress-credentials.js +11 -4
- package/dist/gates/egress.d.ts +28 -1
- package/dist/gates/egress.js +115 -10
- package/dist/gates/fixture-model.d.ts +28 -0
- package/dist/gates/fixture-model.js +92 -0
- package/dist/gates/handler.js +4 -4
- package/dist/gates/http-tool.d.ts +6 -2
- package/dist/gates/http-tool.js +3 -5
- package/dist/gates/in-process.d.ts +5 -0
- package/dist/gates/in-process.js +12 -1
- package/dist/gates/journal.d.ts +30 -0
- package/dist/gates/journal.js +52 -0
- package/dist/gates/mcp-handler.d.ts +4 -0
- package/dist/gates/mcp-handler.js +5 -1
- package/dist/gates/meter.d.ts +10 -2
- package/dist/gates/meter.js +20 -5
- package/dist/gates/policy.d.ts +49 -0
- package/dist/gates/policy.js +134 -0
- package/dist/gates/tenant-vaults.d.ts +7 -7
- package/dist/gates/tenant-vaults.js +5 -5
- package/dist/gates/tool-calls.d.ts +10 -5
- package/dist/gates/tool-calls.js +28 -10
- package/dist/gates/tool-client.d.ts +8 -0
- package/dist/gates/tool-client.js +27 -11
- package/dist/gates/tool-contract.d.ts +10 -68
- package/dist/gates/tool-contract.js +1 -85
- package/dist/gates/tool-gate.d.ts +1 -1
- package/dist/harness/calls.d.ts +12 -5
- package/dist/harness/calls.js +21 -12
- package/dist/harness/executors.js +12 -9
- package/dist/harness/main.js +18 -5
- package/dist/harness/pod.d.ts +34 -0
- package/dist/harness/pod.js +41 -0
- package/dist/harness/service.d.ts +0 -1
- package/dist/harness/service.js +13 -5
- package/dist/harness/setup.d.ts +27 -0
- package/dist/harness/setup.js +150 -0
- package/dist/harness/ws-client.js +3 -2
- package/dist/harness/ws-port.d.ts +1 -5
- package/dist/harness/ws-port.js +1 -5
- package/dist/harness-api/in-process.js +3 -3
- package/dist/harness-api/record.d.ts +15 -1
- package/dist/harness-api/record.js +174 -44
- package/dist/harness-api/redact.d.ts +3 -0
- package/dist/harness-api/redact.js +45 -0
- package/dist/harness-api/server.d.ts +8 -0
- package/dist/harness-api/server.js +93 -13
- package/dist/harness-api/start.d.ts +10 -3
- package/dist/harness-api/start.js +40 -10
- package/dist/harness-api/tool-journal.d.ts +96 -0
- package/dist/harness-api/tool-journal.js +102 -0
- package/dist/harness-api/tool-status.d.ts +13 -0
- package/dist/harness-api/tool-status.js +26 -0
- package/dist/harness-api/workspace.d.ts +6 -3
- package/dist/harness-api/workspace.js +27 -11
- package/dist/harness-api/ws-server.d.ts +11 -3
- package/dist/harness-api/ws-server.js +94 -15
- package/dist/host/gates.d.ts +2 -1
- package/dist/host/gates.js +10 -2
- package/dist/host/main.js +54 -5
- package/dist/host/operate.js +67 -5
- package/dist/host/stack-config.d.ts +64 -0
- package/dist/host/stack-config.js +61 -1
- package/dist/keys/client.js +4 -1
- package/dist/keys/keys.d.ts +5 -5
- package/dist/keys/keys.js +5 -7
- package/dist/management-openapi.json +999 -2211
- package/dist/mcp/connect.d.ts +25 -20
- package/dist/mcp/connect.js +29 -30
- package/dist/mcp/pool.d.ts +2 -2
- package/dist/mcp/pool.js +1 -1
- package/dist/mcp/preview.d.ts +3 -3
- package/dist/mcp/preview.js +10 -20
- package/dist/mcp/snapshot.d.ts +5 -11
- package/dist/mcp/snapshot.js +6 -7
- package/dist/model/pi-model.js +8 -0
- package/dist/openapi.json +6955 -2526
- package/dist/reads/types.d.ts +16 -3
- package/dist/record/append.d.ts +3 -1
- package/dist/record/append.js +1 -0
- package/dist/record/envelope.d.ts +5 -1
- package/dist/record/envelope.js +7 -3
- package/dist/record/environment.d.ts +25 -0
- package/dist/record/environment.js +44 -0
- package/dist/record/index.d.ts +1 -1
- package/dist/record/index.js +1 -1
- package/dist/sandbox/disk-fs.d.ts +95 -0
- package/dist/sandbox/disk-fs.js +206 -0
- package/dist/sandbox/join.d.ts +17 -18
- package/dist/sandbox/join.js +42 -15
- package/dist/sandbox/manager.d.ts +16 -8
- package/dist/sandbox/manager.js +33 -17
- package/dist/sandbox/placement.d.ts +13 -12
- package/dist/sandbox/placement.js +29 -12
- package/dist/sandbox/pods/client.d.ts +6 -1
- package/dist/sandbox/pods/lifecycle.d.ts +28 -27
- package/dist/sandbox/pods/lifecycle.js +14 -26
- package/dist/sandbox/pods/reconcile.js +18 -12
- package/dist/sandbox/pods/spec.d.ts +15 -13
- package/dist/sandbox/pods/spec.js +16 -20
- package/dist/sandbox/records.d.ts +2 -2
- package/dist/sandbox/records.js +3 -3
- package/dist/sandbox/resolve.d.ts +35 -27
- package/dist/sandbox/resolve.js +66 -41
- package/dist/sandbox/session-sandbox.js +1 -1
- package/dist/sandbox/setup.d.ts +61 -0
- package/dist/sandbox/setup.js +123 -0
- package/dist/sandbox/share.d.ts +11 -21
- package/dist/sandbox/share.js +12 -41
- package/dist/sandbox/tenant-config.d.ts +12 -14
- package/dist/sandbox/tenant-config.js +12 -17
- package/dist/sandbox/types.d.ts +6 -0
- package/dist/store/postgres/drizzle/0020_environments.sql +63 -0
- package/dist/store/postgres/drizzle/0021_disk_versions.sql +7 -0
- package/dist/store/postgres/drizzle/0022_model_usage_timing.sql +5 -0
- package/dist/store/postgres/drizzle/0023_artifact_pages.sql +1 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/reads.js +117 -17
- package/dist/store/postgres/record-writer.d.ts +4 -4
- package/dist/store/postgres/record-writer.js +9 -9
- package/dist/store/postgres/record.d.ts +7 -0
- package/dist/store/postgres/record.js +23 -2
- package/dist/store/postgres/schema.d.ts +934 -761
- package/dist/store/postgres/schema.js +102 -73
- package/dist/store/postgres/store.js +119 -66
- package/dist/store/types.d.ts +109 -48
- package/dist/tenant/advance.d.ts +7 -6
- package/dist/tenant/advance.js +115 -42
- package/dist/tenant/artifact-tool.js +3 -4
- package/dist/tenant/commands.d.ts +15 -2
- package/dist/tenant/commands.js +93 -12
- package/dist/tenant/context.d.ts +48 -22
- package/dist/tenant/context.js +4 -15
- package/dist/tenant/effects.d.ts +1 -1
- package/dist/tenant/effects.js +37 -20
- package/dist/tenant/environments.d.ts +167 -0
- package/dist/tenant/environments.js +823 -0
- package/dist/tenant/harness-tokens.d.ts +21 -0
- package/dist/tenant/harness-tokens.js +61 -0
- package/dist/tenant/host-token.d.ts +1 -1
- package/dist/tenant/host-token.js +2 -4
- package/dist/tenant/identity-file.d.ts +4 -4
- package/dist/tenant/identity-file.js +17 -8
- package/dist/tenant/issuers.js +3 -3
- package/dist/tenant/principals.js +1 -1
- package/dist/tenant/reset.js +3 -3
- package/dist/tenant/runtime.d.ts +6 -1
- package/dist/tenant/runtime.js +7 -1
- package/dist/tenant/session.d.ts +3 -3
- package/dist/tenant/session.js +0 -14
- package/dist/tenant/sessions.d.ts +13 -13
- package/dist/tenant/sessions.js +61 -138
- package/dist/tenant/signing-keys.d.ts +5 -1
- package/dist/tenant/status.js +3 -3
- package/dist/tenant/sweep.js +12 -6
- package/dist/tenant/transcript.d.ts +210 -20
- package/dist/tenant/transcript.js +62 -11
- package/dist/tenant/turn-timing.d.ts +43 -0
- package/dist/tenant/turn-timing.js +39 -0
- package/dist/tenant/types.d.ts +2 -0
- package/dist/traces/ids.d.ts +42 -0
- package/dist/traces/ids.js +85 -0
- package/dist/traces/key.d.ts +6 -0
- package/dist/traces/key.js +37 -0
- package/dist/traces/map.d.ts +113 -0
- package/dist/traces/map.js +317 -0
- package/dist/traces/options.d.ts +7 -0
- package/dist/traces/options.js +1 -0
- package/dist/traces/otlp.d.ts +42 -0
- package/dist/traces/otlp.js +84 -0
- package/dist/traces/projector.d.ts +58 -0
- package/dist/traces/projector.js +200 -0
- package/dist/traces/read.d.ts +23 -0
- package/dist/traces/read.js +16 -0
- package/dist/vault/coverage.d.ts +26 -0
- package/dist/vault/coverage.js +64 -0
- package/dist/vault/error.d.ts +11 -1
- package/dist/vault/error.js +5 -1
- package/dist/vault/service.d.ts +47 -48
- package/dist/vault/service.js +321 -382
- package/dist/vault/sources.d.ts +5 -16
- package/dist/vault/sources.js +6 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/package.json +13 -13
- package/dist/api/http/routes/sandboxes.d.ts +0 -9
- package/dist/api/http/routes/sandboxes.js +0 -153
- package/dist/api/http/routes/vaults.d.ts +0 -10
- package/dist/api/http/routes/vaults.js +0 -139
- package/dist/record/sandbox.d.ts +0 -25
- package/dist/record/sandbox.js +0 -43
- package/dist/tenant/sandboxes.d.ts +0 -123
- package/dist/tenant/sandboxes.js +0 -566
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { parseSandboxDuration } from "@nylorun/core/define";
|
|
2
|
+
import { contentKey, readManifest } from "../artifacts/folders.js";
|
|
3
|
+
import { SETUP_FAILED } from "./pods/lifecycle.js";
|
|
4
|
+
export { SETUP_FAILED };
|
|
5
|
+
/** The most of a failed command's output kept in its event and reason. */
|
|
6
|
+
const OUTPUT_TAIL = 4 * 1024;
|
|
7
|
+
/** A command's timeout when the recipe gives none. */
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 10 * 60_000;
|
|
9
|
+
/** The setup of `recipe`, or undefined when it has neither commands nor files. */
|
|
10
|
+
export async function setupPlanOf(ctx, t, environment) {
|
|
11
|
+
const recipe = environment.applied;
|
|
12
|
+
if (!recipe.setup?.length && !recipe.files?.length)
|
|
13
|
+
return undefined;
|
|
14
|
+
return {
|
|
15
|
+
recipeVersion: environment.appliedVersion,
|
|
16
|
+
commands: (recipe.setup ?? []).map((command) => ({
|
|
17
|
+
command: command.command,
|
|
18
|
+
cwd: command.cwd ?? "/workspace",
|
|
19
|
+
timeoutMs: (command.timeout && parseSandboxDuration(command.timeout)) || DEFAULT_TIMEOUT_MS,
|
|
20
|
+
})),
|
|
21
|
+
files: (recipe.files ?? []).map((file, index) => ({ index, path: file.path })),
|
|
22
|
+
environment: await ctx.vault.environmentVariables(t, environment.id),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function parseSetupReport(value) {
|
|
26
|
+
if (!value || typeof value !== "object")
|
|
27
|
+
return undefined;
|
|
28
|
+
const report = value;
|
|
29
|
+
if (report.status !== "ok" && report.status !== "failed")
|
|
30
|
+
return undefined;
|
|
31
|
+
const index = typeof report.index === "number" && Number.isInteger(report.index) ? report.index : undefined;
|
|
32
|
+
const exitCode = typeof report.exitCode === "number" && Number.isInteger(report.exitCode) ? report.exitCode : undefined;
|
|
33
|
+
const output = typeof report.output === "string" ? report.output.slice(-OUTPUT_TAIL) : undefined;
|
|
34
|
+
return {
|
|
35
|
+
status: report.status,
|
|
36
|
+
...(index === undefined ? {} : { index }),
|
|
37
|
+
...(exitCode === undefined ? {} : { exitCode }),
|
|
38
|
+
...(output === undefined ? {} : { output }),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Records a failed setup on Environment `id` held at host epoch `epoch` (the reporting engine's):
|
|
43
|
+
* the pod is `failed` with a reason that starts `setup:`, and `environment.failed` says which
|
|
44
|
+
* command failed and how. A report from an older host, or a success, changes nothing.
|
|
45
|
+
*/
|
|
46
|
+
export async function recordSetup(ctx, id, epoch, report) {
|
|
47
|
+
await ctx.store.tx(async (t) => {
|
|
48
|
+
const environment = await t.environment(id, { lock: true });
|
|
49
|
+
const pod = environment?.pod;
|
|
50
|
+
if (!environment || !pod || pod.hostEpoch !== epoch || pod.desired !== "running")
|
|
51
|
+
return;
|
|
52
|
+
if (report.status === "ok")
|
|
53
|
+
return;
|
|
54
|
+
const command = report.index === undefined ? undefined : environment.applied.setup?.[report.index];
|
|
55
|
+
const what = command === undefined ? "copying the input files failed" : `command ${report.index + 1} (${command.command.slice(0, 80)}) exited ${report.exitCode ?? "abnormally"}`;
|
|
56
|
+
const tail = (report.output ?? "").trim().slice(-500);
|
|
57
|
+
const reason = `${SETUP_FAILED} ${what}${tail ? `: ${tail}` : ""}`;
|
|
58
|
+
await t.updateEnvironmentPod(id, { observed: "failed", reason }, new Date().toISOString());
|
|
59
|
+
await t.environmentEvent(id, "environment.failed", {
|
|
60
|
+
reason,
|
|
61
|
+
setup: {
|
|
62
|
+
...(report.index === undefined ? {} : { index: report.index }),
|
|
63
|
+
...(report.exitCode === undefined ? {} : { exitCode: report.exitCode }),
|
|
64
|
+
output: report.output ?? "",
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
if (report.status === "failed")
|
|
69
|
+
ctx.config.logger.warn("environment setup failed", { environmentId: id, index: report.index, exitCode: report.exitCode });
|
|
70
|
+
else
|
|
71
|
+
ctx.config.logger.info("environment setup done", { environmentId: id });
|
|
72
|
+
}
|
|
73
|
+
/** Whether the engine of `id` should run its setup again: the pod is no longer `failed`. */
|
|
74
|
+
export async function setupState(ctx, id) {
|
|
75
|
+
return ctx.store.tx(async (t) => {
|
|
76
|
+
const environment = await t.environment(id);
|
|
77
|
+
const pod = environment?.pod;
|
|
78
|
+
if (!environment || !pod)
|
|
79
|
+
return { retry: false };
|
|
80
|
+
if (pod.observed === "failed")
|
|
81
|
+
return { retry: false };
|
|
82
|
+
const setup = await setupPlanOf(ctx, t, environment);
|
|
83
|
+
return { retry: true, ...(setup ? { setup } : {}) };
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Input file `index` of Environment `id`'s applied recipe: a file artifact's bytes, a folder's
|
|
88
|
+
* listing, or (with `path`) one of the folder's files. Undefined when there is no such file.
|
|
89
|
+
*/
|
|
90
|
+
export async function setupFile(ctx, id, index, path) {
|
|
91
|
+
const found = await ctx.store.tx(async (t) => {
|
|
92
|
+
const environment = await t.environment(id);
|
|
93
|
+
const file = environment?.applied.files?.[index];
|
|
94
|
+
if (!file)
|
|
95
|
+
return undefined;
|
|
96
|
+
const artifact = await t.artifact(file.artifactId);
|
|
97
|
+
if (!artifact || artifact.sessionId !== null)
|
|
98
|
+
return undefined;
|
|
99
|
+
const version = await t.artifactVersion(file.artifactId, file.version);
|
|
100
|
+
return version ? { artifact, version } : undefined;
|
|
101
|
+
});
|
|
102
|
+
if (!found)
|
|
103
|
+
return undefined;
|
|
104
|
+
if (found.artifact.kind === "file") {
|
|
105
|
+
if (path !== undefined)
|
|
106
|
+
return undefined;
|
|
107
|
+
const got = await ctx.blobs.get(found.version.blobKey);
|
|
108
|
+
return got ? { kind: "file", contentType: found.version.contentType ?? found.artifact.contentType, body: got.body } : undefined;
|
|
109
|
+
}
|
|
110
|
+
const manifest = await readManifest(ctx.blobs, found.version);
|
|
111
|
+
if (path === undefined)
|
|
112
|
+
return {
|
|
113
|
+
kind: "folder",
|
|
114
|
+
entries: manifest.entries
|
|
115
|
+
.filter((entry) => entry.type === undefined)
|
|
116
|
+
.map((entry) => ({ path: entry.path, size: entry.size })),
|
|
117
|
+
};
|
|
118
|
+
const entry = manifest.entries.find((item) => item.path === path && item.type === undefined);
|
|
119
|
+
if (!entry)
|
|
120
|
+
return undefined;
|
|
121
|
+
const got = await ctx.blobs.get(contentKey(entry.sha256));
|
|
122
|
+
return got ? { kind: "file", contentType: entry.contentType, body: got.body } : undefined;
|
|
123
|
+
}
|
package/dist/sandbox/share.d.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* session record (`sandbox`).
|
|
2
|
+
* A session's sandbox: the one of the Environment it names (protocol 11), whose id keys the
|
|
3
|
+
* workspace, with the spec pinned when the session was opened (`Session.sandbox`). Definitions
|
|
4
|
+
* no longer declare one (Sandboxes v3); `sandboxSpecOf` still reads a pinned manifest's.
|
|
6
5
|
*/
|
|
7
6
|
import { type AgentManifest, type CapabilityManifest, type SandboxManifest, type WorkflowManifest } from "@nylorun/core/define";
|
|
8
7
|
export type SessionSandboxRef = {
|
|
9
8
|
readonly id: string;
|
|
10
9
|
readonly ownerUserId: string;
|
|
11
10
|
readonly manifest: AgentManifest | WorkflowManifest | Record<string, unknown>;
|
|
12
|
-
/**
|
|
13
|
-
readonly
|
|
14
|
-
/** The sandbox
|
|
15
|
-
readonly sandboxId?: string;
|
|
16
|
-
/** The sandbox chosen when the session was opened (or inherited from its owner), resolved. */
|
|
11
|
+
/** The Environment the session names; its id keys the workspace. */
|
|
12
|
+
readonly environmentId?: string;
|
|
13
|
+
/** The Environment's sandbox spec, pinned when the session was opened. */
|
|
17
14
|
readonly sandbox?: SandboxManifest;
|
|
18
15
|
};
|
|
19
16
|
/** The session's sandbox spec: the one pinned at open, else the one its definition declares. */
|
|
@@ -26,21 +23,14 @@ export declare function sandboxSpecOf(manifest: AgentManifest | WorkflowManifest
|
|
|
26
23
|
* one (Sandboxes v3), so registration refuses any of these.
|
|
27
24
|
*/
|
|
28
25
|
export declare function declaredSandboxes(manifest: unknown, into?: string[]): string[];
|
|
29
|
-
export declare function sandboxSpecsEqual(a: SandboxManifest | undefined, b: SandboxManifest | undefined): boolean;
|
|
30
26
|
/** Synthetic capability so SandboxManager.run can use a workflow (or shared) spec. */
|
|
31
27
|
export declare function capabilityForSandbox(sandbox: SandboxManifest): CapabilityManifest;
|
|
32
28
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
29
|
+
* The workspace a session's sandbox tools run in: the session, whose log records the
|
|
30
|
+
* workspace's events, and its Environment, whose id keys the workspace.
|
|
35
31
|
*/
|
|
36
|
-
export declare function
|
|
37
|
-
/**
|
|
38
|
-
* The workspace a session's sandbox tools run in: the owning session (one hop through
|
|
39
|
-
* `sandboxOwnerId`, whose log records the workspace's events) and, when that session is
|
|
40
|
-
* attached to a sandbox resource, the resource's id, which keys the workspace.
|
|
41
|
-
*/
|
|
42
|
-
export declare function sandboxWorkspaceOf(session: SessionSandboxRef, lookup: (id: string) => SessionSandboxRef | undefined): {
|
|
32
|
+
export declare function sandboxWorkspaceOf(session: SessionSandboxRef): {
|
|
43
33
|
readonly ownerId: string;
|
|
44
|
-
readonly
|
|
34
|
+
readonly environmentId?: string;
|
|
45
35
|
};
|
|
46
|
-
export declare function sessionHasSandbox(session: SessionSandboxRef
|
|
36
|
+
export declare function sessionHasSandbox(session: SessionSandboxRef): boolean;
|
package/dist/sandbox/share.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* session record (`sandbox`).
|
|
2
|
+
* A session's sandbox: the one of the Environment it names (protocol 11), whose id keys the
|
|
3
|
+
* workspace, with the spec pinned when the session was opened (`Session.sandbox`). Definitions
|
|
4
|
+
* no longer declare one (Sandboxes v3); `sandboxSpecOf` still reads a pinned manifest's.
|
|
6
5
|
*/
|
|
7
|
-
import {
|
|
6
|
+
import {} from "@nylorun/core/define";
|
|
8
7
|
/** The session's sandbox spec: the one pinned at open, else the one its definition declares. */
|
|
9
8
|
export function sessionSandboxSpec(session) {
|
|
10
9
|
return session.sandbox ?? sandboxSpecOf(session.manifest);
|
|
@@ -47,13 +46,6 @@ export function declaredSandboxes(manifest, into = []) {
|
|
|
47
46
|
}
|
|
48
47
|
return into;
|
|
49
48
|
}
|
|
50
|
-
export function sandboxSpecsEqual(a, b) {
|
|
51
|
-
if (a === undefined && b === undefined)
|
|
52
|
-
return true;
|
|
53
|
-
if (a === undefined || b === undefined)
|
|
54
|
-
return false;
|
|
55
|
-
return canonical(a) === canonical(b);
|
|
56
|
-
}
|
|
57
49
|
/** Synthetic capability so SandboxManager.run can use a workflow (or shared) spec. */
|
|
58
50
|
export function capabilityForSandbox(sandbox) {
|
|
59
51
|
return {
|
|
@@ -64,35 +56,14 @@ export function capabilityForSandbox(sandbox) {
|
|
|
64
56
|
};
|
|
65
57
|
}
|
|
66
58
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*/
|
|
70
|
-
export function owningSandboxSessionId(session, lookup) {
|
|
71
|
-
const seen = new Set();
|
|
72
|
-
let current = session;
|
|
73
|
-
while (current) {
|
|
74
|
-
if (seen.has(current.id))
|
|
75
|
-
return session.id;
|
|
76
|
-
seen.add(current.id);
|
|
77
|
-
const ownerId = current.sandboxOwnerId;
|
|
78
|
-
if (!ownerId || ownerId === current.id)
|
|
79
|
-
return current.id;
|
|
80
|
-
current = lookup(ownerId);
|
|
81
|
-
}
|
|
82
|
-
return session.id;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* The workspace a session's sandbox tools run in: the owning session (one hop through
|
|
86
|
-
* `sandboxOwnerId`, whose log records the workspace's events) and, when that session is
|
|
87
|
-
* attached to a sandbox resource, the resource's id, which keys the workspace.
|
|
59
|
+
* The workspace a session's sandbox tools run in: the session, whose log records the
|
|
60
|
+
* workspace's events, and its Environment, whose id keys the workspace.
|
|
88
61
|
*/
|
|
89
|
-
export function sandboxWorkspaceOf(session
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
62
|
+
export function sandboxWorkspaceOf(session) {
|
|
63
|
+
return session.environmentId === undefined
|
|
64
|
+
? { ownerId: session.id }
|
|
65
|
+
: { ownerId: session.id, environmentId: session.environmentId };
|
|
93
66
|
}
|
|
94
|
-
export function sessionHasSandbox(session
|
|
95
|
-
|
|
96
|
-
const owner = ownerId === session.id ? session : lookup(ownerId) ?? session;
|
|
97
|
-
return sessionSandboxSpec(owner) !== undefined || sessionSandboxSpec(session) !== undefined;
|
|
67
|
+
export function sessionHasSandbox(session) {
|
|
68
|
+
return sessionSandboxSpec(session) !== undefined;
|
|
98
69
|
}
|
|
@@ -1,41 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A Tenant's
|
|
3
|
-
*
|
|
2
|
+
* A Tenant's Environment settings, stored as Tenant setting `environments.config`: the limits
|
|
3
|
+
* every Environment's recipe must fit, the pods' stop grace and the harness placement. Unset
|
|
4
4
|
* fields take the defaults below.
|
|
5
5
|
*/
|
|
6
|
-
import { type
|
|
7
|
-
export declare const
|
|
8
|
-
/** The
|
|
6
|
+
import { type PlacementHost, type TenantEnvironmentsConfig } from "@nylorun/core/contracts";
|
|
7
|
+
export declare const ENVIRONMENTS_CONFIG_SETTING = "environments.config";
|
|
8
|
+
/** The Tenant's settings, as stored (`environments.config`). */
|
|
9
|
+
export type TenantSandboxConfig = TenantEnvironmentsConfig;
|
|
10
|
+
/** The most an Environment may ask for when the Tenant sets no maximum. */
|
|
9
11
|
export declare const DEFAULT_MAX_CPUS = 4;
|
|
10
12
|
export declare const DEFAULT_MAX_MEMORY_MIB = 8192;
|
|
11
13
|
export declare const DEFAULT_SANDBOX_IDLE = "15m";
|
|
12
|
-
/** The most
|
|
13
|
-
export declare const
|
|
14
|
+
/** The most Environments a Tenant holds when it sets no limit. */
|
|
15
|
+
export declare const DEFAULT_MAX_ENVIRONMENTS = 100;
|
|
14
16
|
export interface SandboxResourcesLimit {
|
|
15
17
|
readonly cpus: number;
|
|
16
18
|
readonly memoryMiB: number;
|
|
17
19
|
}
|
|
18
20
|
/** A configuration with every default applied. */
|
|
19
21
|
export interface EffectiveSandboxConfig {
|
|
20
|
-
readonly default: "none" | "virtual" | SandboxInlineRequest;
|
|
21
22
|
readonly limits: {
|
|
22
23
|
readonly network: readonly string[];
|
|
23
24
|
readonly resources: SandboxResourcesLimit;
|
|
24
25
|
readonly defaultResources: SandboxResourcesLimit;
|
|
25
26
|
readonly idle: string;
|
|
26
|
-
/** The most
|
|
27
|
-
readonly
|
|
28
|
-
/** Pods: the longest `lifecycle.ttl`. */
|
|
29
|
-
readonly ttl?: string;
|
|
27
|
+
/** The most Environments the Tenant may hold. */
|
|
28
|
+
readonly environments: number;
|
|
30
29
|
};
|
|
31
30
|
/** Pods (F7.2, D36). */
|
|
32
31
|
readonly lifecycle: {
|
|
33
|
-
readonly onExpiry: "retain" | "delete";
|
|
34
32
|
readonly stopGrace: string;
|
|
35
33
|
};
|
|
36
34
|
/** Where each harness may run (D38). */
|
|
37
35
|
readonly placement: Readonly<Record<string, {
|
|
38
|
-
readonly hosts: readonly
|
|
36
|
+
readonly hosts: readonly PlacementHost[];
|
|
39
37
|
}>>;
|
|
40
38
|
}
|
|
41
39
|
interface SettingsReader {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A Tenant's
|
|
3
|
-
*
|
|
2
|
+
* A Tenant's Environment settings, stored as Tenant setting `environments.config`: the limits
|
|
3
|
+
* every Environment's recipe must fit, the pods' stop grace and the harness placement. Unset
|
|
4
4
|
* fields take the defaults below.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { TenantEnvironmentsConfigSchema, } from "@nylorun/core/contracts";
|
|
7
7
|
import { parseSandboxSize } from "@nylorun/core/define";
|
|
8
8
|
import { DEFAULT_SANDBOX_CPUS, DEFAULT_SANDBOX_MEMORY_MIB, DEV_PRESET_HOSTS, } from "./policy.js";
|
|
9
|
-
export const
|
|
10
|
-
/** The most
|
|
9
|
+
export const ENVIRONMENTS_CONFIG_SETTING = "environments.config";
|
|
10
|
+
/** The most an Environment may ask for when the Tenant sets no maximum. */
|
|
11
11
|
export const DEFAULT_MAX_CPUS = 4;
|
|
12
12
|
export const DEFAULT_MAX_MEMORY_MIB = 8192;
|
|
13
13
|
export const DEFAULT_SANDBOX_IDLE = "15m";
|
|
14
|
-
/** The most
|
|
15
|
-
export const
|
|
14
|
+
/** The most Environments a Tenant holds when it sets no limit. */
|
|
15
|
+
export const DEFAULT_MAX_ENVIRONMENTS = 100;
|
|
16
16
|
export function memoryMiB(value) {
|
|
17
17
|
const bytes = parseSandboxSize(value);
|
|
18
18
|
return bytes === undefined ? 0 : Math.max(128, Math.ceil(bytes / 1024 ** 2));
|
|
@@ -26,7 +26,6 @@ function resources(value, fallback) {
|
|
|
26
26
|
export function effectiveSandboxConfig(config) {
|
|
27
27
|
const limits = config.limits ?? {};
|
|
28
28
|
return {
|
|
29
|
-
default: config.default ?? "none",
|
|
30
29
|
limits: {
|
|
31
30
|
network: limits.network ?? DEV_PRESET_HOSTS,
|
|
32
31
|
resources: resources(limits.resources, {
|
|
@@ -38,23 +37,19 @@ export function effectiveSandboxConfig(config) {
|
|
|
38
37
|
memoryMiB: DEFAULT_SANDBOX_MEMORY_MIB,
|
|
39
38
|
}),
|
|
40
39
|
idle: limits.idle ?? DEFAULT_SANDBOX_IDLE,
|
|
41
|
-
|
|
42
|
-
...(limits.ttl === undefined ? {} : { ttl: limits.ttl }),
|
|
43
|
-
},
|
|
44
|
-
lifecycle: {
|
|
45
|
-
onExpiry: config.lifecycle?.onExpiry ?? "retain",
|
|
46
|
-
stopGrace: config.lifecycle?.stopGrace ?? "10s",
|
|
40
|
+
environments: limits.environments ?? DEFAULT_MAX_ENVIRONMENTS,
|
|
47
41
|
},
|
|
42
|
+
lifecycle: { stopGrace: config.lifecycle?.stopGrace ?? "10s" },
|
|
48
43
|
placement: config.placement ?? { "*": { hosts: ["harness-container", "sandbox"] } },
|
|
49
44
|
};
|
|
50
45
|
}
|
|
51
46
|
/** The stored configuration, or `{}` when the Tenant has none. */
|
|
52
47
|
export async function readSandboxConfig(t) {
|
|
53
|
-
const raw = await t.getSetting(
|
|
48
|
+
const raw = await t.getSetting(ENVIRONMENTS_CONFIG_SETTING);
|
|
54
49
|
if (raw === undefined)
|
|
55
50
|
return {};
|
|
56
|
-
return
|
|
51
|
+
return TenantEnvironmentsConfigSchema.parse(JSON.parse(raw));
|
|
57
52
|
}
|
|
58
53
|
export async function writeSandboxConfig(t, config) {
|
|
59
|
-
await t.putSetting(
|
|
54
|
+
await t.putSetting(ENVIRONMENTS_CONFIG_SETTING, JSON.stringify(config));
|
|
60
55
|
}
|
package/dist/sandbox/types.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export interface SandboxSpec {
|
|
|
32
32
|
readonly memoryMiB: number;
|
|
33
33
|
readonly network: ResolvedNetwork;
|
|
34
34
|
}
|
|
35
|
+
import type { DiskRoots } from "./disk-fs.js";
|
|
35
36
|
export interface ExecRequest {
|
|
36
37
|
readonly command: string;
|
|
37
38
|
readonly cwd: string;
|
|
@@ -73,6 +74,11 @@ export interface SandboxHandle {
|
|
|
73
74
|
writeFile(path: string, content: string | Uint8Array): Promise<void>;
|
|
74
75
|
/** Release compute; files persist. */
|
|
75
76
|
stop(): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Where the disk's roots are, for disk versions (R2d step 3, `sandbox/disk-fs.ts`): the
|
|
79
|
+
* workspace, and in a pod the engine's `/harness`. Absent for a backend without a disk.
|
|
80
|
+
*/
|
|
81
|
+
readonly diskRoots?: DiskRoots;
|
|
76
82
|
}
|
|
77
83
|
/** The files `listFiles` found: paths relative to the directory listed. */
|
|
78
84
|
export interface SandboxListing {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
-- Protocol 11: Environments (R2d), a fresh start (Q2). Sandbox resources and every vault but
|
|
2
|
+
-- the host's are dropped, not mapped: which Environment a person's key belongs in is the app's
|
|
3
|
+
-- mapping, and each seal binds its vault id. Sessions opened before protocol 11 are closed
|
|
4
|
+
-- (Q12): their history stays readable and a new turn is refused (`session_closed`).
|
|
5
|
+
CREATE TABLE "nylorun_streams"."environment_events" (
|
|
6
|
+
"environment_id" text COLLATE "C" NOT NULL,
|
|
7
|
+
"seq" bigint NOT NULL,
|
|
8
|
+
"type" text NOT NULL,
|
|
9
|
+
"body" json NOT NULL,
|
|
10
|
+
"committed_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
11
|
+
CONSTRAINT "environment_events_pkey" PRIMARY KEY("environment_id","seq")
|
|
12
|
+
);
|
|
13
|
+
--> statement-breakpoint
|
|
14
|
+
CREATE TABLE "nylorun"."environments" (
|
|
15
|
+
"id" text COLLATE "C" PRIMARY KEY NOT NULL,
|
|
16
|
+
"kind" text NOT NULL,
|
|
17
|
+
"labels" json NOT NULL,
|
|
18
|
+
"recipe" json NOT NULL,
|
|
19
|
+
"applied" json NOT NULL,
|
|
20
|
+
"version" integer DEFAULT 1 NOT NULL,
|
|
21
|
+
"applied_version" integer DEFAULT 1 NOT NULL,
|
|
22
|
+
"owner_user_id" text,
|
|
23
|
+
"last_used_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
24
|
+
"created_at" text COLLATE "C" NOT NULL,
|
|
25
|
+
"updated_at" text COLLATE "C" NOT NULL,
|
|
26
|
+
"k8s_name" text COLLATE "C",
|
|
27
|
+
"volume_gen" integer DEFAULT 0 NOT NULL,
|
|
28
|
+
"desired" text,
|
|
29
|
+
"observed" text,
|
|
30
|
+
"pod_uid" text,
|
|
31
|
+
"host_epoch" integer DEFAULT 0 NOT NULL,
|
|
32
|
+
"join_token_hash" text,
|
|
33
|
+
"rev" integer DEFAULT 0 NOT NULL,
|
|
34
|
+
"last_active_at" timestamp with time zone,
|
|
35
|
+
"started_at" timestamp with time zone,
|
|
36
|
+
"reason" text,
|
|
37
|
+
"retiring" text COLLATE "C",
|
|
38
|
+
"volume_id" text,
|
|
39
|
+
CONSTRAINT "environments_kind_check" CHECK ("nylorun"."environments"."kind" IN ('virtual', 'pod', 'none'))
|
|
40
|
+
);
|
|
41
|
+
--> statement-breakpoint
|
|
42
|
+
DROP TABLE "nylorun_streams"."sandbox_events" CASCADE;--> statement-breakpoint
|
|
43
|
+
DROP TABLE "nylorun"."sandbox_resources" CASCADE;--> statement-breakpoint
|
|
44
|
+
DELETE FROM "nylorun"."vaults" WHERE "id" <> 'host';--> statement-breakpoint
|
|
45
|
+
DELETE FROM "nylorun"."vault_idempotency" WHERE "id" NOT LIKE 'host-model%';--> statement-breakpoint
|
|
46
|
+
DELETE FROM "nylorun"."sandboxes";--> statement-breakpoint
|
|
47
|
+
DELETE FROM "nylorun"."sandbox_signals";--> statement-breakpoint
|
|
48
|
+
UPDATE "nylorun"."sessions" SET "body" = (("body"::jsonb - 'sandboxId' - 'sandboxSource' - 'sandboxOwnerId' - 'sandbox' - 'vaultIds' - 'credentialSelections') || '{"closedReason":"protocol_11"}'::jsonb)::json;--> statement-breakpoint
|
|
49
|
+
UPDATE "nylorun"."tenant_settings" SET "key" = 'environments.config', "value" = ((("value"::jsonb - 'default') #- '{limits,ttl}' #- '{lifecycle,onExpiry}' #- '{limits,sandboxes}') || CASE WHEN ("value"::jsonb #> '{limits,sandboxes}') IS NULL THEN '{}'::jsonb ELSE jsonb_build_object('limits', (("value"::jsonb -> 'limits') - 'sandboxes' - 'ttl') || jsonb_build_object('environments', "value"::jsonb #> '{limits,sandboxes}')) END)::text WHERE "key" = 'sandbox.config';--> statement-breakpoint
|
|
50
|
+
ALTER TABLE "nylorun"."vaults" DROP CONSTRAINT "vaults_scope_check";--> statement-breakpoint
|
|
51
|
+
DROP INDEX "nylorun"."sessions_sandbox";--> statement-breakpoint
|
|
52
|
+
DROP INDEX "nylorun"."vaults_owner";--> statement-breakpoint
|
|
53
|
+
DROP INDEX "nylorun"."vaults_one_host";--> statement-breakpoint
|
|
54
|
+
ALTER TABLE "nylorun"."sessions" ADD COLUMN "environment_id" text GENERATED ALWAYS AS (nylorun.doc(body)->>'environmentId') STORED;--> statement-breakpoint
|
|
55
|
+
ALTER TABLE "nylorun"."vaults" ADD COLUMN "environment_id" text COLLATE "C";--> statement-breakpoint
|
|
56
|
+
ALTER TABLE "nylorun"."vaults" ADD CONSTRAINT "vaults_environment_id_fkey" FOREIGN KEY ("environment_id") REFERENCES "nylorun"."environments"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
57
|
+
CREATE INDEX "sessions_environment" ON "nylorun"."sessions" USING btree ("environment_id");--> statement-breakpoint
|
|
58
|
+
CREATE UNIQUE INDEX "vault_credentials_name" ON "nylorun"."vault_credentials" USING btree ("vault_id","name");--> statement-breakpoint
|
|
59
|
+
CREATE UNIQUE INDEX "vaults_environment" ON "nylorun"."vaults" USING btree ("environment_id");--> statement-breakpoint
|
|
60
|
+
ALTER TABLE "nylorun"."sessions" DROP COLUMN "sandbox_id";--> statement-breakpoint
|
|
61
|
+
ALTER TABLE "nylorun"."vaults" DROP COLUMN "owner_user_id";--> statement-breakpoint
|
|
62
|
+
ALTER TABLE "nylorun"."vaults" DROP COLUMN "scope";--> statement-breakpoint
|
|
63
|
+
ALTER TABLE "nylorun"."vaults" ADD CONSTRAINT "vaults_owner_check" CHECK (("nylorun"."vaults"."id" = 'host') = ("nylorun"."vaults"."environment_id" IS NULL));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- R2d step 3: an Environment's disk versions are one folder artifact it owns (environment_id),
|
|
2
|
+
-- and its row holds the disk lease (disk_op) and the version its next volume starts from
|
|
3
|
+
-- (disk_seed).
|
|
4
|
+
ALTER TABLE "nylorun"."artifacts" ADD COLUMN "environment_id" text COLLATE "C";--> statement-breakpoint
|
|
5
|
+
ALTER TABLE "nylorun"."environments" ADD COLUMN "disk_op" json;--> statement-breakpoint
|
|
6
|
+
ALTER TABLE "nylorun"."environments" ADD COLUMN "disk_seed" json;--> statement-breakpoint
|
|
7
|
+
CREATE UNIQUE INDEX "artifacts_environment_disk" ON "nylorun"."artifacts" USING btree ("environment_id") WHERE environment_id IS NOT NULL;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- R7.1: the gate's own timing of a model call (its span): when it sent the call, when the answer
|
|
2
|
+
-- was complete, and how long the provider took to its first stream event. Null on older rows.
|
|
3
|
+
ALTER TABLE "nylorun"."model_usage" ADD COLUMN "started_at" text;--> statement-breakpoint
|
|
4
|
+
ALTER TABLE "nylorun"."model_usage" ADD COLUMN "ended_at" text;--> statement-breakpoint
|
|
5
|
+
ALTER TABLE "nylorun"."model_usage" ADD COLUMN "first_token_ms" integer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CREATE INDEX "artifacts_creation_order" ON "nylorun"."artifacts" USING btree ("created_at","id");
|
|
@@ -141,6 +141,34 @@
|
|
|
141
141
|
"when": 1791530515498,
|
|
142
142
|
"tag": "0019_sandbox_signal_outbox",
|
|
143
143
|
"breakpoints": true
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"idx": 20,
|
|
147
|
+
"version": "7",
|
|
148
|
+
"when": 1791702110945,
|
|
149
|
+
"tag": "0020_environments",
|
|
150
|
+
"breakpoints": true
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"idx": 21,
|
|
154
|
+
"version": "7",
|
|
155
|
+
"when": 1791709466639,
|
|
156
|
+
"tag": "0021_disk_versions",
|
|
157
|
+
"breakpoints": true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"idx": 22,
|
|
161
|
+
"version": "7",
|
|
162
|
+
"when": 1791717547905,
|
|
163
|
+
"tag": "0022_model_usage_timing",
|
|
164
|
+
"breakpoints": true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"idx": 23,
|
|
168
|
+
"version": "7",
|
|
169
|
+
"when": 1791730977999,
|
|
170
|
+
"tag": "0023_artifact_pages",
|
|
171
|
+
"breakpoints": true
|
|
144
172
|
}
|
|
145
173
|
]
|
|
146
174
|
}
|