Skip to content

Commit 6994224

Browse files
committed
examples/think, examples/tutorial, docs: Remove Think adapter use
Configure Think agents with the Computer AI tools and workspace.fs instead of the removed root-level compatibility methods. Replace the tutorial's bash tool with exec and update the public integration docs.
1 parent 548031a commit 6994224

5 files changed

Lines changed: 81 additions & 52 deletions

File tree

docs/01_vfs.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,13 @@ Workspace where `fs` works against the local SQLite store but
3434
`shell` throws.
3535

3636
`WorkspaceOptions` includes the storage handle, optional backends,
37-
clock, session id, mounts, observer, git identity, assets, artifacts,
38-
and `useThink`. There is no `root` or `sandbox` field on the host
39-
facade — sandbox wiring lives behind a `WorkspaceBackend`.
40-
41-
Set `useThink: true` when assigning the Workspace to
42-
`Think.workspace`. This adds Think's string-oriented filesystem
43-
compatibility methods (`readFile`, `readFileBytes`, `writeFile`,
44-
`readDir`, `rm`, `glob`, `mkdir`, and `stat`) to that Workspace and to
45-
clients returned by `getWorkspace()`, while leaving the primary API on
46-
`workspace.fs`.
37+
clock, session id, mounts, observer, git identity, assets, and
38+
artifacts. There is no `root` or `sandbox` field on the host facade —
39+
sandbox wiring lives behind a `WorkspaceBackend`.
40+
41+
Agent integrations consume the filesystem through `workspace.fs`.
42+
Use `createAITools` from `@cloudflare/computer/tools` for the standard
43+
AI SDK file tools.
4744

4845
Illustrative layout (nothing below `/` is auto-created beyond
4946
`ROOT_INODE` itself):

examples/think/src/agent.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,13 @@
1818
* a CloudflareContainerBackend (`"container"`) for full Linux
1919
* userland through computerd. This mirrors examples/container while
2020
* keeping the chat surface unchanged.
21-
* - `useThink: true` adds the string-based compatibility surface
22-
* Think expects; the cast promotes it from optional to present.
23-
* `workspaceBash` is off because `@cloudflare/computer/tools`
24-
* provides the `exec` tool.
21+
* - Think consumes `workspace.fs` directly, while
22+
* `@cloudflare/computer/tools` provides the complete file and
23+
* `exec` tool set.
2524
*/
2625

2726
import {
2827
type DurableObjectStorageLike,
29-
type ThinkWorkspaceCompatibility,
3028
Workspace,
3129
WorkspaceProxy,
3230
WorkspaceServiceProxy,
@@ -88,6 +86,8 @@ export class Assistant extends withWorkspaceContainer(AssistantBase) {
8886
* shell. Passing `{ backend: "container" }` routes a call to computerd in
8987
* the Cloudflare Container.
9088
*/
89+
// The installed Think release still types workspace as its legacy
90+
// root-level filesystem shape. Runtime tools use workspace.fs.
9191
override workspace = new Workspace({
9292
storage: this.ctx.storage as unknown as DurableObjectStorageLike,
9393
backends: [
@@ -99,8 +99,7 @@ export class Assistant extends withWorkspaceContainer(AssistantBase) {
9999
}),
100100
this.#containerBackend,
101101
],
102-
useThink: true,
103-
}) as Workspace & ThinkWorkspaceCompatibility;
102+
}) as Workspace & AssistantBase["workspace"];
104103

