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..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 @@ -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 @@ -36,7 +37,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 +46,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 +72,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 +146,7 @@ export default { return new Response("Not found", { status: 404 }); }, -}; +} satisfies ExportedHandler; ``` @@ -191,7 +194,7 @@ export default { return new Response("Not found", { status: 404 }); }, -}; +} satisfies ExportedHandler; ``` @@ -210,28 +213,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. 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. @@ -295,11 +287,15 @@ Add more agents by extending the configuration: ```ts // src/agents/chat.ts +import { Agent } from "agents"; + export class Chat extends Agent { // ... } // src/agents/scheduler.ts +import { Agent } from "agents"; + export class Scheduler extends Agent { // ... } @@ -367,7 +363,7 @@ export default { // ... rest of routing }, -}; +} satisfies ExportedHandler; ``` @@ -409,7 +405,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..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. @@ -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 ``` -## Step 3: Test the agent locally +You can also upload all secrets from your `.env` file to production at once: + +```bash +wrangler secret bulk .env +``` + +## Step 3: Run the dev server ```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. `, @@ -202,20 +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 -``` - ## Features - **Streaming Responses**: Real-time AI responses with typing indicators. @@ -231,17 +240,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** @@ -253,3 +257,29 @@ wrangler secret put OPENAI_API_KEY - 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 517fea2c51fc8a..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: @@ -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..d556e27a6f778f 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. @@ -15,7 +21,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 +32,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 +50,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({ @@ -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" }); }); }); ``` @@ -115,12 +121,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 +140,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: @@ -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 + + + + + +