From a44e77f120a37d77da493f18fde3a06cc4de5580 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 13 Feb 2026 13:09:43 +0000 Subject: [PATCH 1/4] [Agents] Update getting-started guides to align with latest best practices and agents-starter - Use $today for compatibility_date per Workers best practices - Update AIChatAgent import to @cloudflare/ai-chat - Update tool definitions to use inputSchema (AI SDK v5) and zod/v3 - Update getSchedulePrompt import to agents/schedule - Add satisfies ExportedHandler to all default exports - Replace .dev.vars with .env for local secrets per best practices - Add wrangler secret bulk .env guidance for production - Replace hand-written Env types with wrangler types guidance - Add @callable() decorators to add-to-existing-project example - Fix vitest config references from .js to .ts - Remove $ prefix from terminal commands in testing guide - Use txt language for command output blocks --- .../add-to-existing-project.mdx | 37 +++++------- .../getting-started/build-a-chat-agent.mdx | 56 ++++++++++++------- .../agents/getting-started/quick-start.mdx | 30 +++++----- .../getting-started/testing-your-agent.mdx | 20 +++---- 4 files changed, 75 insertions(+), 68 deletions(-) diff --git a/src/content/docs/agents/getting-started/add-to-existing-project.mdx b/src/content/docs/agents/getting-started/add-to-existing-project.mdx index 6322b0ec7e645a..e0e75e2c119722 100644 --- a/src/content/docs/agents/getting-started/add-to-existing-project.mdx +++ b/src/content/docs/agents/getting-started/add-to-existing-project.mdx @@ -36,7 +36,7 @@ Create a new file for your agent (for example, `src/agents/counter.ts`): ```ts -import { Agent } from "agents"; +import { Agent, callable } from "agents"; export type CounterState = { count: number; @@ -45,11 +45,13 @@ export type CounterState = { export class CounterAgent extends Agent { initialState: CounterState = { count: 0 }; + @callable() increment() { this.setState({ count: this.state.count + 1 }); return this.state.count; } + @callable() decrement() { this.setState({ count: this.state.count - 1 }); return this.state.count; @@ -69,7 +71,7 @@ Add the Durable Object binding and migration: { "name": "my-existing-project", "main": "src/index.ts", - "compatibility_date": "2025-01-01", + "compatibility_date": "$today", "compatibility_flags": ["nodejs_compat"], "durable_objects": { @@ -143,7 +145,7 @@ export default { return new Response("Not found", { status: 404 }); }, -}; +} satisfies ExportedHandler; ``` @@ -191,7 +193,7 @@ export default { return new Response("Not found", { status: 404 }); }, -}; +} satisfies ExportedHandler; ``` @@ -210,28 +212,17 @@ Configure assets in the Wrangler configuration file: -## 6. Add TypeScript types +## 6. Generate TypeScript types + +Do not hand-write your `Env` interface. Run [`wrangler types`](/workers/wrangler/commands/#types) to generate a type definition file that matches your Wrangler configuration. This catches mismatches between your config and code at compile time instead of at deploy time. -You can generate types automatically from your Wrangler configuration file: +Re-run `wrangler types` whenever you add or rename a binding. ```sh -npx wrangler types env.d.ts +npx wrangler types ``` -This creates an `env.d.ts` file with all your bindings typed. Alternatively, you can manually update your `Env` type to include the agent namespace: - -```ts -import type { CounterAgent } from "./agents/counter"; - -interface Env { - // Your existing bindings - MY_KV: KVNamespace; - MY_DB: D1Database; - - // Add agent bindings - CounterAgent: DurableObjectNamespace; -} -``` +This creates a type definition file with all your bindings typed, including your agent Durable Object namespaces. Refer to [Configuration](/agents/api-reference/configuration/#generating-types) for more details on type generation. @@ -367,7 +358,7 @@ export default { // ... rest of routing }, -}; +} satisfies ExportedHandler; ``` @@ -409,7 +400,7 @@ export default { } // ... }, -}; +} satisfies ExportedHandler; ``` diff --git a/src/content/docs/agents/getting-started/build-a-chat-agent.mdx b/src/content/docs/agents/getting-started/build-a-chat-agent.mdx index 23cd3f8b879fc1..7c1f3c95152ab7 100644 --- a/src/content/docs/agents/getting-started/build-a-chat-agent.mdx +++ b/src/content/docs/agents/getting-started/build-a-chat-agent.mdx @@ -34,9 +34,9 @@ npm install You have two options for setting up your OpenAI API key: -**Option A: Using `.dev.vars` (recommended for development)** +**Option A: Using `.env` (recommended for development)** -Create a `.dev.vars` file in your project root: +Create a `.env` file in your project root (and make sure it is in your `.gitignore`): ```txt OPENAI_API_KEY=your-key-here @@ -50,13 +50,19 @@ For production deployments, use Cloudflare secrets instead of putting API keys i wrangler secret put OPENAI_API_KEY ``` +You can also upload all secrets from your `.env` file to production at once: + +```bash +wrangler secret bulk .env +``` + ## Step 3: Test the agent locally ```bash npm start ``` -The server will be available at `http://localhost:5174`. Open your browser and start chatting. +Open your browser and start chatting. Check the terminal output for the correct URL. ## Understanding the code @@ -82,10 +88,14 @@ The main agent class that handles chat interactions: ```ts -import { AIChatAgent } from "agents/ai-chat-agent"; +import { AIChatAgent } from "@cloudflare/ai-chat"; +import { streamText, type StreamTextOnFinishCallback, type ToolSet } from "ai"; export class Chat extends AIChatAgent { - async onChatMessage(onFinish, options) { + async onChatMessage( + onFinish: StreamTextOnFinishCallback, + options?: { abortSignal?: AbortSignal }, + ) { // Handles incoming messages and manages streaming responses // Processes tool calls and generates AI responses } @@ -102,12 +112,12 @@ Define what actions your agent can perform: ```ts import { tool } from "ai"; -import { z } from "zod"; +import { z } from "zod/v3"; // Automatic execution (no confirmation needed) const getLocalTime = tool({ description: "get the local time for a specified location", - parameters: z.object({ location: z.string() }), + inputSchema: z.object({ location: z.string() }), execute: async ({ location }) => { return "10am"; }, @@ -116,7 +126,7 @@ const getLocalTime = tool({ // Requires confirmation (no execute function) const getWeatherInformation = tool({ description: "show the weather in a given city to the user", - parameters: z.object({ city: z.string() }), + inputSchema: z.object({ city: z.string() }), // Omitting execute function makes this tool require human confirmation }); ``` @@ -133,9 +143,11 @@ const getWeatherInformation = tool({ ```ts // In src/tools.ts +import { z } from "zod/v3"; + const getWeather = tool({ description: "Get current weather for a location", - parameters: z.object({ + inputSchema: z.object({ location: z.string().describe("The city name"), }), execute: async ({ location }) => { @@ -161,7 +173,7 @@ export const tools = { // In src/tools.ts const sensitiveAction = tool({ description: "Perform a sensitive action", - parameters: z.object({ + inputSchema: z.object({ action: z.string().describe("The action to perform"), reason: z.string().describe("Reason for the action"), }), @@ -187,14 +199,17 @@ export const executions = { ### Customizing the system prompt -Edit the system prompt in `src/server.ts`: +Edit the system prompt in `src/server.ts`. You can use the `getSchedulePrompt` helper from `agents/schedule` to include scheduling context: ```ts +import { getSchedulePrompt } from "agents/schedule"; + +// Inside your onChatMessage method: system: `You are a helpful assistant specializing in software development. You can help with coding questions, debugging, and best practices. Always provide clear, actionable advice. -${unstable_getSchedulePrompt({ date: new Date() })} +${getSchedulePrompt({ date: new Date() })} If the user asks to schedule a task, use the schedule tool to schedule the task. `, @@ -216,6 +231,12 @@ For production deployment, set your OpenAI API key as a secret: wrangler secret put OPENAI_API_KEY ``` +You can also upload all secrets from your `.env` file at once: + +```bash +wrangler secret bulk .env +``` + ## Features - **Streaming Responses**: Real-time AI responses with typing indicators. @@ -231,17 +252,12 @@ wrangler secret put OPENAI_API_KEY **"OPENAI_API_KEY is not set"** -- Make sure you have set the API key in `.dev.vars` for local development. -- For production, use `wrangler secret put OPENAI_API_KEY`. - -**"npm run dev" not found** - -- Use `npm start` instead (the script is named `start`). +- Make sure you have set the API key in a `.env` file in your project root for local development. +- For production, use `wrangler secret put OPENAI_API_KEY` or `wrangler secret bulk .env`. **Server not accessible** -- Check that the server is running on port 5174 (not 8787). -- Look for the correct URL in the terminal output. +- Look for the correct URL in the terminal output when you run `npm start` or `npm run dev`. **Tool execution errors** diff --git a/src/content/docs/agents/getting-started/quick-start.mdx b/src/content/docs/agents/getting-started/quick-start.mdx index 517fea2c51fc8a..7dc6540690dbe6 100644 --- a/src/content/docs/agents/getting-started/quick-start.mdx +++ b/src/content/docs/agents/getting-started/quick-start.mdx @@ -89,7 +89,7 @@ export default { new Response("Not found", { status: 404 }) ); }, -}; +} satisfies ExportedHandler; ``` @@ -102,7 +102,7 @@ Update `wrangler.jsonc` to register the agent: { "name": "my-agent", "main": "src/server.ts", - "compatibility_date": "2025-01-01", + "compatibility_date": "$today", "compatibility_flags": ["nodejs_compat"], "durable_objects": { "bindings": [ @@ -179,12 +179,12 @@ flowchart LR ### Key concepts -| Concept | What it means | -| -------------------- | ------------------------------------------------------------------------------------------- | +| Concept | What it means | +| -------------------- | ----------------------------------------------------------------------------------------------------- | | **Agent instance** | Each unique name gets its own agent. `CounterAgent:user-123` is separate from `CounterAgent:user-456` | -| **Persistent state** | State survives restarts, deploys, and hibernation. It is stored in SQLite | -| **Real-time sync** | All clients connected to the same agent receive state updates instantly | -| **Hibernation** | When no clients are connected, the agent hibernates (no cost). It wakes on the next request | +| **Persistent state** | State survives restarts, deploys, and hibernation. It is stored in SQLite | +| **Real-time sync** | All clients connected to the same agent receive state updates instantly | +| **Hibernation** | When no clients are connected, the agent hibernates (no cost). It wakes on the next request | ## Connect from vanilla JavaScript @@ -283,13 +283,13 @@ Now that you have a working agent, explore these topics: ### Common patterns -| Learn how to | Refer to | -| ------------------------ | ------------------------------------------------------------ | -| Add AI/LLM capabilities | [Using AI models](/agents/api-reference/using-ai-models/) | -| Expose tools via MCP | [MCP servers](/agents/api-reference/mcp-agent-api/) | -| Run background tasks | [Schedule tasks](/agents/api-reference/schedule-tasks/) | -| Handle emails | [Email routing](/agents/api-reference/email/) | -| Use Cloudflare Workflows | [Run Workflows](/agents/api-reference/run-workflows/) | +| Learn how to | Refer to | +| ------------------------ | --------------------------------------------------------- | +| Add AI/LLM capabilities | [Using AI models](/agents/api-reference/using-ai-models/) | +| Expose tools via MCP | [MCP servers](/agents/api-reference/mcp-agent-api/) | +| Run background tasks | [Schedule tasks](/agents/api-reference/schedule-tasks/) | +| Handle emails | [Email routing](/agents/api-reference/email/) | +| Use Cloudflare Workflows | [Run Workflows](/agents/api-reference/run-workflows/) | ### Explore more @@ -315,4 +315,4 @@ Now that you have a working agent, explore these topics: title="Schedule tasks" href="/agents/api-reference/schedule-tasks/" description="Run tasks on a delay, schedule, or cron." -/> \ No newline at end of file +/> diff --git a/src/content/docs/agents/getting-started/testing-your-agent.mdx b/src/content/docs/agents/getting-started/testing-your-agent.mdx index 39d1a7928e9fda..d77a999d7d1d82 100644 --- a/src/content/docs/agents/getting-started/testing-your-agent.mdx +++ b/src/content/docs/agents/getting-started/testing-your-agent.mdx @@ -15,7 +15,7 @@ Because Agents run on Cloudflare Workers and Durable Objects, they can be tested :::note -The `agents-starter` template and new Cloudflare Workers projects already include the relevant `vitest` and `@cloudflare/vitest-pool-workers` packages, as well as a valid `vitest.config.js` file. +The `agents-starter` template and new Cloudflare Workers projects already include the relevant `vitest` and `@cloudflare/vitest-pool-workers` packages, as well as a valid `vitest.config.ts` file. ::: @@ -26,9 +26,9 @@ npm install vitest@~3.0.0 --save-dev --save-exact npm install @cloudflare/vitest-pool-workers --save-dev ``` -Ensure that your `vitest.config.js` file is identical to the following: +Ensure that your `vitest.config.ts` file is identical to the following: -```js +```ts import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; export default defineWorkersConfig({ @@ -44,9 +44,9 @@ export default defineWorkersConfig({ ### Add the Agent configuration -Add a `durableObjects` configuration to `vitest.config.js` with the name of your Agent class: +Add a `durableObjects` configuration to `vitest.config.ts` with the name of your Agent class: -```js +```ts import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; export default defineWorkersConfig({ @@ -115,12 +115,12 @@ describe("make a request to my Agent", () => { Running tests is done using the `vitest` CLI: ```sh -$ npm run test +npm run test # or run vitest directly -$ npx vitest +npx vitest ``` -```sh output +```txt MyAgent ✓ should return a greeting (1 ms) @@ -134,10 +134,10 @@ Review the [documentation on testing](/workers/testing/vitest-integration/write- You can also run an Agent locally using the `wrangler` CLI: ```sh -$ npx wrangler dev +npx wrangler dev ``` -```sh output +```txt Your Worker and resources are simulated locally via Miniflare. For more information, see: https://developers.cloudflare.com/workers/testing/local-development. Your worker has access to the following bindings: From 6f15e6ea4912f61b10234a43bcd05e586e8739b1 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 13 Feb 2026 13:27:25 +0000 Subject: [PATCH 2/4] [Agents] Fix structural inconsistencies across getting-started guides - quick-start: add project name to create command so cd my-agent matches - add-to-existing-project: add missing description, fix misdirected 'starting fresh' link to point to quick-start instead of chat agent, add missing Agent import in multiple-agents example - testing-your-agent: add missing description, fix pcx_content_type to how-to, fix response.text() to response.json() in test examples, use relative URL for wrangler dev link, add Next steps section - build-a-chat-agent: rename Step 3 to 'Run the dev server' to avoid confusion with testing guide, remove duplicate secrets section, add Next steps section, import LinkCard --- .../add-to-existing-project.mdx | 11 +++-- .../getting-started/build-a-chat-agent.mdx | 46 ++++++++++++------- .../agents/getting-started/quick-start.mdx | 2 +- .../getting-started/testing-your-agent.mdx | 36 +++++++++++++-- 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/content/docs/agents/getting-started/add-to-existing-project.mdx b/src/content/docs/agents/getting-started/add-to-existing-project.mdx index e0e75e2c119722..a83712497b16ad 100644 --- a/src/content/docs/agents/getting-started/add-to-existing-project.mdx +++ b/src/content/docs/agents/getting-started/add-to-existing-project.mdx @@ -3,6 +3,7 @@ title: Add to existing project pcx_content_type: how-to sidebar: order: 2 +description: Add agents with persistent state and real-time sync to an existing Cloudflare Workers project. --- import { @@ -12,7 +13,7 @@ import { LinkCard, } from "~/components"; -This guide shows how to add agents to an existing Cloudflare Workers project. If you are starting fresh, refer to [Building a chat agent](/agents/getting-started/build-a-chat-agent/) instead. +This guide shows how to add agents to an existing Cloudflare Workers project. If you are starting a new project, refer to [Quick start](/agents/getting-started/quick-start/) instead. ## Prerequisites @@ -286,12 +287,16 @@ Add more agents by extending the configuration: ```ts // src/agents/chat.ts -export class Chat extends Agent { +import { Agent } from "agents"; + +export class Chat extends Agent { // ... } // src/agents/scheduler.ts -export class Scheduler extends Agent { +import { Agent } from "agents"; + +export class Scheduler extends Agent { // ... } ``` diff --git a/src/content/docs/agents/getting-started/build-a-chat-agent.mdx b/src/content/docs/agents/getting-started/build-a-chat-agent.mdx index 7c1f3c95152ab7..f8f55e743f3f17 100644 --- a/src/content/docs/agents/getting-started/build-a-chat-agent.mdx +++ b/src/content/docs/agents/getting-started/build-a-chat-agent.mdx @@ -7,7 +7,7 @@ head: [] description: Build a streaming AI chat agent with tool integration using Cloudflare Workers and the Agents framework. --- -import { TypeScriptExample, WranglerConfig } from "~/components"; +import { TypeScriptExample, WranglerConfig, LinkCard } from "~/components"; A complete guide to building a streaming AI chat agent with tool integration using Cloudflare Workers and the Agents framework. @@ -56,7 +56,7 @@ You can also upload all secrets from your `.env` file to production at once: wrangler secret bulk .env ``` -## Step 3: Test the agent locally +## Step 3: Run the dev server ```bash npm start @@ -217,26 +217,14 @@ If the user asks to schedule a task, use the schedule tool to schedule the task. ## Deploy to Cloudflare Workers +Before deploying, make sure your production secrets are set (refer to Step 2, Option B). + ```bash npm run deploy ``` Your agent will be available at `https://your-project-name.your-subdomain.workers.dev`. -### Environment variables in production - -For production deployment, set your OpenAI API key as a secret: - -```bash -wrangler secret put OPENAI_API_KEY -``` - -You can also upload all secrets from your `.env` file at once: - -```bash -wrangler secret bulk .env -``` - ## Features - **Streaming Responses**: Real-time AI responses with typing indicators. @@ -269,3 +257,29 @@ wrangler secret bulk .env - Use the browser developer tools to view detailed error messages. - Check the terminal output for server logs. - The debug mode in the UI shows detailed message processing. + +## Next steps + + + + + + + + diff --git a/src/content/docs/agents/getting-started/quick-start.mdx b/src/content/docs/agents/getting-started/quick-start.mdx index 7dc6540690dbe6..0a0af27b618dd6 100644 --- a/src/content/docs/agents/getting-started/quick-start.mdx +++ b/src/content/docs/agents/getting-started/quick-start.mdx @@ -24,7 +24,7 @@ Build AI agents that persist, think, and act. Agents run on Cloudflare's global Then install dependencies and start the dev server: diff --git a/src/content/docs/agents/getting-started/testing-your-agent.mdx b/src/content/docs/agents/getting-started/testing-your-agent.mdx index d77a999d7d1d82..5b254d65e58027 100644 --- a/src/content/docs/agents/getting-started/testing-your-agent.mdx +++ b/src/content/docs/agents/getting-started/testing-your-agent.mdx @@ -1,11 +1,17 @@ --- title: Testing your Agents -pcx_content_type: get-started +pcx_content_type: how-to sidebar: order: 3 +description: Write and run tests for your Cloudflare Agents using Vitest and the Workers test pool. --- -import { Render, PackageManagers, WranglerConfig } from "~/components"; +import { + Render, + PackageManagers, + WranglerConfig, + LinkCard, +} from "~/components"; Because Agents run on Cloudflare Workers and Durable Objects, they can be tested using the same tools and techniques as Workers and Durable Objects. @@ -99,13 +105,13 @@ describe("make a request to my Agent", () => { const ctx = createExecutionContext(); const response = await worker.fetch(request, env, ctx); await waitOnExecutionContext(ctx); - expect(await response.text()).toMatchObject({ hello: "from your agent" }); + expect(await response.json()).toMatchObject({ hello: "from your agent" }); }); it("also responds with state", async () => { const request = new Request("http://example.com/agent/my-agent/agent-123"); const response = await SELF.fetch(request); - expect(await response.text()).toMatchObject({ hello: "from your agent" }); + expect(await response.json()).toMatchObject({ hello: "from your agent" }); }); }); ``` @@ -149,4 +155,24 @@ Your worker has access to the following bindings: This spins up a local development server that runs the same runtime as Cloudflare Workers, and allows you to iterate on your Agent's code and test it locally without deploying it. -Visit the [`wrangler dev`](https://developers.cloudflare.com/workers/wrangler/commands/#dev) docs to review the CLI flags and configuration options. +Visit the [`wrangler dev`](/workers/wrangler/commands/#dev) docs to review the CLI flags and configuration options. + +## Next steps + + + + + + From 3425616916cddf23005a1588fe3e354a3ed73f05 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 13 Feb 2026 21:11:49 +0000 Subject: [PATCH 3/4] fix: correct invalid link to local development docs --- src/content/docs/agents/getting-started/testing-your-agent.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/agents/getting-started/testing-your-agent.mdx b/src/content/docs/agents/getting-started/testing-your-agent.mdx index 5b254d65e58027..d556e27a6f778f 100644 --- a/src/content/docs/agents/getting-started/testing-your-agent.mdx +++ b/src/content/docs/agents/getting-started/testing-your-agent.mdx @@ -173,6 +173,6 @@ Visit the [`wrangler dev`](/workers/wrangler/commands/#dev) docs to review the C From 00f5e91ceffb75e20a86837043a1e7f8507d0c7f Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Fri, 13 Feb 2026 21:52:08 +0000 Subject: [PATCH 4/4] [Agents] Drop explicit from Agent where it is the default wrangler types generates Cloudflare.Env which Agent uses by default, so Agent is redundant. Keep Env only where a second type param (state) is needed, e.g. Agent. --- .../docs/agents/getting-started/add-to-existing-project.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/docs/agents/getting-started/add-to-existing-project.mdx b/src/content/docs/agents/getting-started/add-to-existing-project.mdx index a83712497b16ad..df0743b51393da 100644 --- a/src/content/docs/agents/getting-started/add-to-existing-project.mdx +++ b/src/content/docs/agents/getting-started/add-to-existing-project.mdx @@ -223,7 +223,7 @@ Re-run `wrangler types` whenever you add or rename a binding. npx wrangler types ``` -This creates a type definition file with all your bindings typed, including your agent Durable Object namespaces. +This creates a type definition file with all your bindings typed, including your agent Durable Object namespaces. The `Agent` class defaults to using the generated `Env` type, so you do not need to pass it as a type parameter — `extends Agent` is sufficient unless you need to pass a second type parameter for state (for example, `Agent`). Refer to [Configuration](/agents/api-reference/configuration/#generating-types) for more details on type generation. @@ -289,14 +289,14 @@ Add more agents by extending the configuration: // src/agents/chat.ts import { Agent } from "agents"; -export class Chat extends Agent { +export class Chat extends Agent { // ... } // src/agents/scheduler.ts import { Agent } from "agents"; -export class Scheduler extends Agent { +export class Scheduler extends Agent { // ... } ```