@rivet-dev/agentos-runtime-core 0.2.20 → 0.2.21
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/commands/bash +0 -0
- package/commands/rg +0 -0
- package/commands/sh +0 -0
- package/commands/ssh +0 -0
- package/commands/unzip +0 -0
- package/commands/zip +0 -0
- package/dist/generated/HostFunctionLimitsConfig.d.ts +10 -0
- package/dist/generated/PermissionsPolicy.d.ts +1 -1
- package/dist/generated/VmLimitsConfig.d.ts +2 -2
- package/dist/generated-protocol.d.ts +2 -2
- package/dist/generated-protocol.js +4 -4
- package/dist/host-functions-zod.d.ts +9 -0
- package/dist/host-functions-zod.js +274 -0
- package/dist/host-functions.d.ts +95 -0
- package/dist/host-functions.js +54 -0
- package/dist/node-runtime-options-schema.d.ts +1 -1
- package/dist/node-runtime-options-schema.js +14 -13
- package/dist/node-runtime.d.ts +40 -39
- package/dist/node-runtime.js +34 -62
- package/dist/permissions.d.ts +1 -1
- package/dist/permissions.js +2 -2
- package/dist/request-payloads.d.ts +1 -1
- package/dist/request-payloads.js +1 -1
- package/dist/sidecar-process.d.ts +2 -2
- package/dist/sidecar-process.js +2 -2
- package/dist/test-runtime.d.ts +12 -37
- package/dist/test-runtime.js +62 -53
- package/dist/vm-config.d.ts +1 -1
- package/package.json +14 -3
- package/dist/generated/BindingLimitsConfig.d.ts +0 -10
- /package/dist/generated/{BindingLimitsConfig.js → HostFunctionLimitsConfig.js} +0 -0
package/dist/node-runtime.d.ts
CHANGED
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
* isolation boundary — no host escapes, no real Node.js builtins for guest
|
|
18
18
|
* work.
|
|
19
19
|
*/
|
|
20
|
-
import type { BindingDefinition, KernelBootTiming, Permissions, VirtualDirEntry, VirtualFileSystem } from "./test-runtime.js";
|
|
21
20
|
import type { JsRuntimeConfig } from "./generated/JsRuntimeConfig.js";
|
|
22
21
|
import type { VmUserConfig } from "./generated/VmUserConfig.js";
|
|
22
|
+
import type { HostFunctionCollections, HostFunctionSchemas } from "./host-functions.js";
|
|
23
23
|
import type { SidecarProcess } from "./sidecar-process.js";
|
|
24
|
-
|
|
24
|
+
import type { KernelBootTiming, Permissions, VirtualDirEntry, VirtualFileSystem } from "./test-runtime.js";
|
|
25
|
+
export type { HostFunctionExample, VirtualDirEntry, } from "./test-runtime.js";
|
|
25
26
|
export { resolveNodeRuntimeSidecarBinary } from "./test-runtime.js";
|
|
26
|
-
export type NodeRuntimeBootTimingPhase = KernelBootTiming["phase"] | "runtime_mount_wasm" | "runtime_mount_node" | "
|
|
27
|
+
export type NodeRuntimeBootTimingPhase = KernelBootTiming["phase"] | "runtime_mount_wasm" | "runtime_mount_node" | "hostFunctions";
|
|
27
28
|
export interface NodeRuntimeBootTiming {
|
|
28
29
|
phase: NodeRuntimeBootTimingPhase;
|
|
29
30
|
durationMs: number;
|
|
@@ -50,7 +51,7 @@ export declare function resolveNodeRuntimeCommandsDir(explicit?: string): string
|
|
|
50
51
|
* Options that translate into sidecar VM JSON must also stay aligned with
|
|
51
52
|
* `crates/vm-config/src/lib.rs::CreateVmConfig`.
|
|
52
53
|
*/
|
|
53
|
-
export interface NodeRuntimeCreateOptions {
|
|
54
|
+
export interface NodeRuntimeCreateOptions<HOST_FUNCTIONS extends HostFunctionSchemas = HostFunctionSchemas> {
|
|
54
55
|
/**
|
|
55
56
|
* Caller-owned filesystem used only by this low-level compatibility runtime.
|
|
56
57
|
* AgentOS clients do not create a TypeScript filesystem implicitly; normal
|
|
@@ -64,12 +65,11 @@ export interface NodeRuntimeCreateOptions {
|
|
|
64
65
|
/** Initial virtual Linux credentials and account record. Defaults to `1000:1000` (`agentos`). */
|
|
65
66
|
user?: VmUserConfig;
|
|
66
67
|
/**
|
|
67
|
-
* Permission policy for the VM
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* (rule sets) to further sandbox individual scopes.
|
|
68
|
+
* Permission policy for the VM, merged over the sidecar's default: the
|
|
69
|
+
* virtual filesystem, processes, environment, bindings, listeners, and
|
|
70
|
+
* loopback networking work, while external network access is denied. A partial
|
|
71
|
+
* policy works: `{ network: "allow" }` grants external access and keeps every
|
|
72
|
+
* other scope at its default.
|
|
73
73
|
*/
|
|
74
74
|
permissions?: Permissions;
|
|
75
75
|
/**
|
|
@@ -163,41 +163,43 @@ export interface NodeRuntimeCreateOptions {
|
|
|
163
163
|
*/
|
|
164
164
|
nodeModules?: string | NodeModulesMount;
|
|
165
165
|
/**
|
|
166
|
-
* Host-side
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
166
|
+
* Host-side functions the guest can invoke as shell commands, as a record of
|
|
167
|
+
* collections. The keys name everything: the collection key becomes the guest
|
|
168
|
+
* command `agentos-{name}` and each function key becomes one of its
|
|
169
|
+
* subcommands. When the guest runs it the invocation round-trips back to the
|
|
170
|
+
* host, runs the function's `execute`, and its return value is delivered back
|
|
171
|
+
* to the guest. This is how you give sandboxed guest code controlled, named
|
|
172
|
+
* host capabilities (the kind an AI agent calls as tools) without granting it
|
|
173
|
+
* the underlying access directly.
|
|
172
174
|
*
|
|
173
|
-
*
|
|
175
|
+
* This is the same shape `AgentOs.create()` takes. A function needs only a
|
|
176
|
+
* Zod `inputSchema` and an `execute` handler; `.describe()` on the schema is
|
|
177
|
+
* what the agent reads.
|
|
174
178
|
*
|
|
175
179
|
* ```ts
|
|
176
180
|
* const rt = await NodeRuntime.create({
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
181
|
+
* hostFunctions: {
|
|
182
|
+
* math: {
|
|
183
|
+
* add: {
|
|
184
|
+
* inputSchema: z
|
|
185
|
+
* .object({ a: z.number(), b: z.number() })
|
|
186
|
+
* .describe("Add two numbers"),
|
|
187
|
+
* execute: ({ a, b }) => ({ sum: a + b }),
|
|
184
188
|
* },
|
|
185
|
-
* handler: ({ a, b }: { a: number; b: number }) => ({ sum: a + b }),
|
|
186
189
|
* },
|
|
187
190
|
* },
|
|
188
191
|
* });
|
|
189
192
|
* await rt.exec(`
|
|
190
193
|
* import { execFileSync } from "node:child_process";
|
|
191
|
-
* const out = execFileSync("
|
|
194
|
+
* const out = execFileSync("agentos-math", ["add", "--json", JSON.stringify({ a: 2, b: 3 })]);
|
|
192
195
|
* console.log(out.toString());
|
|
193
196
|
* `);
|
|
194
197
|
* ```
|
|
195
198
|
*
|
|
196
|
-
*
|
|
197
|
-
* `
|
|
198
|
-
* your own `permissions.binding` policy to gate individual bindings.
|
|
199
|
+
* The `hostFunction` permission scope is allowed by default; pass your own
|
|
200
|
+
* `permissions.hostFunction` policy to gate individual host functions.
|
|
199
201
|
*/
|
|
200
|
-
|
|
202
|
+
hostFunctions?: HostFunctionCollections<HOST_FUNCTIONS>;
|
|
201
203
|
/**
|
|
202
204
|
* Guest-bound ports that may accept non-loopback connections. By default a
|
|
203
205
|
* guest server is reachable only over loopback inside the VM; listing a port
|
|
@@ -449,7 +451,7 @@ export declare class NodeRuntime {
|
|
|
449
451
|
* session, creates the VM with a bootstrapped root filesystem, mounts the
|
|
450
452
|
* shell and Node runtimes, and waits for the VM to report ready.
|
|
451
453
|
*/
|
|
452
|
-
static create(
|
|
454
|
+
static create<HOST_FUNCTIONS extends HostFunctionSchemas>(callerOptions: NodeRuntimeCreateOptions<HOST_FUNCTIONS>): Promise<NodeRuntime>;
|
|
453
455
|
createResidentRunner(_options?: NodeRuntimeResidentRunnerOptions): Promise<NodeRuntimeResidentRunner>;
|
|
454
456
|
/**
|
|
455
457
|
* Run `code` as a guest Node program and capture its output.
|
|
@@ -571,19 +573,18 @@ export declare class NodeRuntime {
|
|
|
571
573
|
*/
|
|
572
574
|
waitForListener(query: NodeRuntimeListenerQuery, options?: NodeRuntimeWaitForListenerOptions): Promise<NodeRuntimeListener>;
|
|
573
575
|
/**
|
|
574
|
-
* Register host-side
|
|
576
|
+
* Register host-side hostFunctions the guest can invoke as shell commands, after
|
|
575
577
|
* the VM is already running. Each entry becomes a named guest command; when
|
|
576
578
|
* the guest runs it, the invocation round-trips back to the host and runs the
|
|
577
|
-
*
|
|
578
|
-
* is the same capability as the `
|
|
579
|
-
*
|
|
579
|
+
* hostFunction's `handler`, whose return value is delivered back to the guest. This
|
|
580
|
+
* is the same capability as the `hostFunctions` create option, exposed for adding
|
|
581
|
+
* host functions to a live runtime. See `hostFunctions` on {@link NodeRuntime.create} for
|
|
580
582
|
* the invocation shape and permission behavior.
|
|
581
583
|
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
* {@link NodeRuntime.create}) so the bindings are invocable.
|
|
584
|
+
* The `hostFunction` permission scope is allowed by default, so these host
|
|
585
|
+
* functions are invocable unless the runtime's policy restricts them.
|
|
585
586
|
*/
|
|
586
|
-
|
|
587
|
+
registerHostFunctions(hostFunctions: HostFunctionCollections): Promise<void>;
|
|
587
588
|
/**
|
|
588
589
|
* Write a file into the VM's virtual filesystem, creating parent
|
|
589
590
|
* directories as needed. Use this to project assets or npm packages into
|
package/dist/node-runtime.js
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
import { existsSync } from "node:fs";
|
|
21
21
|
import path from "node:path";
|
|
22
22
|
import { fileURLToPath } from "node:url";
|
|
23
|
-
import { createKernel, createNodeRuntime, createWasmVmRuntime, NodeFileSystem, } from "./test-runtime.js";
|
|
24
23
|
import { parseNodeRuntimeCreateOptions } from "./node-runtime-options-schema.js";
|
|
24
|
+
import { createKernel, createNodeRuntime, createWasmVmRuntime, NodeFileSystem, } from "./test-runtime.js";
|
|
25
25
|
export { resolveNodeRuntimeSidecarBinary } from "./test-runtime.js";
|
|
26
26
|
/** Repository root, used to locate the in-repo WASM command build output. */
|
|
27
27
|
const REPO_ROOT = fileURLToPath(new URL("../../..", import.meta.url));
|
|
@@ -66,47 +66,30 @@ export function resolveNodeRuntimeCommandsDir(explicit) {
|
|
|
66
66
|
}
|
|
67
67
|
return BUNDLED_COMMANDS_DIR;
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Secure-by-default permission policy applied when the caller passes no
|
|
71
|
-
* `permissions`. Outward-facing capabilities are denied: there is **no network
|
|
72
|
-
* access** (and no host callbacks) by default — guest code cannot reach the
|
|
73
|
-
* network until you opt in. The filesystem, child-process, process, and env
|
|
74
|
-
* scopes are allowed because they are fully virtualized (the guest only ever
|
|
75
|
-
* sees the VM's in-memory filesystem and kernel-managed processes, never the
|
|
76
|
-
* real host) and are required for the runtime to execute a guest program at
|
|
77
|
-
* all. Tighten or widen any scope by passing your own `permissions`.
|
|
78
|
-
*/
|
|
79
|
-
const DEFAULT_PERMISSIONS = {
|
|
80
|
-
fs: "allow",
|
|
81
|
-
childProcess: "allow",
|
|
82
|
-
process: "allow",
|
|
83
|
-
env: "allow",
|
|
84
|
-
network: "deny",
|
|
85
|
-
};
|
|
86
69
|
/** Guest path a `nodeModules` mount is projected at by default. */
|
|
87
70
|
const DEFAULT_NODE_MODULES_GUEST_PATH = "/tmp/node_modules";
|
|
88
71
|
let nextProgramId = 0;
|
|
89
72
|
let nextResidentRequestId = 0;
|
|
90
73
|
/**
|
|
91
|
-
* Guest preamble exposing `globalThis.
|
|
92
|
-
* async wrapper over the
|
|
93
|
-
* as the guest would by hand (`<
|
|
74
|
+
* Guest preamble exposing `globalThis.callHostFunction(name, input?)`: an ergonomic
|
|
75
|
+
* async wrapper over the hostFunction invocation path. It runs the registered hostFunction
|
|
76
|
+
* as the guest would by hand (`<host-function> --json <input>` through
|
|
94
77
|
* `node:child_process`), so it inherits every security property of that path:
|
|
95
|
-
* the `
|
|
78
|
+
* the `hostFunction` permission scope, the host function's input-schema validation, and the
|
|
96
79
|
* host-side handler all still apply. It adds no new trust surface; it only
|
|
97
80
|
* removes the manual `execFile`/JSON boilerplate so guest and agent code can do
|
|
98
|
-
* `const out = await
|
|
81
|
+
* `const out = await callHostFunction("add", { a, b })`. The value is a single line
|
|
99
82
|
* so it shifts guest source line numbers by at most one in stack traces.
|
|
100
83
|
*
|
|
101
|
-
* Note: the
|
|
102
|
-
* would require a dedicated async guest-to-host
|
|
84
|
+
* Note: the hostFunction still runs through a guest process. Eliminating that spawn
|
|
85
|
+
* would require a dedicated async guest-to-host hostFunction channel (the synchronous
|
|
103
86
|
* sync-RPC path cannot be used: it runs on the sidecar's main sync-RPC thread and
|
|
104
87
|
* a host round-trip would block it); that is a separate, test-gated change.
|
|
105
88
|
*/
|
|
106
|
-
const
|
|
107
|
-
/** Prepend the
|
|
108
|
-
function
|
|
109
|
-
return `${
|
|
89
|
+
const HOST_FUNCTION_PREAMBLE = `globalThis.callHostFunction = (name, input = {}) => import("node:child_process").then(({ execFile }) => new Promise((resolve, reject) => { execFile(name, [name, "--json", JSON.stringify(input)], { maxBuffer: 64 * 1024 * 1024 }, (error, stdout, stderr) => { if (error) { reject(new Error(String(stderr || "").trim() || error.message)); return; } const text = String(stdout ?? "").trim(); let reply; try { reply = text ? JSON.parse(text) : undefined; } catch { reject(new Error("host function returned invalid JSON: " + text)); return; } if (reply && reply.ok === false) { reject(new Error(reply.error || "host function failed")); return; } resolve(reply && typeof reply === "object" && "result" in reply ? reply.result : reply); }); }));`;
|
|
90
|
+
/** Prepend the hostFunction helper preamble to guest program source. */
|
|
91
|
+
function withHostFunctionPreamble(code) {
|
|
92
|
+
return `${HOST_FUNCTION_PREAMBLE}\n${code}`;
|
|
110
93
|
}
|
|
111
94
|
const RESIDENT_READY_PREFIX = "__AGENTOS_RESIDENT_READY__";
|
|
112
95
|
const RESIDENT_RESULT_PREFIX = "__AGENTOS_RESIDENT_RESULT__";
|
|
@@ -128,8 +111,10 @@ export class NodeRuntime {
|
|
|
128
111
|
* session, creates the VM with a bootstrapped root filesystem, mounts the
|
|
129
112
|
* shell and Node runtimes, and waits for the VM to report ready.
|
|
130
113
|
*/
|
|
131
|
-
static async create(
|
|
132
|
-
|
|
114
|
+
static async create(callerOptions) {
|
|
115
|
+
// The generic exists only so each `execute` infers its input from its own
|
|
116
|
+
// `inputSchema`; past this point the concrete schemas carry no meaning.
|
|
117
|
+
const options = parseNodeRuntimeCreateOptions(callerOptions);
|
|
133
118
|
const commandsDir = resolveNodeRuntimeCommandsDir(options.commandsDir);
|
|
134
119
|
// Seed caller-provided files into the VM's in-memory filesystem before
|
|
135
120
|
// boot so they are part of the root filesystem snapshot the guest sees
|
|
@@ -163,24 +148,12 @@ export class NodeRuntime {
|
|
|
163
148
|
fs: new NodeFileSystem({ root: mount.hostPath }),
|
|
164
149
|
readOnly: mount.readOnly ?? true,
|
|
165
150
|
}));
|
|
166
|
-
// Grant the `binding` scope when the caller registers bindings but does not
|
|
167
|
-
// set their own binding policy, so the registered bindings are invocable.
|
|
168
|
-
const bindingDefaults = options.bindings &&
|
|
169
|
-
Object.keys(options.bindings).length > 0 &&
|
|
170
|
-
options.permissions?.binding === undefined
|
|
171
|
-
? { binding: "allow" }
|
|
172
|
-
: {};
|
|
173
151
|
const kernel = createKernel({
|
|
174
152
|
filesystem,
|
|
175
153
|
mounts: mounts.length > 0 ? mounts : undefined,
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
|
|
179
|
-
permissions: {
|
|
180
|
-
...DEFAULT_PERMISSIONS,
|
|
181
|
-
...bindingDefaults,
|
|
182
|
-
...options.permissions,
|
|
183
|
-
},
|
|
154
|
+
// The sidecar owns the defaults and merges this policy over them, so
|
|
155
|
+
// only the scopes the caller set are sent.
|
|
156
|
+
permissions: options.permissions,
|
|
184
157
|
env: options.env,
|
|
185
158
|
cwd: options.cwd,
|
|
186
159
|
user: options.user,
|
|
@@ -199,11 +172,11 @@ export class NodeRuntime {
|
|
|
199
172
|
commandDirs: [commandsDir, ...(options.wasmCommandDirs ?? [])],
|
|
200
173
|
})));
|
|
201
174
|
await measureBootTiming("runtime_mount_node", options.onBootTiming, () => kernel.mount(createNodeRuntime()));
|
|
202
|
-
// Register
|
|
175
|
+
// Register hostFunctions after the runtimes are mounted so they are
|
|
203
176
|
// installed as guest commands the moment the VM is ready.
|
|
204
|
-
const
|
|
205
|
-
if (
|
|
206
|
-
await measureBootTiming("
|
|
177
|
+
const hostFunctions = options.hostFunctions;
|
|
178
|
+
if (hostFunctions && Object.keys(hostFunctions).length > 0) {
|
|
179
|
+
await measureBootTiming("hostFunctions", options.onBootTiming, () => kernel.registerHostFunctions(hostFunctions));
|
|
207
180
|
}
|
|
208
181
|
}
|
|
209
182
|
catch (error) {
|
|
@@ -223,7 +196,7 @@ export class NodeRuntime {
|
|
|
223
196
|
*/
|
|
224
197
|
async exec(code, options = {}) {
|
|
225
198
|
const programPath = `/tmp/agentos-program-${nextProgramId++}.mjs`;
|
|
226
|
-
await this.kernel.writeFile(programPath,
|
|
199
|
+
await this.kernel.writeFile(programPath, withHostFunctionPreamble(code));
|
|
227
200
|
return this.runProgram(programPath, options);
|
|
228
201
|
}
|
|
229
202
|
/**
|
|
@@ -329,7 +302,7 @@ export class NodeRuntime {
|
|
|
329
302
|
*/
|
|
330
303
|
async spawn(code, options = {}) {
|
|
331
304
|
const programPath = `/tmp/agentos-program-${nextProgramId++}.mjs`;
|
|
332
|
-
await this.kernel.writeFile(programPath,
|
|
305
|
+
await this.kernel.writeFile(programPath, withHostFunctionPreamble(code));
|
|
333
306
|
const proc = this.kernel.spawn("node", [programPath], {
|
|
334
307
|
env: options.env,
|
|
335
308
|
cwd: options.cwd,
|
|
@@ -453,7 +426,7 @@ export class NodeRuntime {
|
|
|
453
426
|
// statements inside a function and make them a SyntaxError.
|
|
454
427
|
const wrapped = [
|
|
455
428
|
`import { writeFileSync as __writeFileSync } from "node:fs";`,
|
|
456
|
-
|
|
429
|
+
HOST_FUNCTION_PREAMBLE,
|
|
457
430
|
`globalThis.__return = (value) => {`,
|
|
458
431
|
` __writeFileSync(${JSON.stringify(resultPath)}, JSON.stringify(value === undefined ? null : value));`,
|
|
459
432
|
`};`,
|
|
@@ -576,20 +549,19 @@ export class NodeRuntime {
|
|
|
576
549
|
}
|
|
577
550
|
}
|
|
578
551
|
/**
|
|
579
|
-
* Register host-side
|
|
552
|
+
* Register host-side hostFunctions the guest can invoke as shell commands, after
|
|
580
553
|
* the VM is already running. Each entry becomes a named guest command; when
|
|
581
554
|
* the guest runs it, the invocation round-trips back to the host and runs the
|
|
582
|
-
*
|
|
583
|
-
* is the same capability as the `
|
|
584
|
-
*
|
|
555
|
+
* hostFunction's `handler`, whose return value is delivered back to the guest. This
|
|
556
|
+
* is the same capability as the `hostFunctions` create option, exposed for adding
|
|
557
|
+
* host functions to a live runtime. See `hostFunctions` on {@link NodeRuntime.create} for
|
|
585
558
|
* the invocation shape and permission behavior.
|
|
586
559
|
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
* {@link NodeRuntime.create}) so the bindings are invocable.
|
|
560
|
+
* The `hostFunction` permission scope is allowed by default, so these host
|
|
561
|
+
* functions are invocable unless the runtime's policy restricts them.
|
|
590
562
|
*/
|
|
591
|
-
async
|
|
592
|
-
await this.kernel.
|
|
563
|
+
async registerHostFunctions(hostFunctions) {
|
|
564
|
+
await this.kernel.registerHostFunctions(hostFunctions);
|
|
593
565
|
}
|
|
594
566
|
/**
|
|
595
567
|
* Write a file into the VM's virtual filesystem, creating parent
|
package/dist/permissions.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface LivePermissionsPolicy {
|
|
|
22
22
|
child_process?: LivePermissionScope<LivePatternPermissionRule>;
|
|
23
23
|
process?: LivePermissionScope<LivePatternPermissionRule>;
|
|
24
24
|
env?: LivePermissionScope<LivePatternPermissionRule>;
|
|
25
|
-
|
|
25
|
+
host_function?: LivePermissionScope<LivePatternPermissionRule>;
|
|
26
26
|
}
|
|
27
27
|
export declare function toGeneratedPermissionsPolicy(policy: LivePermissionsPolicy | undefined): protocol.PermissionsPolicy | null;
|
|
28
28
|
export declare function toGeneratedFilesystemPermissionScope(scope: LivePermissionScope<LiveFsPermissionRule>): protocol.FsPermissionScope;
|
package/dist/permissions.js
CHANGED
|
@@ -19,9 +19,9 @@ export function toGeneratedPermissionsPolicy(policy) {
|
|
|
19
19
|
env: policy.env === undefined
|
|
20
20
|
? null
|
|
21
21
|
: toGeneratedPatternPermissionScope(policy.env),
|
|
22
|
-
|
|
22
|
+
hostFunction: policy.host_function === undefined
|
|
23
23
|
? null
|
|
24
|
-
: toGeneratedPatternPermissionScope(policy.
|
|
24
|
+
: toGeneratedPatternPermissionScope(policy.host_function),
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
export function toGeneratedFilesystemPermissionScope(scope) {
|
|
@@ -42,7 +42,7 @@ export type LiveRequestPayload = {
|
|
|
42
42
|
packages?: LivePackageDescriptor[];
|
|
43
43
|
packages_mount_at?: string;
|
|
44
44
|
bootstrap_commands?: string[];
|
|
45
|
-
|
|
45
|
+
host_function_shim_commands?: string[];
|
|
46
46
|
} | {
|
|
47
47
|
type: "link_package";
|
|
48
48
|
package: LivePackageDescriptor;
|
package/dist/request-payloads.js
CHANGED
|
@@ -58,7 +58,7 @@ export function toGeneratedRequestPayload(payload) {
|
|
|
58
58
|
packages: (payload.packages ?? []).map(toGeneratedPackageDescriptor),
|
|
59
59
|
packagesMountAt: payload.packages_mount_at ?? "",
|
|
60
60
|
bootstrapCommands: payload.bootstrap_commands ?? [],
|
|
61
|
-
|
|
61
|
+
hostFunctionShimCommands: payload.host_function_shim_commands ?? [],
|
|
62
62
|
},
|
|
63
63
|
};
|
|
64
64
|
case "link_package":
|
|
@@ -176,7 +176,7 @@ export interface SidecarPermissionsPolicy {
|
|
|
176
176
|
childProcess?: SidecarPermissionScope<SidecarPatternPermissionRule>;
|
|
177
177
|
process?: SidecarPermissionScope<SidecarPatternPermissionRule>;
|
|
178
178
|
env?: SidecarPermissionScope<SidecarPatternPermissionRule>;
|
|
179
|
-
|
|
179
|
+
hostFunction?: SidecarPermissionScope<SidecarPatternPermissionRule>;
|
|
180
180
|
}
|
|
181
181
|
export interface SidecarProjectedModuleDescriptor {
|
|
182
182
|
packageName: string;
|
|
@@ -247,7 +247,7 @@ export declare class SidecarProcess {
|
|
|
247
247
|
packages?: SidecarPackageDescriptor[];
|
|
248
248
|
packagesMountAt?: string;
|
|
249
249
|
bootstrapCommands?: string[];
|
|
250
|
-
|
|
250
|
+
hostFunctionShimCommands?: string[];
|
|
251
251
|
}): Promise<SidecarVmConfiguredResponse>;
|
|
252
252
|
/**
|
|
253
253
|
* Runtime dynamic `linkSoftware`: project one package into the live
|
package/dist/sidecar-process.js
CHANGED
|
@@ -147,7 +147,7 @@ export class SidecarProcess {
|
|
|
147
147
|
? { packages_mount_at: options.packagesMountAt }
|
|
148
148
|
: {}),
|
|
149
149
|
bootstrap_commands: options.bootstrapCommands ?? [],
|
|
150
|
-
|
|
150
|
+
host_function_shim_commands: options.hostFunctionShimCommands ?? [],
|
|
151
151
|
},
|
|
152
152
|
});
|
|
153
153
|
if (response.payload.type !== "vm_configured") {
|
|
@@ -1074,7 +1074,7 @@ function toWirePermissionsPolicy(policy) {
|
|
|
1074
1074
|
child_process: policy.childProcess,
|
|
1075
1075
|
process: policy.process,
|
|
1076
1076
|
env: policy.env,
|
|
1077
|
-
|
|
1077
|
+
host_function: policy.hostFunction,
|
|
1078
1078
|
};
|
|
1079
1079
|
}
|
|
1080
1080
|
function toWireProjectedModuleDescriptor(descriptor) {
|
package/dist/test-runtime.d.ts
CHANGED
|
@@ -96,7 +96,7 @@ export type NetworkPermissions = PermissionMode | RulePermissions<PatternPermiss
|
|
|
96
96
|
export type ChildProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
97
97
|
export type ProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
98
98
|
export type EnvPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
99
|
-
export type
|
|
99
|
+
export type HostFunctionPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
100
100
|
export interface ProcessInfo {
|
|
101
101
|
pid: number;
|
|
102
102
|
ppid: number;
|
|
@@ -185,43 +185,18 @@ export interface Permissions {
|
|
|
185
185
|
childProcess?: ChildProcessPermissions;
|
|
186
186
|
process?: ProcessPermissions;
|
|
187
187
|
env?: EnvPermissions;
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
/** A worked example shown alongside a registered binding. */
|
|
191
|
-
export interface BindingExample {
|
|
192
|
-
/** What this example demonstrates. */
|
|
193
|
-
description: string;
|
|
194
|
-
/** Example input matching the binding's input schema. */
|
|
195
|
-
input: unknown;
|
|
188
|
+
hostFunction?: HostFunctionPermissions;
|
|
196
189
|
}
|
|
197
190
|
/**
|
|
198
|
-
* A host-side
|
|
199
|
-
* runs the
|
|
200
|
-
* `handler`, whose return value is passed back to the guest.
|
|
191
|
+
* A host-side function that guest code can invoke as a shell command. The guest
|
|
192
|
+
* runs the host function by name and the invocation round-trips back to the host JS
|
|
193
|
+
* `handler`, whose return value is passed back to the guest. Host functions never run
|
|
201
194
|
* inside the guest: they execute on the host, so they are the bridge for giving
|
|
202
195
|
* sandboxed guest code controlled, named capabilities (the kind AI agents call
|
|
203
196
|
* as tools).
|
|
204
197
|
*/
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
description: string;
|
|
208
|
-
/** JSON Schema describing the binding's input. */
|
|
209
|
-
inputSchema: object;
|
|
210
|
-
/** Abort the invocation after this many milliseconds. */
|
|
211
|
-
timeoutMs?: number;
|
|
212
|
-
/** Worked examples shown alongside the binding. */
|
|
213
|
-
examples?: BindingExample[];
|
|
214
|
-
/**
|
|
215
|
-
* Extra command names the guest can use to invoke this binding, in addition
|
|
216
|
-
* to the key it is registered under.
|
|
217
|
-
*/
|
|
218
|
-
commandAliases?: string[];
|
|
219
|
-
/**
|
|
220
|
-
* Host handler invoked when guest code runs the binding. Receives the parsed
|
|
221
|
-
* input and returns a JSON-serializable result delivered back to the guest.
|
|
222
|
-
*/
|
|
223
|
-
handler: (input: unknown) => unknown | Promise<unknown>;
|
|
224
|
-
}
|
|
198
|
+
import { type HostFunctionCollections } from "./host-functions.js";
|
|
199
|
+
export type { HostFunction, HostFunctionCollection, HostFunctionCollections, HostFunctionExample, } from "./host-functions.js";
|
|
225
200
|
export interface ResourceBudgets {
|
|
226
201
|
maxOutputBytes?: number;
|
|
227
202
|
maxBridgeCalls?: number;
|
|
@@ -347,7 +322,7 @@ export interface Kernel extends KernelInterface {
|
|
|
347
322
|
streamId?: string;
|
|
348
323
|
maxBytes?: number;
|
|
349
324
|
}): Promise<string>;
|
|
350
|
-
|
|
325
|
+
registerHostFunctions(hostFunctions: HostFunctionCollections): Promise<void>;
|
|
351
326
|
getResourceSnapshot(): Promise<{
|
|
352
327
|
runningProcesses: number;
|
|
353
328
|
exitedProcesses: number;
|
|
@@ -390,10 +365,10 @@ export interface Kernel extends KernelInterface {
|
|
|
390
365
|
readonly timerTable: Record<string, never>;
|
|
391
366
|
readonly zombieTimerCount: number;
|
|
392
367
|
}
|
|
393
|
-
export interface
|
|
394
|
-
[key: string]:
|
|
368
|
+
export interface HostFunctionTree {
|
|
369
|
+
[key: string]: HostFunctionHandler | HostFunctionTree;
|
|
395
370
|
}
|
|
396
|
-
export type
|
|
371
|
+
export type HostFunctionHandler = (...args: unknown[]) => unknown;
|
|
397
372
|
export interface ModuleAccessOptions {
|
|
398
373
|
cwd?: string;
|
|
399
374
|
}
|
|
@@ -415,7 +390,7 @@ export interface NodeRuntimeOptions {
|
|
|
415
390
|
permissions?: Partial<Permissions>;
|
|
416
391
|
memoryLimit?: number;
|
|
417
392
|
moduleAccessPaths?: string[];
|
|
418
|
-
|
|
393
|
+
hostFunctions?: HostFunctionTree;
|
|
419
394
|
loopbackExemptPorts?: number[];
|
|
420
395
|
moduleAccessCwd?: string;
|
|
421
396
|
packageRoots?: Array<{
|