Browser tools
Cloudflare's createBrowserTools turns Browser Rendering into an AI-SDK ToolSet — a set of tools an LLM can call to search the web and execute scripted browser sessions. ayjnt wraps it in a zero-config helper: import once, get tools wired, and the framework provisions every binding the runtime needs.
The one-liner
import { Agent } from "agents";
import { browserTools } from "ayjnt/browser"; // ← the trigger
import type { GeneratedEnv } from "@ayjnt/env";
export default class ResearchAgent extends Agent<GeneratedEnv, State> {
override async onRequest(req: Request): Promise<Response> {
const tools = browserTools(this); // → AI-SDK ToolSet
// pass tools to generateText() / streamText() etc.
return Response.json({ tools: Object.keys(tools) });
}
}What ayjnt wires up
The build picks up import { browserTools } from "ayjnt/browser"
(or createBrowserTools — both trigger the
same detection) and adds four pieces of plumbing to .ayjnt/dist/wrangler.jsonc:
{
"compatibility_flags": ["nodejs_compat"], // Loader runtime requirement
"browser": { "binding": "BROWSER" }, // Browser Rendering
"worker_loaders": [{ "binding": "LOADER" }], // sandboxed CDP execution
"ai": { "binding": "AI" } // model for the tools
}
It also augments .ayjnt/env.d.ts with typed BROWSER, LOADER, and AI
fields on GeneratedEnv, so reading them inside the
agent (via this.env.BROWSER etc.) autocompletes.
Forget any of those four pieces in a hand-rolled wrangler.jsonc and the runtime fails in opaque
ways. That's why ayjnt hooks them up the moment it sees the
import — there's no good reason to import ayjnt/browser without all of these.
What you get back
browserTools(this, options?) returns the same ToolSet shape Cloudflare's createBrowserTools returns — tools keyed by name
like browser_search, browser_execute
and ready to drop straight into generateText({ model, tools, prompt }):
import { generateText } from "ai";
import { createWorkersAI } from "workers-ai-provider";
const tools = browserTools(this);
const ai = createWorkersAI({ binding: this.env.AI });
const result = await generateText({
model: ai("@cf/meta/llama-3.3-70b-instruct-fp8-fast"),
tools,
prompt: "What's the current weather in Tokyo?",
maxSteps: 5,
});Options
| Argument | Type | Purpose |
|---|---|---|
agent | the agent instance (this) | Reads agent.env.BROWSER and agent.env.LOADER |
options.cdpUrl? | string | Override CDP endpoint (e.g. local Chromium for dev) |
options.cdpHeaders? | Record<string, string> | Headers for the CDP URL (e.g. Cloudflare Access) |
options.timeout? | number | Per-tool execution timeout, default 30000ms |
Comparison: raw vs ayjnt
// without ayjnt/browser:
import { createBrowserTools } from "agents/browser/ai";
const tools = createBrowserTools({
browser: env.BROWSER,
loader: env.LOADER,
});
// + remember to add browser + worker_loaders + ai + nodejs_compat
// to wrangler.jsonc by hand. Miss one — opaque runtime error.
// with ayjnt/browser:
import { browserTools } from "ayjnt/browser";
const tools = browserTools(this);
// framework handles wrangler.jsonc and env.d.ts.
Both APIs are exported from ayjnt/browser — the
detection fires on either name, so use whichever fits your
style. browserTools(this, ...) is the shortcut; createBrowserTools({ browser, loader }) is the
explicit form.
Production caveats
- Browser Rendering must be enabled on your Cloudflare account (free tier supports it for development).
-
@cloudflare/codemodeis a peer dependency of the agents SDK's browser tools — installed by the example automatically. - No-binding fallback for local dev: pass
cdpUrltobrowserTools(this, { cdpUrl: "http://localhost:9222" })to point at a local Chromium when Browser Rendering isn't wired up.
Co-located UI
The example ships an app.tsx next to the agent: useAgent() from @ayjnt/research opens a
WebSocket, the form calls a @callable investigate(question)
method, and the rendered list of registered tool names proves
the framework provisioned BROWSER + LOADER + AI correctly.
Swap in generateText({ tools, ... }) inside investigate when you're ready for real LLM output.
Reference
- Cloudflare's Browser Rendering docs
-
examples/browser-tools— full agent + UI withgenerateTextintegration sketched out.