/** * The turn's workspace tools over a filesystem that exists for this turn only. * * GUEST code, bundled with the agent entry, so it must stay portable: no * `node:` import, no host module, no root `@lobu/core` import (that root drags * the Node logger and tracing SDKs). The local shell is just-bash's browser * build, without real binaries or network access. Write and edit use Pi's own * factories with filesystem operations, as do read, ls and find. Pi also owns * output truncation; the bundler excludes unused Node I/O and renderers. Grep * stays local because Pi's grep always starts an rg process. * * The filesystem is in-memory and lives for one turn only. It starts empty * except for what the HOST seeds into it before the model runs — this turn's * non-image attachments under `input/` and the agent's enabled skills under * `.skills/`, the two established agent-visible locations. Nothing * written here outlives the turn, and nothing here can reach the network: the * shell is built without `fetch`, so `curl` and `wget` do not exist in it. */ import type { AgentTool } from '@mariozechner/pi-agent-core'; import { InMemoryFs } from 'just-bash/browser'; import type { AgentTurnBashPolicy, AgentTurnBuiltinTool, RuntimeExecRequest, RuntimeExecResult } from './types.js'; /** Where a turn's files live; also the shell's working directory. */ export declare const WORKSPACE_ROOT = "/workspace"; /** * Total bytes the write and edit tools may place in one turn's workspace: an * eighth of the isolate's default 512MB heap, and far above a real turn's * files (the largest session transcript measured across 2050 real rows is * 633KB, `gateway/services/transcript-snapshot.ts`). A runaway write then * refuses with an error the model can act on, instead of an OOM that kills * the whole turn. */ export declare const WORKSPACE_WRITE_BUDGET_BYTES: number; /** * Where the turn's own attachments are seeded. The name is part of the * agent-visible contract: the system prompt lists each upload by this path. */ export declare const INPUT_DIR = "/workspace/input"; /** * Where the agent's enabled skills are seeded, one `SKILL.md` per skill. */ export declare const SKILLS_DIR = "/workspace/.skills"; /** * One file the HOST places in the turn's filesystem before the model runs. * * The guest never fetches: the gateway reads an attachment out of the artifact * store it already owns, and a skill straight out of agent settings, then hands * the bytes over the same signed envelope as everything else. `data` is base64 * so arbitrary bytes survive the JSON hop intact; `text` is the convenience for * content that is already a string, and exactly one of the two is given. */ export type WorkspaceSeedFile = { path: string; data: string; text?: never; } | { path: string; text: string; data?: never; }; /** * The turn's filesystem, and the tools that act on it. * * Returned together because more than the file tools need the FS: `upload_file` * reads the very same in-memory tree, so the workspace the model wrote with * `bash` is the workspace it can hand to the user. Handing out the `InMemoryFs` * is what keeps that one filesystem, rather than giving the media port a second * one that would always look empty. */ export interface AgentWorkspace { /** The turn's filesystem: seeded by the host, gone at the end of the turn. */ fs: InMemoryFs; /** Resolved once the root directory exists; every tool awaits it first. */ ready: Promise; tools: AgentTool[]; /** * Write host-supplied files into the turn's tree before the model runs. * * Containment goes through the SAME `resolve` the file tools use, so a * traversing path is refused here for the reason it is refused there rather * than by a second check that could drift. Throws on the first bad path and * writes nothing further, because a partially seeded workspace would tell the * model a file exists when its sibling silently did not. */ seed(files: readonly WorkspaceSeedFile[]): Promise; /** * Resolve a model-supplied path inside the workspace root, or throw. * Exported so a non-file tool that takes a path — `upload_file` — enforces * containment through the SAME check the file tools do, rather than a second * implementation that could drift from it. */ resolve(path: string | undefined): string; } /** How the host runs one command in the remote runtime sandbox. */ export interface RemoteRuntime { exec(request: RuntimeExecRequest): Promise; } /** * Build the workspace tools the turn admits, over one fresh filesystem. The * local shell and every file tool share it, so what local `bash` writes `read` * sees. A supplied remote runtime replaces only `bash`; file tools remain on * this in-memory filesystem. */ export declare function createWorkspace(names: readonly AgentTurnBuiltinTool[], bashPolicy?: AgentTurnBashPolicy, remote?: RemoteRuntime): AgentWorkspace; //# sourceMappingURL=workspace.d.ts.map