105104
/** Forwarded by WorkspaceProxy for computerd's outbound /ws upgrade. */
106105
override async fetch(request: Request): Promise<Response> {

examples/tutorial/README.md

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ with a link to the PDF.
1616
POST /prompt ──► RecipeAgent
1717
│ fetch_url https://openstove.org/... (host)
1818
│ write /workspace/card.md (host)
19-
bash pandoc card.md -o card.pdf (container)
19+
exec pandoc card.md -o card.pdf (container)
2020
2121
R2 ──► signed link, good for a day
2222
```
@@ -26,7 +26,7 @@ of the workspace. The `write` tool runs on the host, in the durable
2626
object, and writes through the `Workspace` into durable object storage.
2727
The container sees the same file on its FUSE mount at `/workspace`, so
2828
`pandoc` reads it as an ordinary file. The PDF `pandoc` writes syncs
29-
back the other way when the `bash` call finishes, so the finished file
29+
back the other way when the `exec` call finishes, so the finished file
3030
can be published straight from the workspace.
3131

3232
The finished code is [one file](src/index.ts). The rest of this page
@@ -86,11 +86,12 @@ wrangler r2 bucket create recipe-cards
8686
npm install @cloudflare/computer @cloudflare/think agents ai zod
8787
```
8888

89-
- `@cloudflare/computer` is the filesystem, the container backend, and
90-
the assets client that publishes to R2.
91-
- `@cloudflare/think` provides the agent loop and its file, shell, and
92-
fetch tools. `agents` provides `getAgentByName` for reaching an
93-
instance by name; `ai` and `zod` satisfy Think's peer dependencies.
89+
- `@cloudflare/computer` provides the filesystem, container backend,
90+
AI SDK file and execution tools, and the assets client that publishes
91+
to R2.
92+
- `@cloudflare/think` provides the agent loop and fetch tools. `agents`
93+
provides `getAgentByName` for reaching an instance by name; `ai` and
94+
`zod` satisfy Think's peer dependencies.
9495

9596
## 3. Create the Dockerfile
9697

@@ -132,9 +133,9 @@ works in both places.
132133
## 4. Give Think a Computer workspace
133134

134135
The durable object owns a `CloudflareContainerBackend`, which is the
135-
container the workspace is mounted in. The `Workspace` instance enables
136-
Computer's Think-compatible methods so Think's built-in tools use the
137-
same filesystem as the container.
136+
container the workspace is mounted in. Think receives the Computer
137+
`Workspace`; agent tools use its `workspace.fs` and `workspace.runtime`
138+
facades directly.
138139

139140
```ts
140141
import {
@@ -144,23 +145,22 @@ import {
144145
import { Think } from "@cloudflare/think";
145146
import {
146147
type DurableObjectStorageLike,
147-
type ThinkWorkspaceCompatibility,
148148
Workspace,
149149
} from "@cloudflare/computer";
150150

151151
class RecipeBase extends Think<Env> {}
152152

153153
export class RecipeAgent extends withWorkspaceContainer(RecipeBase) {
154154
readonly #backend = new CloudflareContainerBackend({
155+
id: "container",
155156
container: () => this,
156157
workspace: { binding: "RecipeAgent", id: this.ctx.id.toString() },
157158
});
158159

159160
override workspace = new Workspace({
160161
storage: this.ctx.storage as unknown as DurableObjectStorageLike,
161162
backends: [this.#backend],
162-
useThink: true,
163-
}) as Workspace & ThinkWorkspaceCompatibility;
163+
});
164164

165165
override async fetch(request: Request): Promise<Response> {
166166
return new URL(request.url).pathname === "/ws"
@@ -178,13 +178,17 @@ hand `/ws` to the backend before the base class sees it.
178178

179179
## 5. Hook the workspace up to the agent
180180

181-
Think already has file and shell tools. The Computer workspace makes
182-
those tools use the same filesystem as the container:
183-
`write` calls Computer's host-side filesystem, while `bash` calls the
184-
container shell. Think's fetch tool gets an allowlist of one host, so
185-
the agent can read openstove.org and nothing else.
181+
Disable Think's legacy shell tool and return Computer's complete tool
182+
set from `getTools()`. `write` calls the host-side filesystem, while
183+
`exec` runs against the container backend. Think's fetch tool gets an
184+
allowlist of one host, so the agent can read openstove.org and nothing
185+
else.
186186

187187
```ts
188+
import { createAITools } from "@cloudflare/computer/tools";
189+
import type { ToolSet } from "ai";
190+
191+
override workspaceBash = false;
188192
override maxSteps = 10;
189193
override fetchTools = {
190194
allowlist: ["https://openstove.org/**"],
@@ -196,6 +200,20 @@ override getModel() {
196200
return "@cf/zai-org/glm-5.2";
197201
}
198202

203+
override getTools(): ToolSet {
204+
return createAITools({
205+
workspace: this.workspace,
206+
shell: {
207+
defaultBackend: "container",
208+
backends: {
209+
container: {
210+
description: "Cloudflare Container with full Linux userland, including pandoc and typst.",
211+
},
212+
},
213+
},
214+
});
215+
}
216+
199217
override getSystemPrompt() {
200218
return [
201219
"You turn a cooking request into a one-page PDF recipe card.",
@@ -209,13 +227,13 @@ override getSystemPrompt() {
209227
" and numbered Method steps. End with the source page URL spelled out,",
210228
" not a markdown link: the card gets printed, and a link prints as its",
211229
" text alone.",
212-
"3. Convert it with `bash`: `pandoc /workspace/card.md -o /workspace/card.pdf --pdf-engine=typst`.",
230+
"3. Convert it with `exec`: `pandoc /workspace/card.md -o /workspace/card.pdf --pdf-engine=typst`.",
213231
"4. Reply with one sentence naming the recipe you picked.",
214232
].join("\n");
215233
}
216234
```
217235

218-
Nothing copies files between `write` and `bash`: the write goes into
236+
Nothing copies files between `write` and `exec`: the write goes into
219237
durable object storage and the container reads it back out of the mount,
220238
and the PDF `pandoc` leaves behind travels the same road in reverse.
221239

@@ -351,7 +369,7 @@ curl -X POST http://localhost:8787/prompt \
351369
```
352370

353371
The first request may be slow: the container has to boot before the
354-
first `bash` runs. The link points at R2 rather than at the worker, so
372+
first `exec` runs. The link points at R2 rather than at the worker, so
355373
it works the same whether the worker runs locally or deployed.
356374

357375
`wrangler deploy` works against any account with Workers AI and

examples/tutorial/src/index.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,27 @@
66
// POST /prompt ──► RecipeAgent (Think + Computer)
77
// │ fetch_url openstove.org (host)
88
// │ write /workspace/card.md (host)
9-
// │ bash pandoc card.md -o card.pdf (container)
9+
// │ exec pandoc card.md -o card.pdf (container)
1010
// ▼
1111
// R2 ──► signed link, good for a day
1212
//
1313
// The write and the pandoc run touch one filesystem: the host writes
1414
// through the Workspace, the container sees the same bytes on its
1515
// FUSE mount, and the PDF the container produces is readable back on
16-
// the host once the shell command finishes.
16+
// the host once the exec command finishes.
1717
//
1818
// README.md walks through building this file from an empty directory.
1919

20-
import {
21-
type DurableObjectStorageLike,
22-
type ThinkWorkspaceCompatibility,
23-
Workspace,
24-
WorkspaceProxy,
25-
} from "@cloudflare/computer";
20+
import { type DurableObjectStorageLike, Workspace, WorkspaceProxy } from "@cloudflare/computer";
2621
import { createAssets } from "@cloudflare/computer/assets";
2722
import {
2823
CloudflareContainerBackend,
2924
withWorkspaceContainer,
3025
} from "@cloudflare/computer/backends/container";
26+
import { createAITools } from "@cloudflare/computer/tools";
3127
import { Think } from "@cloudflare/think";
3228
import { getAgentByName } from "agents";
29+
import type { ToolSet } from "ai";
3330

3431
// Carries container egress back to the durable object. The runtime
3532
// binds it by name, so it has to appear in the worker's module graph.
@@ -38,6 +35,7 @@ export { WorkspaceProxy };
3835
class RecipeBase extends Think<Env> {}
3936

4037
export class RecipeAgent extends withWorkspaceContainer(RecipeBase) {
38+
override workspaceBash = false;
4139
override maxSteps = 10;
4240
override fetchTools = {
4341
allowlist: ["https://openstove.org/**"],
@@ -46,15 +44,17 @@ export class RecipeAgent extends withWorkspaceContainer(RecipeBase) {
4644
};
4745

4846
readonly #backend = new CloudflareContainerBackend({
47+
id: "container",
4948
container: () => this,
5049
workspace: { binding: "RecipeAgent", id: this.ctx.id.toString() },
5150
});
5251

52+
// The installed Think release still types workspace as its legacy
53+
// root-level filesystem shape. Runtime tools use workspace.fs.
5354
override workspace = new Workspace({
5455
storage: this.ctx.storage as unknown as DurableObjectStorageLike,
5556
backends: [this.#backend],
56-
useThink: true,
57-
}) as Workspace & ThinkWorkspaceCompatibility;
57+
}) as Workspace & RecipeBase["workspace"];
5858

5959
override getModel() {
6060
return "@cf/zai-org/glm-5.2";
@@ -73,11 +73,26 @@ export class RecipeAgent extends withWorkspaceContainer(RecipeBase) {
7373
" and numbered Method steps. End with the source page URL spelled out,",
7474
" not a markdown link: the card gets printed, and a link prints as its",
7575
" text alone.",
76-
"3. Convert it with `bash`: `pandoc /workspace/card.md -o /workspace/card.pdf --pdf-engine=typst`.",
76+
"3. Convert it with `exec`: `pandoc /workspace/card.md -o /workspace/card.pdf --pdf-engine=typst`.",
7777
"4. Reply with one sentence naming the recipe you picked.",
7878
].join("\n");
7979
}
8080

81+
override getTools(): ToolSet {
82+
return createAITools({
83+
workspace: this.workspace,
84+
shell: {
85+
defaultBackend: "container",
86+
backends: {
87+
container: {
88+
description:
89+
"Cloudflare Container with full Linux userland, including pandoc and typst.",
90+
},
91+
},
92+
},
93+
});
94+
}
95+
8196
override async fetch(request: Request): Promise<Response> {
8297
return new URL(request.url).pathname === "/ws"
8398
? this.#backend.handleFetch(request)

packages/computer/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ await ws.ready();
464464
const stub = ws.stub(); // crosses the Workers-RPC boundary
465465
```
466466

467-
When assigning a workspace to a Think agent's `workspace`, pass
468-
`useThink: true` so Think's compatibility methods are added alongside
469-
`workspace.fs` and `workspace.runtime`.
467+
Agent frameworks should consume files through `workspace.fs`. Use
468+
`createAITools` from `@cloudflare/computer/tools` for the standard AI
469+
SDK file tools.
470470

471471
### Durable pending-sync retries
472472

0 commit comments

Comments
 (0)