UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

152 lines • 7.52 kB
import { type Files } from '../files.ts'; import type { Decisions } from '../../policy/decisions.ts'; import type { MountEntry } from '../mount/mount.ts'; import type { SessionState } from '../session/session.ts'; import type { ExecuteResult, SessionExecuteOptions } from '../workspace/types.ts'; import { FileVersionTracker } from './file_version.ts'; import { type WorkspaceMediaRead } from './read_file.ts'; export interface ToolResult { [key: string]: unknown; content: { type: 'text'; text: string; }[]; isError?: boolean; } /** What a tool table acts through: one session's entry points (`Session`). */ export interface SessionLike { readonly sessionId: string; readonly state: SessionState; readonly decisions: Decisions; readonly vfs: Files; mounts(): readonly MountEntry[]; shell(command: string, options?: SessionExecuteOptions): Promise<ExecuteResult>; glob(pattern: string): Promise<string[]>; loaded(): Promise<void>; reads(): Promise<FileVersionTracker>; } /** What an adapter takes to pick a session's tool table. */ export interface MirageToolOperationsOptions { staleWriteProtection?: boolean; /** * The session the tools act as, with its cwd, environment and mount * grants; the workspace's default session when absent. */ sessionId?: string; } export declare function ensureParents(vfs: Files, path: string): Promise<void>; /** Every tool, in the order the entry points list them. */ export declare const TOOL_NAMES: readonly ["shell", "read", "write", "edit", "ls", "grep", "glob"]; /** * Whether a session may write anywhere: a mount it can see whose mode, * narrowed by the profile or opened by a show entry below it, reaches * write. `/dev` is left out: its null sink takes a write from anyone and * stores nothing. Mirrors Python's `writes`. */ export declare function writes(session: SessionState, mounts: readonly MountEntry[]): boolean; /** * The agent tools for one session, independent of any agent framework. * `session.tools` is the session's own table. Every guarded table of a * session shares the session's read history, so a read through one * guards a write through another. Build one directly only to turn the * guard off. */ export declare class MirageToolOperations { private readonly session; private readonly own; /** * @param session The session the tools act as, with its cwd, * environment and mount grants. * @param staleWriteProtection False lets an agent overwrite a file that * changed since it read it. */ constructor(session: SessionLike, staleWriteProtection?: boolean); /** * The read history this call uses: the session's, which every guarded * table of the session shares, or this table's own when the guard is * off. A call keeps the one it started with, so a restore during the * call cannot mix two histories. */ private versions; /** * The tools this session can use, in the order the entry points list them. * Read off the session's profile, so no entry point offers a tool every call * of which would be refused: `shell` needs a command the allow list * installs, `ls` and `grep` run those commands and need them, and * `write` and `edit` need somewhere the session may write. `read` and * `glob` are always offered; what they cannot reach answers as the * error it is. A session not loaded yet (a stored one before its first * call) is offered every tool, since its profile is not known here; the * policies still judge each call, and `offered` loads it first. Mirrors * Python's `names`. */ names(): readonly string[]; /** * The tools this session can use, its sessions loaded first, so a stored * session answers with its own profile: what an async entry point lists and * calls by. Mirrors Python's `offered`. */ offered(): Promise<readonly string[]>; private lineOptions; /** Run a line in the session's shell; `signal` aborts it, as in-app. */ shell(command: string, signal?: AbortSignal): Promise<ToolResult>; /** Read a file as line-numbered text; a relative path is taken under the session's cwd, spelled as given. */ read(given: string, offset?: number, limit?: number): Promise<ToolResult>; /** * Read a file for an entry point that hands media to the model, in one fetch: * an image or a PDF comes back as media and counts as seen in full; * anything else is the `read` answer for the same bytes. Either way * the file is stamped for a later edit. */ readMedia(given: string, offset?: number, limit?: number): Promise<ToolResult | WorkspaceMediaRead>; private readFailure; private numbered; /** * Write a file; an existing one must have been read in full first. A * new file is created with its missing parents. An existing one is * overwritten only when the agent was shown all of it and it did not * change since, so a write never clobbers text the agent has not seen. A * relative path is taken under the session's cwd, spelled as given. */ write(given: string, content: string): Promise<ToolResult>; /** Replace a string in an existing file; a relative path is taken under the session's cwd, spelled as given. */ edit(given: string, oldString: string, newString: string, replaceAll?: boolean): Promise<ToolResult>; ls(path: string, signal?: AbortSignal): Promise<ToolResult>; /** * Search recursively for a pattern, as `grep -rn` does. Each option is * the GNU grep flag of the same name, and the line runs in the * session's shell, so the search is the shell's own: the same policy, * push-down and history as typing it. grep exits 1 when nothing * matched, an empty answer rather than a failure, so only an exit above * 1 (a bad regex, an unreadable path) is a tool error. */ grep(pattern: string, path: string, options?: { ignoreCase?: boolean | undefined; fixedStrings?: boolean | undefined; include?: string | undefined; context?: number | undefined; filesWithMatches?: boolean | undefined; count?: boolean | undefined; maxCount?: number | undefined; }, signal?: AbortSignal): Promise<ToolResult>; /** * Find files, not directories, whose path matches a pattern. The * pattern is expanded by `Session.glob`, the shell's own resolver: * `**` matches any number of directories, and a relative pattern is * matched under `path`. A symlink to a file counts; a dangling one does * not, nor does a match the workspace refuses to stat, since nothing * says what it is. Any other failure propagates rather than pass for a * short list. */ glob(pattern: string, path?: string): Promise<ToolResult>; /** * Run one tool by name with its JSON input. The one entry every entry point * shares: MCP, the HTTP routes, the CLI and the agent adapters hand a * tool's name and its input, as the tool's `*_INPUT` schema reads it, * to this method, so each tool answers the same way through each of * them. Throws for a name no tool has, or one the session's profile does * not offer (`offered`). Mirrors Python's `call`. */ call(name: string, args: Readonly<Record<string, unknown>>, signal?: AbortSignal): Promise<ToolResult>; } //# sourceMappingURL=tool_operations.d.ts.map