Skip to content

feat: add Workspace class — persistent virtual filesystem for Agents#1069

Merged
threepointone merged 9 commits intomainfrom
workspace-mixin
Mar 5, 2026
Merged

feat: add Workspace class — persistent virtual filesystem for Agents#1069
threepointone merged 9 commits intomainfrom
workspace-mixin

Conversation

@threepointone
Copy link
Contributor

Summary

Adds the Workspace class to agents/experimental/workspace — a persistent virtual filesystem backed by Durable Object SQLite with optional R2 spillover for large files.

This PR includes the full implementation, comprehensive tests, a design document, and an interactive demo.


What is included

1. Workspace class (packages/agents/src/experimental/workspace.ts)

A complete virtual filesystem that any Agent can attach:

import { Workspace } from "agents/experimental/workspace";

class MyAgent extends Agent {
  workspace = new Workspace(this, { namespace: "ws" });
}

Filesystem operations:

  • readFile, writeFile, deleteFile, rename
  • readDir, mkdir, stat, lstat, exists
  • glob (picomatch-based pattern matching)
  • symlink, readlink
  • getWorkspaceInfo (aggregate stats)

Storage model:

  • Files <= 1 MB stored inline in SQLite (single round-trip reads)
  • Files > 1 MB spill to R2 automatically (transparent to callers)
  • Namespace isolation — multiple workspaces per DO, no table collisions

Bash execution:

  • bash(command, { cwd }) — run shell commands via just-bash (pure JS bash interpreter)
  • Custom commands, environment variables, and network config
  • Observability events (workspace:bash) emitted for every execution

2. BashSession — persistent shell sessions

const session = workspace.createBashSession({ cwd: "/project" });
await session.exec("npm init -y");
await session.exec("mkdir src && echo \"hello\" > src/index.ts");
console.log(session.cwd);  // "/project"
console.log(session.env);  // includes all shell variables
session.close();
  • cwd and env persist across exec() calls
  • State captured via stdout-based sentinels (no filesystem side-effects)
  • Multiple independent sessions share the same filesystem
  • isClosed getter, Symbol.dispose support

3. Tests (packages/agents/src/tests/workspace.test.ts)

29 tests covering:

  • Filesystem: readFile, writeFile, deleteFile, rename, readDir, mkdir, stat, exists, glob, symlinks, large file R2 spillover, namespace isolation, workspace info, change events
  • Bash: echo/stdout, exit codes, file manipulation, env vars, custom commands, workspace-level commands, cwd option
  • BashSession (15 tests): cwd persistence, env persistence, initial cwd/env, independent sessions, shared filesystem, session reuse, variable persistence, multi-step workflows, exit code preservation, stderr pass-through, empty stdout, early exit state preservation, isClosed lifecycle, observability events

4. Design document (design/workspace.md)

Covers: storage model, namespace isolation, symlinks, change events, observability, bash execution, bash sessions, streaming I/O, security boundaries, key decisions, tradeoffs, and testing strategy.

5. Experimental demo (experimental/workspace-chat/)

An interactive AIChatAgent + Workspace example:

  • Server: AIChatAgent with 7 tools — readFile, writeFile, listDirectory, deleteFile, mkdir, bash, glob
  • Client: Chat UI with a file browser sidebar (clickable files show content), auto-refresh after AI actions, reasoning trace rendering, Streamdown markdown
  • Each browser gets its own agent instance (UUID persisted in localStorage)
  • Model: @cf/zai-org/glm-4.7-flash via Workers AI

API surface

New export: agents/experimental/workspace

Export Type Description
Workspace class Main filesystem class
BashSession class Persistent shell session
BashOptions type Options for bash/createBashSession
BashResult type bash() return type
FileInfo type File/directory entry metadata
FileStat type Detailed file stats
WorkspaceChangeEvent type Change event payload
WorkspaceOptions type Constructor options
WorkspaceHost interface Host requirements
defineCommand function Helper for custom bash commands

Changeset

Included in .changeset/workspace-class.md — minor bump for agents package.

Add just-bash as a dependency in packages/agents and refine the fiber mixin typings. Introduce a FiberAgentClass generic constructor return type so consumers extending the mixin retain FiberMethods on `this`, broaden spawnFiber's methodName to string, export FiberMethods for external use, and add several internal tracking properties to the interface. Update a test to pass a string methodName accordingly.
Introduce a new Workspace class that provides durable hybrid file storage (SQLite inline + optional R2 for large files) and optional bash execution. Replaces the previous withWorkspace mixin pattern with a class-based API (usage: new Workspace(this, { namespace, r2, r2Prefix, inlineThreshold, bashLimits })). The Workspace includes namespace validation, per-host registration to avoid duplicate namespaces, a scoped SQL helper, lazy table initialization, and R2 key prefixing.

Add TestWorkspaceAgent exposing workspace operations, a comprehensive vitest suite (workspace.test.ts) covering file I/O, dirs, rm, listing, path normalization and bash integration, and wire the agent into the test worker and wrangler config. Add just-bash as a dependency in package.json and include it in the test runtime config. Update changelog (.changeset) to document the new Workspace class.
Introduce a new Workspace class providing durable file storage for Agents with a hybrid SQLite+R2 backend and optional just-bash execution (usage: new Workspace(this, { r2, r2Prefix })). Update package exports, tests, and workspace implementation to use the new API (idPrefix renamed to r2Prefix). Also update package metadata and regenerate package-lock.json to reflect dependency changes and added example entries.
Introduce an experimental Workspace virtual filesystem (hybrid SQLite+R2) under agents/experimental/workspace with BashSession, persistent cwd/env sessions, streaming I/O, symlinks, change events, and diagnostics/observability hooks. Add design documentation (design/workspace.md) and register it in design indices. Add a workspace-chat example (frontend, server, configs, vite/wrangler, types) demonstrating AIChatAgent integration and tools (read/write/list/mkdir/bash/glob). Expose the workspace API under the package exports as ./experimental/workspace, add observability helpers and tests updates, and make a small example model comment tweak in the OpenAI SDK sample.
@changeset-bot
Copy link

changeset-bot bot commented Mar 5, 2026

🦋 Changeset detected

Latest commit: 6157447

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Add a STORAGE_KEY and getUserId() helper that retrieves a persisted UUID from localStorage (or generates one with crypto.randomUUID() and stores it). Fall back to "default" when window is undefined. Use the returned ID as the agent name when initializing the WorkspaceChatAgent so the client retains a stable identifier across sessions.
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 5, 2026

Open in StackBlitz

npm i https://pkg.pr.new/agents@1069
npm i https://pkg.pr.new/@cloudflare/ai-chat@1069
npm i https://pkg.pr.new/@cloudflare/codemode@1069
npm i https://pkg.pr.new/hono-agents@1069

commit: 1fd1675

Introduce a minimal TurndownService stub (remove and turndown methods) at experimental/workspace-chat/src/turndown-stub.ts and update vite.config.ts to import node:path and alias 'turndown' to the stub. This avoids pulling in the real turndown package for the workspace-chat experiment during bundling.
@threepointone threepointone merged commit b5238de into main Mar 5, 2026
3 checks passed
@threepointone threepointone deleted the workspace-mixin branch March 5, 2026 11:41
@github-actions github-actions bot mentioned this pull request Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant