//#region src/sandbox/bridged-source.d.ts /** * Host-bridged source execution - the sandbox primitive behind * code-mode / programmatic tool calling. * * The four built-in adapters ({@link createNoneSandbox} et al.) run a * **pre-registered handler** (`code.kind === 'handler'`): a module + * export resolved inside the worker, invoked once with a single * structured-cloneable `input`, returning a single value. That model * cannot express "run this model-written script, and while it runs let * it call back out to a fixed set of host tools, keeping every * intermediate value inside the sandbox." * * `runBridgedSource(...)` adds exactly that, as a **separate** surface so * the audited handler runtimes stay byte-identical. It spawns a * `node:worker_threads` `Worker`, evaluates the supplied source as the * body of an `async (tools) => { … }` function, and exposes `tools` as a * set of async functions - one per allowed name - that round-trip each * call to the parent over the worker `MessagePort`. The parent services * the call via the injected {@link BridgedSourceOptions.dispatch} hook * (the agent wires this to the real {@link ToolExecutor}, so per-tool * ACL / sanitization / truncation still apply). Only the script's final * return value crosses back; intermediate values never leave the worker. * * Isolation is the `worker-threads` tier's: a fresh V8 isolate per run, * an empty environment (the worker is constructed with `env: {}` and the * runtime scrubs `process.env` before user code runs, so host secrets * are not visible), best-effort `node:fs` / `node:net` import * blocking and a `fetch` refusal (reused from * {@link createWorkerThreadsSandbox}), a hard wall-clock timeout via * `worker.terminate()`, an optional memory ceiling, and `AbortSignal` * cancellation. The **only** channel from the * worker to the host is the tool-call RPC, and it serves none but the * `allowedTools` names - there is no way to obtain a reference to the * executor, the registry, or any other host object (functions do not * survive `structuredClone`). As with `createWorkerThreadsSandbox`, this * is defence in depth, not a guarantee against process-level mischief by * hostile code; deployments that need V8-grade isolation should layer * `isolated-vm` / `docker` underneath (host-bridging those tiers is a * follow-up). * * @packageDocumentation */ /** A single tool invocation the sandboxed script asked the host to run. */ interface BridgedToolCall { /** Registered tool name the script invoked via `tools.(args)`. */ readonly name: string; /** The arguments object the script passed; structured-clone safe. */ readonly args: unknown; } /** Options for {@link runBridgedSource}. */ interface BridgedSourceOptions { /** * Model-written JavaScript, evaluated as the body of an * `async (tools) => { … }` function. A top-level `return` yields the * final result; the value must be structured-clone safe. */ readonly source: string; /** Names the script may call as `tools.(args)`. */ readonly allowedTools: ReadonlyArray; /** * Host bridge invoked for each `tools.(args)` call. Resolve with * the tool's output (structured-clone safe) or reject to surface an * error to the script. Calls for a name not in `allowedTools` are * rejected by the runner before `dispatch` is consulted. */ readonly dispatch: (call: BridgedToolCall) => Promise; /** Hard wall-clock timeout (ms) for the whole script. Default 30000. */ readonly timeoutMs?: number; /** Memory ceiling (MB) for the worker. Omitted ⇒ Node default. */ readonly maxMemoryMb?: number; /** Block outbound network (`fetch` + `node:http`/`net`/…). Default true. */ readonly noNetwork?: boolean; /** Block filesystem (`node:fs`/…) imports. Default true. */ readonly noFilesystem?: boolean; /** Cancellation signal; aborts the run and terminates the worker. */ readonly signal?: AbortSignal; /** Ceiling on bridged tool calls per run. Default 64. */ readonly maxToolCalls?: number; /** Grace (ms) after abort before forcible `terminate()`. Default 100. */ readonly abortGraceMs?: number; /** Optional WARN logger. */ readonly warn?: (message: string) => void; } /** Outcome of a {@link runBridgedSource} run. */ type BridgedSourceResult = { readonly ok: true; /** The script's final return value (structured-clone safe). */ readonly output: unknown; /** Number of bridged tool calls the script made. */ readonly toolCalls: number; readonly durationMs: number; } | { readonly ok: false; readonly error: { readonly kind: 'timeout' | 'sandbox-violation' | 'aborted' | 'execution-failed'; readonly message: string; }; readonly toolCalls: number; readonly durationMs: number; }; /** * E3 (item 13, step 1): the code-mode RUNTIME contract - the seam * through which a harness substitutes WHERE model-written code * executes (a different worker pool, a subprocess, a remote runner). * {@link runBridgedSource} is the built-in `worker_threads` * implementation; a provider conforms by accepting the same options * and settling with the same result union. * * Invariant (fixed): the options carry ONLY the script source, the * allowed tool names, the host `dispatch` bridge, the cancellation * signal and resource limits. Credentials, `RunState` and policy stay * on the harness side - every in-script `tools.(args)` call * routes back through `dispatch` into the host's tool executor, where * ACL / sanitization / taint / permission governance applies. A * provider therefore never needs (and must never be handed) secret * material or run internals. * * @stable */ type CodeModeRunner = (options: BridgedSourceOptions) => Promise; /** * Run model-written source in a worker, bridging `tools.(args)` * calls back to the host. See the module docstring for the isolation * contract. * * @stable */ declare function runBridgedSource(opts: BridgedSourceOptions): Promise; //#endregion export { BridgedSourceOptions, BridgedSourceResult, BridgedToolCall, CodeModeRunner, runBridgedSource }; //# sourceMappingURL=bridged-source.d.ts.map