Skip to content

computer: Provide ai-sdk, pi-ai and tanstack-ai compatible tools - #191

Merged
aron-cf merged 4 commits into
mainfrom
split/tools-main
Oct 2, 2026
Merged

aron-cf merged 4 commits into
mainfrom
split/tools-main

Conversation

@aron-cf

@aron-cf aron-cf commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

This PR was extracted from #186 so it can land on main but leaves out the changes to exec that are still on the container path.


Devin Review

@aron-cf aron-cf added the allow-pr Allow a PR to remain open. label Oct 2, 2026
@changeset-bot

changeset-bot Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

馃 Changeset detected

Latest commit: d810bea

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

This PR includes changesets to release 4 packages
Name Type
@cloudflare/computer Minor
@cloudflare/dofs Minor
@cloudflare/computer-rpc Minor
@cloudflare/computerd Minor

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

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Devin Review

Comment on lines +60 to +75
const fetch = async (_input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
const input = JSON.parse(bodyText(init?.body)) as Record<string, unknown>;
const name = typeof input.model === "string" ? input.model : undefined;
if (!name) throw new TypeError("Workers AI pi request is missing its model");
delete input.model;
return runBinding.run(name, input, {
returnRawResponse: true,
...(init?.signal ? { signal: init.signal } : {}),
});
};

const api = openAICompletionsApi();
const streams: ProviderStreams = {
stream: (m, context, options) =>
api.stream(m, context, { ...options, fetch } as ApiStreamOptions<string>),
streamSimple: (m, context, options) => api.streamSimple(m, context, { ...options, fetch }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃攳 Workers AI transport remains untested

The local pi run replaces Workers AI with a scripted model, so it never exercises workersAI against the binding. A deployed smoke test would check whether pi can consume its streamed response.

Devin Review


Was this helpful? React with 馃憤 or 馃憥 to provide feedback.

Comment on lines +106 to +110
const { task } = (await request.json()) as { task?: string };
if (!task) return new Response("body needs a task\n", { status: 400 });

const agent = env.PiAgent.get(env.PiAgent.idFromName("demo"));
return new Response(`${await agent.run(task)}\n`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃煡 Unauthenticated tasks control the shared workspace

Any caller can POST a task to PiAgent without authentication. Every request uses the same demo object, exposing its files and shell to unauthorized callers.

Devin Review


Was this helpful? React with 馃憤 or 馃憥 to provide feedback.

Comment on lines +79 to +83
const { task } = (await request.json()) as { task?: string };
if (!task) return new Response("body needs a task\n", { status: 400 });

const agent = env.TanStackAgent.get(env.TanStackAgent.idFromName("demo"));
return new Response(`${await agent.run(task)}\n`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃煡 Unauthenticated tasks share the TanStack workspace

Any caller can POST a task to TanStackAgent without authentication. The fixed demo object exposes its persistent files and shell to every caller.

Devin Review


Was this helpful? React with 馃憤 or 馃憥 to provide feedback.

aron-cf and others added 4 commits October 2, 2026 11:03
Split each tool into a framework-neutral core under tools/common
(schema, description, executor; zod only) and an adapter per agent
library. tools/ai-sdk wraps the core with `tool()` from `ai`;
tools/pi-ai and tools/tanstack-ai build their own shapes from the
same core without importing their libraries, so each entry point
pulls in only what it uses. createAITools stays exported from
@cloudflare/computer/tools.

The exec core keeps the current options: a `shell` with a backend
map and a default backend. All three tool sets resolve options
through the same resolveToolOptions, so they offer the same tools.

The pi and TanStack adapters come from #149.

Co-authored-by: aron <263346377+aron-cf@users.noreply.github.com>
Two one-shot agents on a Worker-shell Workspace: pi-ai, where `run` is
the whole loop, and tanstack-ai, where chat() owns it. Both pass the
one worker shell to `exec` through `shell`. `npm run local` drives
each loop in Node with a scripted model, through a small shim for
`cloudflare:workers`.

Bumps the libraries to current releases (pi-ai 0.99, @tanstack/ai
0.63, @tanstack/ai-cloudflare 0.2) and adds both to the CI examples
matrix. Docs, READMEs, and a changeset cover the two entry points.

The examples come from #149.

Co-authored-by: aron <263346377+aron-cf@users.noreply.github.com>
chat() passes a tool result to the adapter as multimodal content only
when it is a ContentPart array. The read tool returned an image or PDF
as a plain object, which TanStack JSON-stringified, so the model got
the base64 as text. It now returns a text part plus an image or
document part, and the test checks the shape with TanStack's own
isContentPartArray.

Also covers a failed pi publish, which already comes back as an error
result.
Renames createPiAITools to createPiTools and createTanStackAITools to
createTanStackTools, with their option and result types. The entry
points stay tools/pi-ai and tools/tanstack-ai.

pi checks tool arguments with TypeBox, which also compiles plain JSON
Schema, so the pi tools need only zod for their own schemas. pi 0.99
also closes a constrainedSampling schema itself when the provider runs
it strict. The adapter used to close read, write, and edit up front,
which made every optional field required in the schema pi validates
against. A provider that fell back to ordinary tool calling and left
`offset` out of a read failed pi's own validateToolCall. The
declarations now stay open, and execute drops a null only on an
optional field that cannot take one. Tests check the declarations
against pi's validateToolCall and makeStrictJsonSchema.
@pkg-pr-new

pkg-pr-new Bot commented Oct 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@cloudflare/computer@191

commit: d64fb73

@aron-cf
aron-cf merged commit 960d85b into main Oct 2, 2026
21 checks passed
@aron-cf
aron-cf deleted the split/tools-main branch October 2, 2026 11:10
@github-actions github-actions Bot mentioned this pull request Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

allow-pr Allow a PR to remain open.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants