Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/calm-computers-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@cloudflare/think": minor
---

Add an opt-in `@cloudflare/think/experimental/computer` integration using
Computer's `useThink` compatibility surface. Locally owned Computers are
assigned directly to `this.workspace`; remote `getWorkspace()` clients use the
same upstream compatibility methods. Think's default `@cloudflare/shell`
workspace, direct `this.workspace` methods, stored data, and `just-bash` tool
remain unchanged. The experimental Computer uses separate storage and does not
migrate legacy workspace data.
30 changes: 16 additions & 14 deletions docs/think/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1283,20 +1283,21 @@ Think's `this.messages` getter reads directly from Session's tree-structured sto

## Package Exports

| Export | Description |
| --------------------------------------- | ------------------------------------------------------------- |
| `@cloudflare/think` | `Think`, `Session`, `Workspace`, `skills` namespace |
| `@cloudflare/think/framework` | Framework manifest discovery and Worker config helpers |
| `@cloudflare/think/server-entry` | Framework Worker entry helpers for custom server handlers |
| `@cloudflare/think/messengers` | Messenger contracts, Chat SDK bridge, state agent, delivery |
| `@cloudflare/think/messengers/telegram` | Telegram messenger provider and delivery helpers |
| `@cloudflare/think/workflows` | `ThinkWorkflow`, `step.prompt()` — Workflow prompts |
| `@cloudflare/think/tools/workspace` | `createWorkspaceTools()` — for custom storage backends |
| `@cloudflare/think/tools/fetch` | `createFetchTools()` — opt-in allowlisted HTTP reads |
| `@cloudflare/think/tools/execute` | `createExecuteTool()` — sandboxed code execution via codemode |
| `@cloudflare/think/tools/extensions` | `createExtensionTools()` — LLM-driven extension loading |
| `@cloudflare/think/extensions` | `ExtensionManager`, `HostBridgeLoopback` — extension runtime |
| `@cloudflare/think/vite` | Think Vite plugin and generated Worker config helpers |
| Export | Description |
| ----------------------------------------- | ------------------------------------------------------------- |
| `@cloudflare/think` | `Think`, `Session`, `Workspace`, `skills` namespace |
| `@cloudflare/think/framework` | Framework manifest discovery and Worker config helpers |
| `@cloudflare/think/server-entry` | Framework Worker entry helpers for custom server handlers |
| `@cloudflare/think/messengers` | Messenger contracts, Chat SDK bridge, state agent, delivery |
| `@cloudflare/think/messengers/telegram` | Telegram messenger provider and delivery helpers |
| `@cloudflare/think/experimental/computer` | Opt-in `@cloudflare/computer` workspace integration |
| `@cloudflare/think/workflows` | `ThinkWorkflow`, `step.prompt()` — Workflow prompts |
| `@cloudflare/think/tools/workspace` | `createWorkspaceTools()` — for custom storage backends |
| `@cloudflare/think/tools/fetch` | `createFetchTools()` — opt-in allowlisted HTTP reads |
| `@cloudflare/think/tools/execute` | `createExecuteTool()` — sandboxed code execution via codemode |
| `@cloudflare/think/tools/extensions` | `createExtensionTools()` — LLM-driven extension loading |
| `@cloudflare/think/extensions` | `ExtensionManager`, `HostBridgeLoopback` — extension runtime |
| `@cloudflare/think/vite` | Think Vite plugin and generated Worker config helpers |

## Dependencies

Expand All @@ -1308,6 +1309,7 @@ Peer dependencies you provide:
| `ai` | yes | Vercel AI SDK v6 |
| `zod` | yes | Schema validation (v4) |
| `@chat-adapter/telegram` | optional | Required for Telegram messengers |
| `@cloudflare/computer` | optional | Experimental Computer workspace integration |
| `vite` | optional | Required for the Think Vite plugin (`/vite`) |

