/** * Workspaces: where an agent's files live, apart from where its code runs. * * A `Workspace` reads, writes, and lists files, and optionally searches them, removes them, and * holds bytes. The package ships five: in memory, on disk, in a long-term `Store` (memory, Redis, * Postgres, or SQLite), read-only over another, and a composite that mounts several at paths of its * own. A `Sandbox` is a workspace that can also run commands, and says how it is isolated, so one * can be given wherever a workspace goes, or mounted in a composite beside the others. */ import type { Store, StoreNamespace } from '../types/store.js'; import type { ToolDefinition } from '../types/messages.js'; /** Options for `Workspace.glob()`. */ export interface WorkspaceGlobOptions { /** The directory to search, inside the workspace. Defaults to its root. */ cwd?: string; /** The most paths returned. Defaults to 1,000. */ limit?: number; } /** Options for `Workspace.grep()`. */ export interface WorkspaceGrepOptions { /** The directory to search, inside the workspace. Defaults to its root. */ cwd?: string; /** Searches only the files whose paths, relative to `cwd`, match this glob. */ glob?: string; /** Matches without regard to case. */ ignoreCase?: boolean; /** The most matching lines returned. Defaults to 200. */ limit?: number; } /** One line `Workspace.grep()` matched. */ export interface WorkspaceMatch { /** The file, relative to the workspace's root. */ file: string; /** The line's number, counting from 1. */ line: number; /** The line, cut to 300 characters. */ text: string; } /** * Where an agent's files live. Paths are relative to the workspace's root, with `/` between * segments; a leading `/` names the root, and a path that would leave it is refused with a * `WorkspacePathError`. Reading a file that does not exist rejects with an error whose `code` is * `ENOENT`. Every method reports a failure by rejecting, never by throwing. */ export interface Workspace { /** Names the workspace in reports. */ readonly name: string; /** Reads a text file. */ readFile(file: string): Promise; /** Writes a text file, creating its directory. */ writeFile(file: string, content: string): Promise; /** Lists a directory's entries, files and directories, by name, sorted. */ listFiles?(directory?: string): Promise; /** Removes a file, or a directory and everything in it. */ removeFile?(file: string): Promise; /** * The files under a directory whose paths match a glob, such as `src/**\/*.ts`, sorted. The glob * matches paths relative to `cwd`; the paths returned are relative to the root, as `readFile` * takes them. Returns at most `limit`. */ glob?(pattern: string, options?: WorkspaceGlobOptions): Promise; /** * The lines matching a regular expression in the files under a directory, at most `limit`. Files * over 1 MB and binary files are skipped. */ grep?(pattern: string, options?: WorkspaceGrepOptions): Promise; /** Reads a file's bytes, for an image, audio, or a document. */ readBytes?(file: string): Promise; /** Writes a file's bytes, creating its directory. */ writeBytes?(file: string, bytes: Uint8Array): Promise; } /** Raised when a path would leave the workspace, or lies under no mount of a composite. */ export declare class WorkspacePathError extends Error { /** The path that was refused. */ readonly path: string; /** `WORKSPACE_PATH`, or `SANDBOX_PATH` from a sandbox. */ readonly code: string; constructor( /** The path that was refused. */ path: string, message?: string); } /** Raised when a read-only workspace, or a read-only mount of a composite, is written to. */ export declare class WorkspaceReadOnlyError extends Error { /** The path that was written to. */ readonly path: string; /** Always `WORKSPACE_READ_ONLY`. */ readonly code = "WORKSPACE_READ_ONLY"; constructor( /** The path that was written to. */ path: string); } /** * A path as a workspace holds it: relative to the root, `/` between segments, without `.` or `..`. * The root is `''`. A path that would leave the root is refused with a `WorkspacePathError`. For a * workspace of your own, so its paths mean what every other's do. */ export declare function resolveWorkspacePath(path: string): string; /** Options for `memoryWorkspace()`. */ export interface MemoryWorkspaceOptions { /** Names it in reports. Defaults to `memory`. */ name?: string; /** Files it starts with, by path: text, or bytes. */ files?: Record; } /** * A workspace in this process's memory: for tests, for scratch work, and for a run whose files need * not outlive it. Every method, search included; directories exist while a file is under them. */ export declare function memoryWorkspace(options?: MemoryWorkspaceOptions): Workspace; /** Options for `fileWorkspace()`. */ export interface FileWorkspaceOptions { /** The directory the files live under. Created when missing. */ root: string; /** Names it in reports. Defaults to `files`. */ name?: string; } /** * A directory on disk as a workspace, on Node. Every path stays under `root`, and its search skips * `.git` and `node_modules`, walks at most 20,000 entries, and follows no links. It runs nothing: a * workspace holds files, a sandbox runs code. */ export declare function fileWorkspace(options: FileWorkspaceOptions): Workspace; /** Options for `storeWorkspace()`. */ export interface StoreWorkspaceOptions { /** Where its files are kept in the store. Defaults to `['nexus', 'workspace']`. */ namespace?: StoreNamespace; /** Names it in reports. Defaults to `store`. */ name?: string; } /** * A workspace in a long-term `Store`: the memory, Redis, Postgres, or SQLite store, so an agent's * files outlive its process and every replica sees the same ones. Each file is two items: its * contents, and a small entry in a tree, so listing and searching read entries, not contents. Files * are never indexed for semantic search. * * A write stores the contents before the entry, so a process that stops between the two leaves a * file that reads but is not listed, until it is written again. */ export declare function storeWorkspace(store: Store, options?: StoreWorkspaceOptions): Workspace; /** A workspace that reads another and refuses every write with a `WorkspaceReadOnlyError`. */ export declare function readOnlyWorkspace(workspace: Workspace): Workspace; /** One mount of a composite workspace: a workspace, read-only or not. */ export interface WorkspaceMount { /** The workspace mounted. */ workspace: Workspace; /** Refuses writes to it through the composite. */ readOnly?: boolean; } /** Options for `compositeWorkspace()`. */ export interface CompositeWorkspaceOptions { /** Names it in reports. Defaults to `composite`. */ name?: string; } /** * Several workspaces as one, each mounted at a path: a sandbox at the root for the code, a store at * `memories` for what outlives the run, read-only docs at `docs`. A path goes to the deepest mount it * is under, as that mount's own path; a listing shows the mounts below a directory as directories; * search spans every mount under the directory searched, and a mount without `glob` is left out of * it. A path under no mount is refused, so a composite without a root mount has only its mounts. * * ```ts * const workspace = compositeWorkspace({ * '/': sandbox, * memories: storeWorkspace(store, { namespace: ['agents', tenantId] }), * docs: { workspace: fileWorkspace({ root: './docs' }), readOnly: true }, * }); * ``` */ export declare function compositeWorkspace(mounts: Record, options?: CompositeWorkspaceOptions): Workspace; /** Options for `workspaceTools()`. */ export interface WorkspaceToolsOptions { /** The largest file `read_media` sends to the model, in bytes. Defaults to 10 MB. */ maxMediaBytes?: number; /** * The path a permission policy sees the workspace's files under. Defaults to `/workspace`, so a * policy granting `/workspace/**` grants the workspace. */ mount?: string; } /** * The file tools over a workspace: `read_file` and `write_file`, and, where the workspace can, * `list_files`, `glob_files`, `grep_files`, and `read_media`. Each declares `filesystem:read` or * `filesystem:write` with the path under `mount`, so a permission policy can grant the workspace, * or part of it, and nothing else. */ export declare function workspaceTools(workspace: Workspace, options?: WorkspaceToolsOptions): ToolDefinition[]; /** One conformance check's result. */ export interface WorkspaceConformanceCheck { /** What was checked. */ name: string; /** Whether it held. */ ok: boolean; /** What went wrong, when it did not. */ detail?: string; } /** What `runWorkspaceConformance()` found. */ export interface WorkspaceConformanceReport { /** The workspace's name. */ workspace: string; /** True when every check held. */ passed: boolean; /** Every check, in order. A method the workspace does not have is not checked. */ checks: WorkspaceConformanceCheck[]; } /** * Checks a workspace against the contract, without a test framework, so any workspace (a bucket, a * database, a hosted file service) can prove itself the same way: * * - text files round-trip, are replaced when written again, and directories are created for them; * - a missing file is refused with `ENOENT`, and a path that would leave the workspace is refused; * - a listing names a directory's files and directories, sorted; * - glob matches paths relative to its directory, sorted, within its limit; * - grep finds lines by number, within a glob, without regard to case when asked, within its limit, * skipping binary files; * - bytes round-trip, and a text file reads as its bytes; * - a file, and a directory with everything in it, are removed. * * Every check runs on a fresh workspace from `create`. */ export declare function runWorkspaceConformance(create: () => Workspace | Promise): Promise;