import type { SandboxBackend, ShellResult } from './types.js'; export interface FileStat { type: 'file' | 'directory' | 'symlink' | 'other'; size: number; mtime?: Date; mode?: number; } export interface SandboxSnapshot { id: string; label?: string; metadata?: Record; } export interface SnapshotPruneOptions { keep?: number; olderThanMs?: number; } export interface SnapshotPruneResult { removed: string[]; kept: string[]; } export interface SandboxExecOptions { cwd?: string; env?: Record; timeout?: number; signal?: AbortSignal; /** Receives stdout chunks while the provider is executing the command. */ onStdout?: (chunk: string) => void; /** Receives stderr chunks while the provider is executing the command. */ onStderr?: (chunk: string) => void; /** Observe eventual settlement after prompt cancellation returned to the caller. */ onOrphanSettled?: (settlement: SandboxOrphanSettlement) => void | Promise; } export type SandboxOrphanSettlement = { status: 'fulfilled'; exitCode: number; } | { status: 'rejected'; error: string; }; /** * Reject promptly on cancellation even when a remote provider cannot cancel * its command. The underlying promise remains observed and reports its final, * redacted settlement through `onOrphanSettled`. */ export declare function execSandboxCommand(sandbox: SandboxEnv, command: string, options?: SandboxExecOptions): Promise; export interface SandboxCapabilities { exec: boolean; filesystem: boolean; binaryFiles: boolean; snapshots: boolean; restore: boolean; /** True when a portable reference can reconnect to the same running sandbox. */ reconnect?: boolean; /** True when the sandbox can be forked from a snapshot into independent branches. */ fork?: boolean; /** True when the sandbox can be suspended (paused) and later resumed without losing state. */ suspend?: boolean; resume?: boolean; network: 'none' | 'restricted' | 'egress' | 'provider-managed'; /** * Strongest layer that enforces the advertised network restriction. * `process` policy is defense in depth only: code running in the sandbox can * bypass it with a direct socket. Production allowlists should use a * container, cluster, or provider boundary. */ networkEnforcement?: 'none' | 'process' | 'container' | 'cluster' | 'provider'; /** Non-secret operator reference, such as a Docker network or NetworkPolicy name. */ networkBoundary?: string; persistence: 'ephemeral' | 'session' | 'durable'; isolation: 'process' | 'container' | 'microvm' | 'provider'; } export interface SandboxEnv { exec(command: string, options?: SandboxExecOptions): Promise; readFile(path: string): Promise; readFileBuffer(path: string): Promise; writeFile(path: string, content: string | Uint8Array): Promise; stat(path: string): Promise; readdir(path: string): Promise; exists(path: string): Promise; mkdir(path: string, options?: { recursive?: boolean; }): Promise; rm(path: string, options?: { recursive?: boolean; force?: boolean; }): Promise; readonly cwd: string; readonly capabilities?: SandboxCapabilities; resolvePath(path: string): string; snapshot?(): Promise; restore?(snapshot: SandboxSnapshot): Promise; /** * Create a new independent sandbox initialized from the given snapshot. * Each fork is fully independent — writes in one are invisible to the * others and to the origin. The origin sandbox continues running * unaffected. Implementations that don't support forking should omit. */ fork?(snapshot: SandboxSnapshot): Promise; /** * Pause the sandbox so its compute is released but state is preserved. * Optional capability — providers without native suspend may implement * via snapshot+stop, or omit entirely. */ suspend?(): Promise; /** Resume a suspended sandbox. Idempotent when already running. */ resume?(): Promise; /** * Optional. Return provider-specific routing data so this sandbox can be * re-attached from a different process. Backends that can be reached only * by ID (E2B, Daytona, Modal call IDs, Kubernetes pod refs) implement this; * in-process backends (Local) typically omit it, since refs are scoped to * one process. * * The returned `provider` string must match a decoder registered via * `registerSandboxRefDecoder()` for the ref to be re-attachable. */ encodeRef?(): { provider: string; providerData: unknown; } | undefined; /** @internal Scoped grant used only after the session approval machinery resolves a call. */ __runWithPolicyApproval?(call: import('./tools.js').ToolCall, operation: () => Promise): Promise; cleanup(): Promise; } export interface SandboxFactoryOptions { backend?: SandboxBackend; workspacePath?: string; sessionId?: string; env?: Record; metadata?: Record; /** Default working directory inside the sandbox workspace. */ cwd?: string; /** * Auto-suspend the sandbox after `idleSuspendMs` of inactivity. Operations * (exec / read / write / etc.) reset the idle timer and transparently * resume a previously-suspended sandbox. Backends that lack native * suspend/resume (or don't implement them) simply ignore this option. * * Defaults to `undefined` (no auto-suspend). */ idleSuspendMs?: number; /** * When true (default), accessing a suspended sandbox auto-resumes it * before serving the request. Set to false to receive an error instead. */ autoResumeOnAccess?: boolean; } export type SandboxFactory = (options: SandboxFactoryOptions) => Promise | SandboxEnv; /** * Register an implementation for a non-core `SandboxBackend` name. Provider packages use this * hook so the shared runtime can resolve backends such as `databricks` without depending on them. */ export declare function registerSandboxBackendFactory(backend: SandboxBackend, factory: SandboxFactory): void; /** Remove a provider-owned backend factory, primarily for tests and controlled shutdown. */ export declare function unregisterSandboxBackendFactory(backend: SandboxBackend): void; /** Return provider backend names currently available to `createSandboxEnv()`. */ export declare function listSandboxBackendFactories(): SandboxBackend[]; export interface RemoteSandboxApi { exec(command: string, options?: SandboxExecOptions): Promise; readFile(path: string): Promise; readFileBuffer(path: string): Promise; writeFile(path: string, content: string | Uint8Array): Promise; stat(path: string): Promise; readdir(path: string): Promise; exists(path: string): Promise; mkdir(path: string, options?: { recursive?: boolean; }): Promise; rm(path: string, options?: { recursive?: boolean; force?: boolean; }): Promise; snapshot?(): Promise; restore?(snapshot: SandboxSnapshot): Promise; /** * Provider-native start-from-snapshot. Returns a new RemoteSandboxApi * (typically wrapping a fresh provider sandbox) that's been initialized * to the snapshotted state. The origin remains unaffected. */ fork?(snapshot: SandboxSnapshot): Promise; /** Provider-native suspend (e.g. E2B `pause`, Daytona `stop`). */ suspend?(): Promise; /** Provider-native resume (e.g. E2B `resume`, Daytona `start`). */ resume?(): Promise; } export interface RemoteSandboxOptions { cwd?: string; cleanup?: (() => void | Promise) | { cleanup(): void | Promise; }; pathStyle?: 'posix'; capabilities?: SandboxCapabilities; /** * Optional encoder for cross-process refs. When set, the resulting * SandboxEnv exposes `encodeRef()` returning the supplied provider data, * allowing `session.sandboxRef({ portable: true })` to round-trip the * sandbox through `attachSandbox(serialized)` in another process. * The matching decoder must be registered via `registerSandboxRefDecoder`. */ encodeRef?: () => { provider: string; providerData: unknown; }; } /** * Wrap a provider-owned remote sandbox client in Fabric's SandboxEnv contract. * Provider credentials and SDK objects remain outside model context/history; * Fabric only sees the narrow file/shell/snapshot API exposed here. */ export declare function createRemoteSandboxEnv(api: RemoteSandboxApi, options?: RemoteSandboxOptions): SandboxEnv; /** * Return a view of a sandbox with a narrower default cwd. Relative file paths * and shell cwd values are resolved from this scoped cwd while the underlying * sandbox still enforces its workspace boundary. */ export declare function createScopedSandboxEnv(sandbox: SandboxEnv, cwd?: string): SandboxEnv; /** * Adapter expectations: * - Every backend must expose the SandboxEnv contract above and map paths into a scoped workspace. * - Secrets and provider credentials must stay in adapter-owned environment/config, not model context. * - exec should enforce backend-specific command, network, and timeout policy before process launch. * - snapshot/restore is optional because not all targets support filesystem or VM snapshots. * - Future adapters should be added without changing session/runtime code. * * Planned backends: local, Docker, Azure Container Apps, Azure Container Instances, AKS, * Databricks, E2B, Daytona, Cloudflare, Modal, Kubernetes, and Firecracker/microVM. */ export interface SandboxAdapterDescriptor { backend: SandboxBackend; create: SandboxFactory; supportsSnapshots?: boolean; supportsExec?: boolean; supportsBinaryFiles?: boolean; } export declare class EmptySandboxEnv implements SandboxEnv { readonly cwd: string; readonly capabilities: SandboxCapabilities; private fs; private bash; constructor(cwd?: string); exec(command: string, options?: SandboxExecOptions): Promise; readFile(filePath: string): Promise; readFileBuffer(filePath: string): Promise; writeFile(filePath: string, content: string | Uint8Array): Promise; stat(filePath: string): Promise; readdir(dirPath: string): Promise; exists(filePath: string): Promise; mkdir(dirPath: string, options?: { recursive?: boolean; }): Promise; rm(filePath: string, options?: { recursive?: boolean; force?: boolean; }): Promise; resolvePath(filePath: string): string; snapshot(): Promise; restore(snapshot: SandboxSnapshot): Promise; fork(snapshot: SandboxSnapshot): Promise; cleanup(): Promise; private captureEntries; } export declare const VirtualSandboxEnv: typeof EmptySandboxEnv; export interface LocalSandboxOptions { workspacePath?: string; env?: Record; /** Names of host process environment variables to forward into local commands. */ envAllowlist?: string[]; /** Forward a small non-secret set of useful host env vars. Defaults to true. */ inheritSafeEnv?: boolean; outputLimitBytes?: number; defaultTimeoutMs?: number; sessionId?: string; snapshotRoot?: string; } export interface DockerSandboxOptions { workspacePath: string; image?: string; env?: Record; network?: 'none' | 'bridge' | 'host' | string | boolean; /** * Assert that a named Docker network is `--internal` and routes outbound * traffic only through an independently enforced egress proxy. Ignored for * `network=none`, which is already enforced by Docker. */ networkBoundary?: { enforcement: 'container'; reference: string; }; user?: string; cpus?: string | number; memory?: string; pidsLimit?: number; readOnlyRootFilesystem?: boolean; mountReadOnly?: boolean; outputLimitBytes?: number; /** Names of host process environment variables to forward into containers. */ envAllowlist?: string[]; ownsWorkspace?: boolean; sessionId?: string; snapshotRoot?: string; } export declare class LocalSandboxEnv implements SandboxEnv { readonly cwd: string; readonly capabilities: SandboxCapabilities; private readonly env; private readonly snapshotRoot; private readonly outputLimitBytes; private readonly defaultTimeoutMs?; constructor(options?: LocalSandboxOptions); exec(command: string, options?: SandboxExecOptions): Promise; readFile(filePath: string): Promise; readFileBuffer(filePath: string): Promise; writeFile(filePath: string, content: string | Uint8Array): Promise; stat(filePath: string): Promise; readdir(dirPath: string): Promise; exists(filePath: string): Promise; mkdir(dirPath: string, options?: { recursive?: boolean; }): Promise; rm(filePath: string, options?: { recursive?: boolean; force?: boolean; }): Promise; resolvePath(filePath: string): string; private resolveExistingPath; private resolveWritablePath; private nearestExistingParent; private assertInsideWorkspace; snapshot(): Promise; restore(snapshot: SandboxSnapshot): Promise; fork(snapshot: SandboxSnapshot): Promise; cleanup(): Promise; } export declare class DockerSandboxEnv implements SandboxEnv { readonly cwd = "/workspace"; readonly capabilities: SandboxCapabilities; private readonly hostWorkspacePath; private readonly image; private readonly env; private readonly network; private readonly user?; private readonly cpus?; private readonly memory?; private readonly pidsLimit?; private readonly readOnlyRootFilesystem; private readonly mountReadOnly; private readonly outputLimitBytes; private readonly ownsWorkspace; private readonly snapshotRoot; constructor(options: DockerSandboxOptions); exec(command: string, options?: SandboxExecOptions): Promise; readFile(filePath: string): Promise; readFileBuffer(filePath: string): Promise; writeFile(filePath: string, content: string | Uint8Array): Promise; stat(filePath: string): Promise; readdir(dirPath: string): Promise; exists(filePath: string): Promise; mkdir(dirPath: string, options?: { recursive?: boolean; }): Promise; rm(filePath: string, options?: { recursive?: boolean; force?: boolean; }): Promise; resolvePath(filePath: string): string; snapshot(): Promise; restore(snapshot: SandboxSnapshot): Promise; fork(snapshot: SandboxSnapshot): Promise; cleanup(): Promise; private toContainerPath; private toWorkspaceRelativePath; } export declare function pruneSnapshots(snapshotRoot: string, options?: SnapshotPruneOptions): Promise; export declare class UnimplementedSandboxEnv extends EmptySandboxEnv { exec(command: string): Promise; } export declare function createSandboxEnv(options?: SandboxFactoryOptions): Promise; //# sourceMappingURL=sandbox.d.ts.map