Bundled with `@cloudflare/think`:
Expand Down
86 changes: 86 additions & 0 deletions docs/think/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,92 @@ This requires an R2 bucket binding in `wrangler.jsonc`:
}
```

### Experimental Computer workspace

You can opt an individual Think class into the new
[`@cloudflare/computer`](https://github.com/cloudflare/computer)
implementation
without changing Think's default workspace:

```sh
npm install @cloudflare/computer
```

```typescript
import { Think } from "@cloudflare/think";
import {
createComputerWorkspace,
WorkerBackend,
WorkspaceServiceProxy
} from "@cloudflare/think/experimental/computer";

export { WorkspaceServiceProxy };

export class MyAgent extends Think<Env> {
override workspace = createComputerWorkspace({
storage: this.ctx.storage,
backends: [
new WorkerBackend({
loader: this.env.LOADER,
workspace: {
binding: "MyAgent",
id: this.ctx.id.toString()
},
ctx: this.ctx
})
]
});

getModel() {
/* ... */
}
}
```

Use `this.workspace.readFile(...)` and `this.workspace.writeFile(...)` as you
would with Think's default workspace. Computer-specific APIs are also available
through `this.workspace.shell`, `this.workspace.git`, and
`this.workspace.assets`. When a `WorkerBackend` is configured, Think's built-in
`bash` tool uses Computer shell exec instead of the legacy `just-bash` snapshot.

Add a Worker Loader binding for shell execution:

```jsonc
{
"worker_loaders": [{ "binding": "LOADER" }]
}
```

> **No data migration:** The experimental Computer stores files in separate
> `vfs_*` SQLite tables. It does not read or migrate the existing Think
> workspace stored by `@cloudflare/shell`, so an existing agent starts with an
> empty Computer workspace after opting in. The legacy files remain untouched
> and become visible again if you remove the override, but files written to the
> Computer are not visible to the legacy workspace.

`WorkspaceServiceProxy` is the Worker entrypoint used by the shell backend to
call back into the Computer owned by the Think instance. It does not own a
separate workspace.

#### API reference

| Export | Signature or behavior |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `createComputerWorkspace(options)` | Creates a locally owned Computer with `useThink: true`; returns the Computer itself |
| `LocalComputerWorkspace` | The local Computer type intersected with Think's `WorkspaceLike` |
| `adaptComputer(computer)` | Narrows a `getWorkspace()` client whose owner enabled `useThink` to Think's workspace type |
| `ComputerWorkspace` | Computer client type intersected with Think's `WorkspaceLike` |
| `Computer` | Alias for the current `Workspace` class from `@cloudflare/computer` |
| `getWorkspace()` and `withWorkspace()` | Re-exports for unified local and remote Computer clients |
| `WorkerBackend` | Worker Loader shell backend from `@cloudflare/computer/backends/worker` |
| `WorkspaceServiceProxy` | Worker entrypoint connecting the shell backend to the Think-owned Computer |
| `ComputerOptions`, `WorkspaceClient`, and Worker types | Type-only exports for constructing or adapting a Computer |

Use `createComputerWorkspace()` for a Computer owned directly by the Think
instance. Use `adaptComputer(await getWorkspace(stub))` when another Durable
Object owns the Computer. The owning Computer must set `useThink: true`;
`getWorkspace()` then installs the same compatibility methods on its client.

## Custom Tools

Override `getTools()` to add your own tools. These are standard AI SDK `tool()` definitions with Zod schemas:
Expand Down
74 changes: 61 additions & 13 deletions packages/think/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,52 @@ export class MyAgent extends Think<Env> {
}
```

### Experimental Computer workspace

To try the new `@cloudflare/computer` implementation without changing the
default for other Think agents, install the experimental peer:

```sh
npm install @cloudflare/computer
```

```ts
import {
createComputerWorkspace,
WorkerBackend,
WorkspaceServiceProxy
} from "@cloudflare/think/experimental/computer";

export { WorkspaceServiceProxy };

export class MyAgent extends Think<Env> {
override workspace = createComputerWorkspace({
storage: this.ctx.storage,
backends: [
new WorkerBackend({
loader: this.env.LOADER,
workspace: {
binding: "MyAgent",
id: this.ctx.id.toString()
},
ctx: this.ctx
})
]
});
}
```

