Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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

Expand All @@ -36,7 +37,7 @@ Create a new file for your agent (for example, `src/agents/counter.ts`):
<TypeScriptExample>

```ts
import { Agent } from "agents";
import { Agent, callable } from "agents";

export type CounterState = {
count: number;
Expand All @@ -45,11 +46,13 @@ export type CounterState = {
export class CounterAgent extends Agent<Env, CounterState> {
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;
Expand All @@ -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": {
Expand Down Expand Up @@ -143,7 +146,7 @@ export default {

return new Response("Not found", { status: 404 });
},
};
} satisfies ExportedHandler<Env>;
```

</TypeScriptExample>
Expand Down Expand Up @@ -191,7 +194,7 @@ export default {

return new Response("Not found", { status: 404 });
},
};
} satisfies ExportedHandler<Env>;
```

</TypeScriptExample>
Expand All @@ -210,28 +213,17 @@ Configure assets in the Wrangler configuration file:

</WranglerConfig>

## 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<CounterAgent>;
}
```
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<Env, CounterState>`).

Refer to [Configuration](/agents/api-reference/configuration/#generating-types) for more details on type generation.

Expand Down Expand Up @@ -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 {
// ...
}
Expand Down Expand Up @@ -367,7 +363,7 @@ export default {

// ... rest of routing
},
};
} satisfies ExportedHandler<Env>;
```

</TypeScriptExample>
Expand Down Expand Up @@ -409,7 +405,7 @@ export default {
}
// ...
},
};
} satisfies ExportedHandler<Env>;
```

</TypeScriptExample>
Expand Down
90 changes: 60 additions & 30 deletions src/content/docs/agents/getting-started/build-a-chat-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand All @@ -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

Expand All @@ -82,10 +88,14 @@ The main agent class that handles chat interactions:
<TypeScriptExample>

```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<Env> {
async onChatMessage(onFinish, options) {
async onChatMessage(
onFinish: StreamTextOnFinishCallback<ToolSet>,
options?: { abortSignal?: AbortSignal },
) {
// Handles incoming messages and manages streaming responses
// Processes tool calls and generates AI responses
}
Expand All @@ -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";
},
Expand All @@ -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
});
```
Expand All @@ -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 }) => {
Expand All @@ -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"),
}),
Expand All @@ -187,35 +199,32 @@ 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.
`,
```

## 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.
Expand All @@ -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**

Expand All @@ -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

<LinkCard
title="Testing your agents"
href="/agents/getting-started/testing-your-agent/"
description="Write and run tests for your agent with Vitest."
/>

<LinkCard
title="Schedule tasks"
href="/agents/api-reference/schedule-tasks/"
description="Run tasks on a delay, schedule, or cron."
/>

<LinkCard
title="State management"
href="/agents/api-reference/store-and-sync-state/"
description="Deep dive into setState(), initialState, and onStateChanged()."
/>

<LinkCard
title="MCP servers"
href="/agents/api-reference/mcp-agent-api/"
description="Expose your agent's tools via the Model Context Protocol."
/>
Loading
Loading