Computer's `useThink` compatibility keeps the existing direct interface
(`this.workspace.readFile(...)`). `createComputerWorkspace()` returns the
Computer itself, so native surfaces such as `this.workspace.fs`,
`this.workspace.shell`, and `this.workspace.git` remain available. Think uses
Computer shell exec for the built-in `bash` tool.

> **No data migration:** opting in starts a separate, empty Computer workspace.
> Existing legacy workspace files remain untouched but are not visible through
> the experimental Computer. Files written through the Computer are likewise not
> visible if you switch back.

## Agent Skills

Think supports the [Agent Skills](https://agentskills.io/) directory format as
Expand Down Expand Up @@ -315,19 +361,20 @@ Script execution requires a Worker Loader binding:

## Exports

| Export | Description |
| --------------------------------------- | ------------------------------------------------------------- |
| `@cloudflare/think` | `Think`, `Session`, `Workspace` — main class + re-exports |
| `@cloudflare/think/framework` | Framework manifest discovery and Worker config helpers |
| `@cloudflare/think/server-entry` | Framework Worker entry helpers for custom server handlers |
| `@cloudflare/think/messengers` | Messenger contracts, Chat SDK bridge, state agent, delivery |
| `@cloudflare/think/messengers/telegram` | Telegram messenger provider and delivery helpers |
| `@cloudflare/think/tools/workspace` | `createWorkspaceTools()` — for custom storage backends |
| `@cloudflare/think/tools/fetch` | `createFetchTools()` — opt-in allowlisted HTTP reads |
| `@cloudflare/think/tools/execute` | `createExecuteTool()` — sandboxed code execution via codemode |
| `@cloudflare/think/tools/extensions` | `createExtensionTools()` — LLM-driven extension loading |
| `@cloudflare/think/extensions` | `ExtensionManager`, `HostBridgeLoopback` — extension runtime |
| `@cloudflare/think/vite` | Think Vite plugin and generated Worker config helpers |
| Export | Description |
| ----------------------------------------- | ------------------------------------------------------------- |
| `@cloudflare/think` | `Think`, `Session`, `Workspace` — main class + re-exports |
| `@cloudflare/think/framework` | Framework manifest discovery and Worker config helpers |
| `@cloudflare/think/server-entry` | Framework Worker entry helpers for custom server handlers |
| `@cloudflare/think/messengers` | Messenger contracts, Chat SDK bridge, state agent, delivery |
| `@cloudflare/think/messengers/telegram` | Telegram messenger provider and delivery helpers |
| `@cloudflare/think/experimental/computer` | Opt-in `@cloudflare/computer` compatibility adapter |
| `@cloudflare/think/tools/workspace` | `createWorkspaceTools()` — for custom storage backends |
| `@cloudflare/think/tools/fetch` | `createFetchTools()` — opt-in allowlisted HTTP reads |
| `@cloudflare/think/tools/execute` | `createExecuteTool()` — sandboxed code execution via codemode |
| `@cloudflare/think/tools/extensions` | `createExtensionTools()` — LLM-driven extension loading |
| `@cloudflare/think/extensions` | `ExtensionManager`, `HostBridgeLoopback` — extension runtime |
| `@cloudflare/think/vite` | Think Vite plugin and generated Worker config helpers |

## Think

Expand Down Expand Up @@ -1009,6 +1056,7 @@ getTools() {
| `@cloudflare/worker-bundler` | TypeScript skill script compilation |
| `just-bash` | Bash skill script execution |
| `@chat-adapter/telegram` | Required for Telegram messengers |
| `@cloudflare/computer` | Optional experimental Computer workspace |

## Acknowledgments

Expand Down
9 changes: 9 additions & 0 deletions packages/think/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@ai-sdk/react": "^4.0.0",
"@chat-adapter/telegram": "^4.31.0",
"@cloudflare/ai-chat": "workspace:*",
"@cloudflare/computer": "https://pkg.pr.new/cloudflare/computer/@cloudflare/computer@6208b43",
"@cloudflare/kumo": "^2.6.0",
"@phosphor-icons/react": "^2.1.10",
"@streamdown/code": "^1.1.1",
Expand All @@ -62,6 +63,7 @@
"peerDependencies": {
"@ai-sdk/react": "^3.0.0 || ^4.0.0",
"@chat-adapter/telegram": "^4.29.0",
"@cloudflare/computer": ">=0.1.0-alpha.2 <0.2.0",
"agents": ">=0.18.0 <1.0.0",
"ai": "^6.0.0 || ^7.0.0",
"react": "^19.0.0",
Expand All @@ -75,6 +77,9 @@
"@chat-adapter/telegram": {
"optional": true
},
"@cloudflare/computer": {
"optional": true
},
"react": {
"optional": true
},
Expand Down Expand Up @@ -111,6 +116,10 @@
"types": "./dist/messengers/telegram.d.ts",
"import": "./dist/messengers/telegram.js"
},
"./experimental/computer": {
"types": "./dist/experimental/computer.d.ts",
"import": "./dist/experimental/computer.js"
},
"./react": {
"types": "./dist/react.d.ts",
"import": "./dist/react.js"
Expand Down
1 change: 1 addition & 0 deletions packages/think/scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ async function main() {
"src/server-entry.ts",
"src/messengers/index.ts",
"src/messengers/telegram.ts",
"src/experimental/computer.ts",
"src/tools/workspace.ts",
"src/tools/fetch.ts",
"src/tools/execute.ts",
Expand Down
72 changes: 72 additions & 0 deletions packages/think/src/experimental/computer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
Workspace as Computer,
type WorkspaceClient,
type WorkspaceOptions as ComputerOptions
} from "@cloudflare/computer";
import type { WorkspaceLike } from "../tools/workspace";

export {
getWorkspace,
WorkspaceServiceProxy,
withWorkspace
} from "@cloudflare/computer";
export { WorkerBackend } from "@cloudflare/computer/backends/worker";
export type {
WorkerBackendOptions,
WorkerShellFetcher
} from "@cloudflare/computer/backends/worker";
export type { ComputerOptions, WorkspaceClient };
export { Computer };

/**
* A locally owned Computer with Think compatibility methods enabled.
*
* This is the actual Computer instance, not an adapter. Its native `fs`,
* `shell`, `git`, `assets`, and other surfaces remain directly available.
*/
export type LocalComputerWorkspace = Computer & WorkspaceLike;
export type ComputerWorkspace = WorkspaceClient & WorkspaceLike;

/**
* Create a Think-compatible workspace backed by a locally owned Computer.
*
* @experimental There is currently no data migration path from Think's
* legacy workspace.
*/
export function createComputerWorkspace(
options: ComputerOptions
): LocalComputerWorkspace {
return new Computer({
...options,
useThink: true
}) as LocalComputerWorkspace;
}

/**
* Mark a Computer client whose owner enabled `useThink` as a Think workspace.
*
* The client already contains the compatibility methods; this function only
* narrows their optional types.
*/
export function adaptComputer(computer: WorkspaceClient): ComputerWorkspace {
// WorkspaceClient exposes these methods as optional because useThink is an
// owner-side runtime option that TypeScript cannot infer across RPC.
const methods: Array<keyof WorkspaceLike> = [
"readFile",
"readFileBytes",
"writeFile",
"readDir",
"rm",
"glob",
"mkdir",
"stat"
];
for (const method of methods) {
if (typeof computer[method] !== "function") {
throw new Error(
"Computer client is not Think-compatible. Construct its Workspace with useThink: true."
);
}
}
return computer as ComputerWorkspace;
}
Loading
Loading