diff --git a/public/_redirects b/public/_redirects index bf46e3e39fc8cc8..9f76cd33e2d172f 100644 --- a/public/_redirects +++ b/public/_redirects @@ -98,6 +98,15 @@ # agents /agents/build/prompts/ /workers/get-started/prompting/ 301 +/agents/examples/browse-the-web/ /agents/api-reference/browse-the-web/ 301 +/agents/examples/manage-and-sync-state/ /agents/api-reference/store-and-sync-state/ 301 +/agents/examples/rag/ /agents/api-reference/rag/ 301 +/agents/examples/run-workflows/ /agents/api-reference/run-workflows/ 301 +/agents/examples/schedule-tasks/ /agents/api-reference/schedule-tasks/ 301 +/agents/examples/using-ai-models/ /agents/api-reference/using-ai-models/ 301 +/agents/examples/websockets/ /agents/api-reference/websockets/ 301 +/agents/examples/sdk/ /agents/api-reference/agents-api/ 301 +/agents/examples/build-mcp-server/ /agents/api-reference/build-mcp-server/ 301 # ai /ai/ /use-cases/ai/ 301 diff --git a/src/assets/images/agents/npm-i-agents.apng b/src/assets/images/agents/npm-i-agents.apng new file mode 100644 index 000000000000000..bd246619482fc5b Binary files /dev/null and b/src/assets/images/agents/npm-i-agents.apng differ diff --git a/src/content/changelog/agents/2025-02-25-agents-sdk.mdx b/src/content/changelog/agents/2025-02-25-agents-sdk.mdx index b49a025a9280f50..26d5a5b4eca3c95 100644 --- a/src/content/changelog/agents/2025-02-25-agents-sdk.mdx +++ b/src/content/changelog/agents/2025-02-25-agents-sdk.mdx @@ -1,31 +1,31 @@ --- -title: Introducing the agents-sdk -description: Build and ship AI Agents on Cloudflare using the agents-sdk +title: Introducing the Agents SDK +description: Build and ship AI Agents on Cloudflare using the Agents SDK products: - agents - workers date: 2025-02-25T14:00:00Z --- -We've released the [agents-sdk](http://blog.cloudflare.com/build-ai-agents-on-cloudflare/), a package and set of tools that help you build and ship AI Agents. +We've released the [Agents SDK](http://blog.cloudflare.com/build-ai-agents-on-cloudflare/), a package and set of tools that help you build and ship AI Agents. -You can get up and running with a [chat-based AI Agent](https://github.com/cloudflare/agents-starter) (and deploy it to Workers) that uses the `agents-sdk`, tool calling, and state syncing with a React-based front-end by running the following command: +You can get up and running with a [chat-based AI Agent](https://github.com/cloudflare/agents-starter) (and deploy it to Workers) that uses the Agents SDK, tool calling, and state syncing with a React-based front-end by running the following command: ```sh npm create cloudflare@latest agents-starter -- --template="cloudflare/agents-starter" # open up README.md and follow the instructions ``` -You can also add an Agent to any existing Workers application by installing the `agents-sdk` package directly +You can also add an Agent to any existing Workers application by installing the `agents` package directly ```sh -npm i agents-sdk +npm i agents ``` ... and then define your first Agent: ```ts -import { Agent } from 'agents-sdk'; +import { Agent } from 'agents'; export class YourAgent extends Agent { // Build it out @@ -37,4 +37,4 @@ export class YourAgent extends Agent { } ``` -Head over to the [Agents documentation](/agents/) to learn more about the `agents-sdk`, the SDK APIs, as well as how to test and deploying agents to production. +Head over to the [Agents documentation](/agents/) to learn more about the Agents SDK, the SDK APIs, as well as how to test and deploying agents to production. diff --git a/src/content/changelog/agents/2025-03-18-npm-i-agents.mdx b/src/content/changelog/agents/2025-03-18-npm-i-agents.mdx new file mode 100644 index 000000000000000..72b1fcee555648d --- /dev/null +++ b/src/content/changelog/agents/2025-03-18-npm-i-agents.mdx @@ -0,0 +1,136 @@ +--- +title: npm i agents +description: Install the latest version of the `agents` SDK to build multi-agent applications, use the new RPC API, and visit the latest documentation updates. +products: + - agents + - workers +date: 2025-03-18T14:00:00Z +--- + +import { Badge, MetaInfo, Render, TypeScriptExample } from "~/components" +import { Image } from 'astro:assets'; +import npmAgentsAnimated from "~/assets/images/agents/npm-i-agents.apng" + +npm i agents + +#### `agents-sdk` -> `agents` + +📝 **We've renamed the Agents package to `agents`**! + +If you've already been building with the Agents SDK, you can update your dependencies to use the new package name, and replace references to `agents-sdk` with `agents`: + +```sh +# Install the new package +npm i agents +``` + +```sh +# Remove the old (deprecated) package +npm uninstall agents-sdk + +# Find instances of the old package name in your codebase +grep -r 'agents-sdk' . +# Replace instances of the old package name with the new one +# (or use find-replace in your editor) +sed -i 's/agents-sdk/agents/g' $(grep -rl 'agents-sdk' .) +``` + +All future updates will be pushed to the new `agents` package, and the older package has been marked as deprecated. + +#### Agents SDK updates + +We've added a number of big new features to the Agents SDK over the past few weeks, including: + +- You can now set `cors: true` when using `routeAgentRequest` to return permissive default CORS headers to Agent responses. +- The regular client now syncs state on the agent (just like the React version). +- `useAgentChat` bug fixes for passing headers/credentials, includng properly clearing cache on unmount. +- Experimental `/schedule` module with a prompt/schema for adding scheduling to your app (with evals!). +- Changed the internal `zod` schema to be compatible with the limitations of Google's Gemini models by removing the discriminated union, allowing you to use Gemini models with the scheduling API. + +We've also fixed a number of bugs with state synchronization and the React hooks. + + + +```ts +// via https://github.com/cloudflare/agents/tree/main/examples/cross-domain +export default { + async fetch(request: Request, env: Env) { + return ( + // Set { cors: true } to enable CORS headers. + (await routeAgentRequest(request, env, { cors: true })) || + new Response("Not found", { status: 404 }) + ); + }, +} satisfies ExportedHandler; +``` + + + +#### Call Agent methods from your client code + +We've added a new [`@unstable_callable()`](/agents/api-reference/agents-api/) decorator for defining methods that can be called directly from clients. This allows you call methods from within your client code: you can call methods (with arguments) and get native JavaScript objects back. + + + +```ts +// server.ts +import { unstable_callable, Agent, type StreamingResponse } from "agents"; +import type { Env } from "../server"; + + export class Rpc extends Agent { + // Use the decorator to define a callable method + @unstable_callable({ + description: "rpc test", + }) + async getHistory() { + return this.sql`SELECT * FROM history ORDER BY created_at DESC LIMIT 10`; + } +} +``` +```tsx +// client.tsx +const { call } = useAgent({ agent: "rpc" }); + +const fetchUserHistory = async () => { + try { + setLoading(true); + // Call methods directly on the Agent! + const result = await call("getHistory"); + addToast(`RPC result: ${result}`, "success"); + } catch (error) { + addToast(`Error: ${error}`, "error"); + } finally { + setLoading(false); + } +}; +``` + + + +#### agents-starter + +The [`agents-starter`](https://github.com/cloudflare/agents-starter) project — a real-time, chat-based example application with tool-calling & human-in-the-loop built using the Agents SDK — has seen the following updates: + +- Upgraded to use the latest [wrangler v4](/changelog/2025-03-13-wrangler-v4/) release. +- [Workers AI](/workers-ai/) is now the default AI provider in the [`agents-starter`](https://github.com/cloudflare/agents-starter) project: this uses the new [structured outputs](/changelog/2025-02-25-json-mode/) (or "JSON mode") support now in Workers AI and the [`workers-ai-provider`](https://sdk.vercel.ai/providers/community-providers/cloudflare-workers-ai#generateobject). + +If you're new to Agents, you can install and run the `agents-starter` project in two commands: + +```sh +# Install it +$ npm create cloudflare@latest agents-starter -- --template="cloudflare/agents-starter" +# Run it +$ npm run start +``` + +#### More documentation + +We've heard your feedback on the Agents SDK documentation, and we're shipping more API reference material and usage examples, including: + +- Expanded [API reference documentation](/agents/api-reference/), covering the methods and properties exposed by the Agents SDK, as well as more usage examples. +- More [Client API](/agents/api-reference/agents-api/#client-api) documentation that documents `useAgent`, `useAgentChat` and the new `@unstable_callable` RPC decorator exposed by the SDK. +- New documentation on how to [call agents](/agents/api-reference/calling-agents/) and (optionally) authenticate clients before they connect to your Agents. + +Note that the Agents SDK is continually growing: the type definitions included in the SDK will always include the latest APIs exposed by the `agents` package. + +If you're still wondering what Agents are, [read our blog on building AI Agents on Cloudflare](https://blog.cloudflare.com/build-ai-agents-on-cloudflare/) and/or visit the [Agents documentation](/agents/) to learn more. diff --git a/src/content/docs/agents/api-reference/agents-api.mdx b/src/content/docs/agents/api-reference/agents-api.mdx new file mode 100644 index 000000000000000..c111050094f8404 --- /dev/null +++ b/src/content/docs/agents/api-reference/agents-api.mdx @@ -0,0 +1,955 @@ +--- +title: Agents API +pcx_content_type: concept +sidebar: + order: 1 +--- + +import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; + +This page provides an overview of the Agent SDK API, including the `Agent` class, methods and properties built-in to the Agents SDK. + +The Agents SDK exposes two main APIs: + +* The server-side `Agent` class. An Agent encapsulates all of the logic for an Agent, including how clients can connect to it, how it stores state, the methods it exposes, how to call AI models, and any error handling. +* The client-side `AgentClient` class, which allows you to connect to an Agent instance from a client-side application. The client APIs also include React hooks, including `useAgent` and `useAgentChat`, and allow you to automatically synchronize state between each unique Agent (running server-side) and your client applications. + +You can also find more specific usage examples for each API in the [Agents API Reference](/agents/api-reference/). + + + +```ts +import { Agent } from "agents"; + +class MyAgent extends Agent { + // Define methods on the Agent +} + +export default MyAgent; +``` + + + +An Agent can have many (millions of) instances: each instance is a separate micro-server that runs independently of the others. This allows Agents to scale horizontally: an Agent can be associated with a single user, or many thousands of users, depending on the agent you're building. + +Instances of an Agent are addressed by a unique identifier: that identifier (ID) can be the user ID, an email address, GitHub username, a flight ticket number, an invoice ID, or any other identifier that helps to uniquely identify the instance and for whom it is acting on behalf of. + + + +### Agent class API + +Writing an Agent requires you to define a class that extends the `Agent` class from the Agents SDK package. An Agent encapsulates all of the logic for an Agent, including how clients can connect to it, how it stores state, the methods it exposes, and any error handling. + +You can also define your own methods on an Agent: it's technically valid to publish an Agent only has your own methods exposed, and create/get Agents directly from a Worker. + +Your own methods can access the Agent's environment variables and bindings on `this.env`, state on `this.setState`, and call other methods on the Agent via `this.yourMethodName`. + +```ts +import { Agent } from "agents"; + +interface Env { + // Define environment variables & bindings here +} + +// Pass the Env as a TypeScript type argument +// Any services connected to your Agent or Worker as Bindings +// are then available on this.env. + +// The core class for creating Agents that can maintain state, orchestrate +// complex AI workflows, schedule tasks, and interact with users and other +// Agents. +class MyAgent extends Agent { + // Optional initial state definition + initialState = { + counter: 0, + messages: [], + lastUpdated: null + }; + + // Called when a new Agent instance starts or wakes from hibernation + async onStart() { + console.log('Agent started with state:', this.state); + } + + // Handle HTTP requests coming to this Agent instance + // Returns a Response object + async onRequest(request: Request): Promise { + return new Response("Hello from Agent!"); + } + + // Called when a WebSocket connection is established + // Access the original request via ctx.request for auth etc. + async onConnect(connection: Connection, ctx: ConnectionContext) { + // Connections are automatically accepted by the SDK. + // You can also explicitly close a connection here with connection.close() + // Access the Request on ctx.request to inspect headers, cookies and the URL + } + + // Called for each message received on a WebSocket connection + // Message can be string, ArrayBuffer, or ArrayBufferView + async onMessage(connection: Connection, message: WSMessage) { + // Handle incoming messages + connection.send("Received your message"); + } + + // Handle WebSocket connection errors + async onError(connection: Connection, error: unknown): Promise { + console.error(`Connection error:`, error); + } + + // Handle WebSocket connection close events + async onClose(connection: Connection, code: number, reason: string, wasClean: boolean): Promise { + console.log(`Connection closed: ${code} - ${reason}`); + } + + // Called when the Agent's state is updated from any source + // source can be "server" or a client Connection + onStateUpdate(state: State, source: "server" | Connection) { + console.log("State updated:", state, "Source:", source); + } + + // You can define your own custom methods to be called by requests, + // WebSocket messages, or scheduled tasks + async customProcessingMethod(data: any) { + // Process data, update state, schedule tasks, etc. + this.setState({ ...this.state, lastUpdated: new Date() }); + } +} +``` + + + +```ts +// Basic Agent implementation with custom methods +import { Agent } from "agents"; + +interface MyState { + counter: number; + lastUpdated: Date | null; +} + +class MyAgent extends Agent { + initialState = { + counter: 0, + lastUpdated: null + }; + + async onRequest(request: Request) { + if (request.method === "POST") { + await this.incrementCounter(); + return new Response(JSON.stringify(this.state), { + headers: { "Content-Type": "application/json" } + }); + } + return new Response(JSON.stringify(this.state), { + headers: { "Content-Type": "application/json" } + }); + } + + async incrementCounter() { + this.setState({ + counter: this.state.counter + 1, + lastUpdated: new Date() + }); + } +} +``` + + + +### WebSocket API + +The WebSocket API allows you to accept and manage WebSocket connections made to an Agent. + +#### Connection + +Represents a WebSocket connection to an Agent. + +```ts +// WebSocket connection interface +interface Connection { + // Unique ID for this connection + id: string; + + // Client-specific state attached to this connection + state: State; + + // Update the connection's state + setState(state: State): void; + + // Accept an incoming WebSocket connection + accept(): void; + + // Close the WebSocket connection with optional code and reason + close(code?: number, reason?: string): void; + + // Send a message to the client + // Can be string, ArrayBuffer, or ArrayBufferView + send(message: string | ArrayBuffer | ArrayBufferView): void; +} +``` + + + +```ts +// Example of handling WebSocket messages +export class YourAgent extends Agent { + async onMessage(connection: Connection, message: WSMessage) { + if (typeof message === 'string') { + try { + // Parse JSON message + const data = JSON.parse(message); + + if (data.type === 'update') { + // Update connection-specific state + connection.setState({ ...connection.state, lastActive: Date.now() }); + + // Update global Agent state + this.setState({ + ...this.state, + connections: this.state.connections + 1 + }); + + // Send response back to this client only + connection.send(JSON.stringify({ + type: 'updated', + status: 'success' + })); + } + } catch (e) { + connection.send(JSON.stringify({ error: 'Invalid message format' })); + } + } + } +} +``` + + + +#### WSMessage + +Types of messages that can be received from a WebSocket. + +```ts +// Types of messages that can be received from WebSockets +type WSMessage = string | ArrayBuffer | ArrayBufferView; +``` + +#### ConnectionContext + +Context information for a WebSocket connection. + +```ts +// Context available during WebSocket connection +interface ConnectionContext { + // The original HTTP request that initiated the WebSocket connection + request: Request; +} +``` + +### State synchronization API + +:::note + +To learn more about how to manage state within an Agent, refer to the documentation on [managing and syncing state](/agents/api-reference/store-and-sync-state/). + +::: + +#### State + +Methods and types for managing Agent state. + +```ts +// State management in the Agent class +class Agent { + // Initial state that will be set if no state exists yet + initialState: State = {} as unknown as State; + + // Current state of the Agent, persisted across restarts + get state(): State; + + // Update the Agent's state + // Persists to storage and notifies all connected clients + setState(state: State): void; + + // Called when state is updated from any source + // Override to react to state changes + onStateUpdate(state: State, source: "server" | Connection): void; +} +``` + + + +```ts +// Example of state management in an Agent +interface ChatState { + messages: Array<{ sender: string; text: string; timestamp: number }>; + participants: string[]; + settings: { + allowAnonymous: boolean; + maxHistoryLength: number; + }; +} + +interface Env { + // Your bindings and environment variables +} + +// Inside your Agent class +export class YourAgent extends Agent { + async addMessage(sender: string, text: string) { + // Update state with new message + this.setState({ + ...this.state, + messages: [ + ...this.state.messages, + { sender, text, timestamp: Date.now() } + ].slice(-this.state.settings.maxHistoryLength) // Maintain max history + }); + + // The onStateUpdate method will automatically be called + // and all connected clients will receive the update + } + + // Override onStateUpdate to add custom behavior when state changes + onStateUpdate(state: ChatState, source: "server" | Connection) { + console.log(`State updated by ${source === "server" ? "server" : "client"}`); + + // You could trigger additional actions based on state changes + if (state.messages.length > 0) { + const lastMessage = state.messages[state.messages.length - 1]; + if (lastMessage.text.includes('@everyone')) { + this.notifyAllParticipants(lastMessage); + } + } + } +} +``` + + + +### Scheduling API + +#### Scheduling tasks + +Schedule tasks to run at a specified time in the future. + +```ts +// Scheduling API for running tasks in the future +class Agent { + // Schedule a task to run in the future + // when: seconds from now, specific Date, or cron expression + // callback: method name on the Agent to call + // payload: data to pass to the callback + // Returns a Schedule object with the task ID + async schedule( + when: Date | string | number, + callback: keyof this, + payload?: T + ): Promise>; + + // Get a scheduled task by ID + // Returns undefined if the task doesn't exist + async getSchedule(id: string): Promise | undefined>; + + // Get all scheduled tasks matching the criteria + // Returns an array of Schedule objects + getSchedules(criteria?: { + description?: string; + id?: string; + type?: "scheduled" | "delayed" | "cron"; + timeRange?: { start?: Date; end?: Date }; + }): Schedule[]; + + // Cancel a scheduled task by ID + // Returns true if the task was cancelled, false otherwise + async cancelSchedule(id: string): Promise; +} +``` + + + +```ts +// Example of scheduling in an Agent +interface ReminderData { + userId: string; + message: string; + channel: string; +} + +export class YourAgent extends Agent { + // Schedule a one-time reminder in 2 hours + async scheduleReminder(userId: string, message: string) { + const twoHoursFromNow = new Date(Date.now() + 2 * 60 * 60 * 1000); + + const schedule = await this.schedule( + twoHoursFromNow, + 'sendReminder', + { userId, message, channel: 'email' } + ); + + console.log(`Scheduled reminder with ID: ${schedule.id}`); + return schedule.id; + } + + // Schedule a recurring daily task using cron + async scheduleDailyReport() { + // Run at 08:00 AM every day + const schedule = await this.schedule( + '0 8 * * *', // Cron expression: minute hour day month weekday + 'generateDailyReport', + { reportType: 'daily-summary' } + ); + + console.log(`Scheduled daily report with ID: ${schedule.id}`); + return schedule.id; + } + + // Method that will be called when the scheduled task runs + async sendReminder(data: ReminderData) { + console.log(`Sending reminder to ${data.userId}: ${data.message}`); + // Add code to send the actual notification + } +} +``` + + + +#### Schedule object + +Represents a scheduled task. + +```ts +// Represents a scheduled task +type Schedule = { + // Unique identifier for the schedule + id: string; + // Name of the method to be called + callback: string; + // Data to be passed to the callback + payload: T; +} & ( + | { + // One-time execution at a specific time + type: "scheduled"; + // Timestamp when the task should execute + time: number; + } + | { + // Delayed execution after a certain time + type: "delayed"; + // Timestamp when the task should execute + time: number; + // Number of seconds to delay execution + delayInSeconds: number; + } + | { + // Recurring execution based on cron expression + type: "cron"; + // Timestamp for the next execution + time: number; + // Cron expression defining the schedule + cron: string; + } +); +``` + + + +```ts +export class YourAgent extends Agent { + // Example of managing scheduled tasks + async viewAndManageSchedules() { + // Get all scheduled tasks + const allSchedules = this.getSchedules(); + console.log(`Total scheduled tasks: ${allSchedules.length}`); + + // Get tasks scheduled for a specific time range + const upcomingSchedules = this.getSchedules({ + timeRange: { + start: new Date(), + end: new Date(Date.now() + 24 * 60 * 60 * 1000) // Next 24 hours + } + }); + + // Get a specific task by ID + const taskId = "task-123"; + const specificTask = await this.getSchedule(taskId); + + if (specificTask) { + console.log(`Found task: ${specificTask.callback} at ${new Date(specificTask.time)}`); + + // Cancel a scheduled task + const cancelled = await this.cancelSchedule(taskId); + console.log(`Task cancelled: ${cancelled}`); + } + } +} +``` + + + +### SQL API + +Each Agent instance has an embedded SQLite database that can be accessed using the `this.sql` method within any method on your `Agent` class. + +#### SQL queries + +Execute SQL queries against the Agent's built-in SQLite database using the `this.sql` method within any method on your `Agent` class. + +```ts +// SQL query API for the Agent's embedded database +class Agent { + // Execute a SQL query with tagged template literals + // Returns an array of rows matching the query + sql>( + strings: TemplateStringsArray, + ...values: (string | number | boolean | null)[] + ): T[]; +} +``` + + + +```ts +// Example of using SQL in an Agent +interface User { + id: string; + name: string; + email: string; + created_at: number; +} + +export class YourAgent extends Agent { + async setupDatabase() { + // Create a table if it doesn't exist + this.sql` + CREATE TABLE IF NOT EXISTS users ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + email TEXT UNIQUE, + created_at INTEGER + ) + `; + } + + async createUser(id: string, name: string, email: string) { + // Insert a new user + this.sql` + INSERT INTO users (id, name, email, created_at) + VALUES (${id}, ${name}, ${email}, ${Date.now()}) + `; + } + + async getUserById(id: string): Promise { + // Query a user by ID + const users = this.sql` + SELECT * FROM users WHERE id = ${id} + `; + + return users.length ? users[0] : null; + } + + async searchUsers(term: string): Promise { + // Search users with a wildcard + return this.sql` + SELECT * FROM users + WHERE name LIKE ${'%' + term + '%'} OR email LIKE ${'%' + term + '%'} + ORDER BY created_at DESC + `; + } +} +``` + + + +:::note + +Visit the [state management API documentation](/agents/api-reference/store-and-sync-state/) within the Agents SDK, including the native `state` APIs and the built-in `this.sql` API for storing and querying data within your Agents. + +::: + + +### Client API + +The Agents SDK provides a set of client APIs for interacting with Agents from client-side JavaScript code, including: + +* React hooks, including `useAgent` and `useAgentChat`, for connecting to Agents from client applications. +* Client-side [state syncing](/agents/api-reference/store-and-sync-state/) that allows you to subscribe to state updates between the Agent and any connected client(s) when calling `this.setState` within your Agent's code. +* The ability to call remote methods (Remote Procedure Calls; RPC) on the Agent from client-side JavaScript code using the `@callable` method decorator. + +#### AgentClient + +Client for connecting to an Agent from the browser. + +```ts +import { AgentClient } from "agents/client"; + +// Options for creating an AgentClient +type AgentClientOptions = Omit & { + // Name of the agent to connect to (class name in kebab-case) + agent: string; + // Name of the specific Agent instance (optional, defaults to "default") + name?: string; + // Other WebSocket options like host, protocol, etc. +}; + +// WebSocket client for connecting to an Agent +class AgentClient extends PartySocket { + static fetch(opts: PartyFetchOptions): Promise; + constructor(opts: AgentClientOptions); +} +``` + + + +```ts +// Example of using AgentClient in the browser +import { AgentClient } from "agents/client"; + +// Connect to an Agent instance +const socket = new AgentClient({ + agent: "chat-agent", // Name of your Agent class in kebab-case + name: "support-room-123", // Specific instance name + + // Optional event handlers + onOpen: () => { + console.log("Connected to agent"); + // Send an initial message + socket.send(JSON.stringify({ type: "join", user: "user123" })); + }, + + onMessage: (event) => { + // Handle incoming messages + const data = JSON.parse(event.data); + console.log("Received:", data); + + if (data.type === "state_update") { + // Update local UI with new state + updateUI(data.state); + } + }, + + onClose: () => console.log("Disconnected from agent") +}); + +// Send messages to the Agent +function sendMessage(text) { + socket.send(JSON.stringify({ + type: "message", + text, + timestamp: Date.now() + })); +} +``` + + + +#### agentFetch + +Make an HTTP request to an Agent. + +```ts +import { agentFetch } from "agents/client"; + +// Options for the agentFetch function +type AgentClientFetchOptions = Omit & { + // Name of the agent to connect to + agent: string; + // Name of the specific Agent instance (optional) + name?: string; +}; + +// Make an HTTP request to an Agent +function agentFetch( + opts: AgentClientFetchOptions, + init?: RequestInit +): Promise; +``` + + + +```ts +// Example of using agentFetch in the browser +import { agentFetch } from "agents/client"; + +// Function to get data from an Agent +async function fetchAgentData() { + try { + const response = await agentFetch( + { + agent: "task-manager", + name: "user-123-tasks" + }, + { + method: "GET", + headers: { + "Authorization": `Bearer ${userToken}` + } + } + ); + + if (!response.ok) { + throw new Error(`Error: ${response.status}`); + } + + const data = await response.json(); + return data; + } catch (error) { + console.error("Failed to fetch from agent:", error); + } +} +``` + + + +### React API + +The Agents SDK provides a React API for simplifying connection and routing to Agents from front-end frameworks, including React Router (Remix), Next.js, and Astro. + +#### useAgent + +React hook for connecting to an Agent. + +```ts +import { useAgent } from "agents/react"; + +// Options for the useAgent hook +type UseAgentOptions = Omit< + Parameters[0], + "party" | "room" +> & { + // Name of the agent to connect to + agent: string; + // Name of the specific Agent instance (optional) + name?: string; + // Called when the Agent's state is updated + onStateUpdate?: (state: State, source: "server" | "client") => void; +}; + +// React hook for connecting to an Agent +// Returns a WebSocket connection with setState method +function useAgent( + options: UseAgentOptions +): PartySocket & { + // Update the Agent's state + setState: (state: State) => void +}; +``` + +### Chat Agent + +The Agents SDK exposes an `AIChatAgent` class that extends the `Agent` class and exposes an `onChatMessage` method that simplifies building interactive chat agents. + +You can combine this with the `useAgentChat` React hook from the `agents/ai-react` package to manage chat state and messages between a user and your Agent(s). + +#### AIChatAgent + +Extension of the `Agent` class with built-in chat capabilities. + +```ts +import { AIChatAgent } from "agents/ai-chat-agent"; +import { Message, StreamTextOnFinishCallback, ToolSet } from "ai"; + +// Base class for chat-specific agents +class AIChatAgent extends Agent { + // Array of chat messages for the current conversation + messages: Message[]; + + // Handle incoming chat messages and generate a response + // onFinish is called when the response is complete + async onChatMessage( + onFinish: StreamTextOnFinishCallback + ): Promise; + + // Persist messages within the Agent's local storage. + async saveMessages(messages: Message[]): Promise; +} +``` + + + +```ts +// Example of extending AIChatAgent +import { AIChatAgent } from "agents/ai-chat-agent"; +import { Message } from "ai"; + +interface Env { + AI: any; // Your AI binding +} + +class CustomerSupportAgent extends AIChatAgent { + // Override the onChatMessage method to customize behavior + async onChatMessage(onFinish) { + // Access the AI models using environment bindings + const { openai } = this.env.AI; + + // Get the current conversation history + const chatHistory = this.messages; + + // Generate a system prompt based on knowledge base + const systemPrompt = await this.generateSystemPrompt(); + + // Generate a response stream + const stream = await openai.chat({ + model: "gpt-4o", + messages: [ + { role: "system", content: systemPrompt }, + ...chatHistory + ], + stream: true + }); + + // Return the streaming response + return new Response(stream, { + headers: { "Content-Type": "text/event-stream" } + }); + } + + // Helper method to generate a system prompt + async generateSystemPrompt() { + // Query knowledge base or use static prompt + return `You are a helpful customer support agent. + Respond to customer inquiries based on the following guidelines: + - Be friendly and professional + - If you don't know an answer, say so + - Current company policies: ...`; + } +} +``` + + + +### Chat Agent React API + +#### useAgentChat + +React hook for building AI chat interfaces using an Agent. + +```ts +import { useAgentChat } from "agents/ai-react"; +import { useAgent } from "agents/react"; +import type { Message } from "ai"; + +// Options for the useAgentChat hook +type UseAgentChatOptions = Omit< + Parameters[0] & { + // Agent connection from useAgent + agent: ReturnType; + }, + "fetch" +>; + +// React hook for building AI chat interfaces using an Agent +function useAgentChat(options: UseAgentChatOptions): { + // Current chat messages + messages: Message[]; + // Set messages and synchronize with the Agent + setMessages: (messages: Message[]) => void; + // Clear chat history on both client and Agent + clearHistory: () => void; + // Append a new message to the conversation + append: (message: Message, chatRequestOptions?: any) => Promise; + // Reload the last user message + reload: (chatRequestOptions?: any) => Promise; + // Stop the AI response generation + stop: () => void; + // Current input text + input: string; + // Set the input text + setInput: React.Dispatch>; + // Handle input changes + handleInputChange: (e: React.ChangeEvent) => void; + // Submit the current input + handleSubmit: (event?: { preventDefault?: () => void }, chatRequestOptions?: any) => void; + // Additional metadata + metadata?: Object; + // Whether a response is currently being generated + isLoading: boolean; + // Current status of the chat + status: "submitted" | "streaming" | "ready" | "error"; + // Tool data from the AI response + data?: any[]; + // Set tool data + setData: (data: any[] | undefined | ((data: any[] | undefined) => any[] | undefined)) => void; + // Unique ID for the chat + id: string; + // Add a tool result for a specific tool call + addToolResult: ({ toolCallId, result }: { toolCallId: string; result: any }) => void; + // Current error if any + error: Error | undefined; +}; +``` + + + +```tsx +// Example of using useAgentChat in a React component +import { useAgentChat } from "agents/ai-react"; +import { useAgent } from "agents/react"; +import { useState } from "react"; + +function ChatInterface() { + // Connect to the chat agent + const agentConnection = useAgent({ + agent: "customer-support", + name: "session-12345" + }); + + // Use the useAgentChat hook with the agent connection + const { + messages, + input, + handleInputChange, + handleSubmit, + isLoading, + error, + clearHistory + } = useAgentChat({ + agent: agentConnection, + initialMessages: [ + { role: "system", content: "You're chatting with our AI assistant." }, + { role: "assistant", content: "Hello! How can I help you today?" } + ] + }); + + return ( +
+
+ {messages.map((message, i) => ( +
+ {message.role === 'user' ? '👤' : '🤖'} {message.content} +
+ ))} + + {isLoading &&
AI is typing...
} + {error &&
Error: {error.message}
} +
+ +
+ + + +
+
+ ); +} +``` + +
+ + +### Next steps + +* [Build a chat Agent](/agents/getting-started/build-a-chat-agent/) using the Agents SDK and deploy it to Workers. +* Learn more [using WebSockets](/agents/api-reference/websockets/) to build interactive Agents and stream data back from your Agent. +* [Orchestrate asynchronous workflows](/agents/api-reference/run-workflows) from your Agent by combining the Agents SDK and [Workflows](/workflows). diff --git a/src/content/docs/agents/examples/browse-the-web.mdx b/src/content/docs/agents/api-reference/browse-the-web.mdx similarity index 99% rename from src/content/docs/agents/examples/browse-the-web.mdx rename to src/content/docs/agents/api-reference/browse-the-web.mdx index 703759ceb989095..689b856339b5e3d 100644 --- a/src/content/docs/agents/examples/browse-the-web.mdx +++ b/src/content/docs/agents/api-reference/browse-the-web.mdx @@ -2,7 +2,7 @@ title: Browse the web pcx_content_type: concept sidebar: - order: 99 + order: 7 --- import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; diff --git a/src/content/docs/agents/api-reference/calling-agents.mdx b/src/content/docs/agents/api-reference/calling-agents.mdx new file mode 100644 index 000000000000000..7bc38dccc1ee130 --- /dev/null +++ b/src/content/docs/agents/api-reference/calling-agents.mdx @@ -0,0 +1,266 @@ +--- +title: Calling Agents +pcx_content_type: concept +sidebar: + order: 2 + +--- + +import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; + +Learn how to call your Agents from Workers, including how to create Agents on-the-fly, address them, and route requests to specific instances of an Agent. + +### Calling your Agent + +Agents are created on-the-fly and can serve multiple requests concurrently. Each Agent instance is isolated from other instances, can maintain its own state, and has a unique address. + + + +You can create and run an instance of an Agent directly from a Worker using either: + +* The `routeAgentRequest` helper: this will automatically map requests to an individual Agent based on the `/agents/:agent/:name` URL pattern. The value of `:agent` will be the name of your Agent class converted to `kebab-case`, and the value of `:name` will be the name of the Agent instance you want to create or retrieve. +* `getAgentByName`, which will create a new Agent instance if none exists by that name, or retrieve a handle to an existing instance. + +See the usage patterns in the following example: + + + +```ts +import { Agent, AgentNamespace, getAgentByName, routeAgentRequest } from 'agents'; + +interface Env { + // Define your Agent on the environment here + // Passing your Agent class as a TypeScript type parameter allows you to call + // methods defined on your Agent. + MyAgent: AgentNamespace; +} + +export default { + async fetch(request, env, ctx): Promise { + // Routed addressing + // Automatically routes HTTP requests and/or WebSocket connections to /agents/:agent/:name + // Best for: connecting React apps directly to Agents using useAgent from agents/react + return (await routeAgentRequest(request, env)) || Response.json({ msg: 'no agent here' }, { status: 404 }); + + // Named addressing + // Best for: convenience method for creating or retrieving an agent by name/ID. + // Bringing your own routing, middleware and/or plugging into an existing + // application or framework. + let namedAgent = getAgentByName(env.MyAgent, 'my-unique-agent-id'); + // Pass the incoming request straight to your Agent + let namedResp = (await namedAgent).fetch(request); + return namedResp + }, +} satisfies ExportedHandler; + +export class MyAgent extends Agent { + // Your Agent implementation goes here +} +``` + + +#### Calling methods directly + +When using `getAgentByName`, you can pass both requests (including WebSocket) connections and call methods defined directly on the Agent itself using the native [JavaScript RPC](/workers/runtime-apis/rpc/) (JSRPC) API. + +For example, once you have a handle (or "stub") to an unique instance of your Agent, you can call methods on it: + + + +```ts +import { Agent, AgentNamespace, getAgentByName } from 'agents'; + +interface Env { + // Define your Agent on the environment here + // Passing your Agent class as a TypeScript type parameter allows you to call + // methods defined on your Agent. + MyAgent: AgentNamespace; +} + +interface UserHistory { + history: string[]; + lastUpdated: Date; +} + +export default { + async fetch(request, env, ctx): Promise { + let namedAgent = getAgentByName(env.MyAgent, 'my-unique-agent-id'); + // Call methods directly on the Agent, and pass native JavaScript objects + let chatResponse = namedAgent.chat('Hello!'); + // No need to serialize/deserialize it from a HTTP request or WebSocket + // message and back again + let agentState = getState() // agentState is of type UserHistory + return namedResp + }, +} satisfies ExportedHandler; + +export class MyAgent extends Agent { + // Your Agent implementation goes here + async chat(prompt: string) { + // call your favorite LLM + return "result" + } + + async getState() { + // Return the Agent's state directly + return this.state; + } + + // Other methods as you see fit! +} +``` + + +When using TypeScript, ensure you pass your Agent class as a TypeScript type parameter to the AgentNamespace type so that types are correctly inferred: + +```ts +interface Env { + // Passing your Agent class as a TypeScript type parameter allows you to call + // methods defined on your Agent. + MyAgent: AgentNamespace; +} + +export class CodeReviewAgent extends Agent { + // Agent methods here +} +``` + +### Naming your Agents + +When creating names for your Agents, think about what the Agent represents. A unique user? A team or company? A room or channel for collaboration? + +A consistent approach to naming allows you to: + +* direct incoming requests directly to the right Agent +* deterministically route new requests back to that Agent, no matter where the client is in the world. +* avoid having to rely on centralized session storage or external services for state management, since each Agent instance can maintain its own state. + +For a given Agent definition (or 'namespace' in the code below), there can be millions (or tens of millions) of instances of that Agent, each handling their own requests, making calls to LLMs, and maintaining their own state. + +For example, you might have an Agent for every user using your new AI-based code editor. In that case, you'd want to create Agents based on the user ID from your system, which would then allow that Agent to handle all requests for that user. + +It also ensures that [state within the Agent](/agents/api-reference/store-and-sync-state/), including chat history, language preferences, model configuration and other context can associated specifically with that user, making it easier to manage state. + +The example below shows how to create a unique agent Agent for each `userId` in a request: + + + +```ts +import { Agent, AgentNamespace, getAgentByName, routeAgentRequest } from 'agents'; + +interface Env { + MyAgent: AgentNamespace; +} + +export default { + async fetch(request, env, ctx): Promise { + let userId = new URL(request.url).searchParams.get('userId') || 'anonymous'; + // Use an identifier that allows you to route to requests, WebSockets or call methods on the Agent + // You can also put authentication logic here - e.g. to only create or retrieve Agents for known users. + let namedAgent = getAgentByName(env.MyAgent, 'my-unique-agent-id'); + return (await namedAgent).fetch(request); + }, +} satisfies ExportedHandler; + +export class MyAgent extends Agent { + // You can access the name of the agent via this.name in any method within + // the Agent + async onStartup() { console.log(`agent ${this.name} ready!`)} +} +``` + + +Replace `userId` with `teamName`, `channel`, `companyName` as fits your Agents goals - and/or configure authentication to ensure Agents are only created for known, authenticated users. + +### Authenticating Agents + +When building and deploying Agents using the Agents SDK, you will often want to authenticate clients before passing requests to an Agent in order to restrict who the Agent will call, authorize specific users for specific Agents, and/or to limit who can access administrative or debug APIs exposed by an Agent. + +As best practices: + +* Handle authentication in your Workers code, before you invoke your Agent. +* Use the built-in hooks when using the `routeAgentRequest` helper - `onBeforeConnect` and `onBeforeRequest` +* Use your preferred router (such as Hono) and authentication middleware or provider to apply custom authentication schemes before calling an Agent using other methods. + +The `routeAgentRequest` helper documented earlier in this guide exposes two useful hooks (`onBeforeConnect`, `onBeforeRequest`) that allow you to apply custom logic before creating or retrieving an Agent: + + + +```ts +import { Agent, AgentNamespace, routeAgentRequest } from 'agents'; + +interface Env { + MyAgent: AgentNamespace; +} + +export default { + async fetch(request, env, ctx): Promise { + // Use the onBeforeConnect and onBeforeRequest hooks to authenticate clients + // or run logic before handling a HTTP request or WebSocket. + return ( + (await routeAgentRequest(request, env, { + // Run logic before a WebSocket client connects + onBeforeConnect: (request) => { + // Your code/auth code here + // You can return a Response here - e.g. a HTTP 403 Not Authorized - + // which will stop further request processing and will NOT invoke the + // Agent. + // return Response.json({"error": "not authorized"}, { status: 403 }) + }, + // Run logic before a HTTP client clients + onBeforeRequest: (request) => { + // Your code/auth code here + // Returning nothing will result in the call to the Agent continuing + }, + // Prepend a prefix for how your Agents are named here + prefix: 'name-prefix-here', + })) || Response.json({ msg: 'no agent here' }, { status: 404 }) + ); + + }, +} satisfies ExportedHandler; +``` + + +If you are using `getAgentByName` or the underlying Durable Objects routing API, you should authenticate incoming requests or WebSocket connections before calling `getAgentByName`. + +For example, if you are using [Hono](https://hono.dev/), you can authenticate in the middleware before calling an Agent and passing a request (or a WebSocket connection) to it: + + + +```ts +import { Agent, AgentNamespace, getAgentByName } from 'agents'; +import { Hono } from 'hono'; + +const app = new Hono<{ Bindings: Env }>(); + +app.use('/code-review/*', async (c, next) => { + // Perform auth here + // e.g. validate a Bearer token, a JWT, use your preferred auth library + // return Response.json({ msg: 'unauthorized' }, { status: 401 }); + await next(); // continue on if valid +}); + +app.get('/code-review/:id', async (c) => { + const id = c.req.param('teamId'); + if (!id) return Response.json({ msg: 'missing id' }, { status: 400 }); + + // Call the Agent, creating it with the name/identifier from the ":id" segment + // of our URL + const agent = await getAgentByName(c.env.MyAgent, id); + + // Pass the request to our Agent instance + return await agent.fetch(c.req.raw); +}); +``` + + + +This ensures we only create Agents for authenticated users, and allows you to validate whether Agent names conform to your preferred naming scheme before instances are created. + +### Next steps + +* Review the [API documentation](/agents/api-reference/agents-api/) for the Agents class to learn how to define +* [Build a chat Agent](/agents/getting-started/build-a-chat-agent/) using the Agents SDK and deploy it to Workers. +* Learn more [using WebSockets](/agents/api-reference/websockets/) to build interactive Agents and stream data back from your Agent. +* [Orchestrate asynchronous workflows](/agents/api-reference/run-workflows) from your Agent by combining the Agents SDK and [Workflows](/workflows). diff --git a/src/content/docs/agents/api-reference/configuration.mdx b/src/content/docs/agents/api-reference/configuration.mdx index b11bab3291ffe46..79426eac85ff2cb 100644 --- a/src/content/docs/agents/api-reference/configuration.mdx +++ b/src/content/docs/agents/api-reference/configuration.mdx @@ -2,13 +2,15 @@ title: Configuration pcx_content_type: concept sidebar: - order: 3 + order: 100 --- import { MetaInfo, Render, Type, WranglerConfig } from "~/components"; An Agent is configured like any other Cloudflare Workers project, and uses [a wrangler configuration](/workers/wrangler/configuration/) file to define where your code is and what services (bindings) it will use. +### Project structure + The typical file structure for an Agent project created from `npm create cloudflare@latest agents-starter -- --template cloudflare/agents-starter` follows: ```sh @@ -28,6 +30,8 @@ The typical file structure for an Agent project created from `npm create cloudfl `-- wrangler.jsonc // your Workers & Agent configuration ``` +### Example configuration + Below is a minimal `wrangler.jsonc` file that defines the configuration for an Agent, including the entry point, `durable_object` namespace, and code `migrations`: @@ -70,3 +74,5 @@ The configuration includes: - A `main` field that points to the entry point of your Agent, which is typically a TypeScript (or JavaScript) file. - A `durable_objects` field that defines the [Durable Object namespace](/durable-objects/reference/glossary/) that your Agents will run within. - A `migrations` field that defines the code migrations that your Agent will use. This field is mandatory and must contain at least one migration. The `new_sqlite_classes` field is mandatory for the Agent to store state. + +Agents must define these fields in their `wrangler.jsonc` (or `wrangler.toml`) config file. diff --git a/src/content/docs/agents/api-reference/http-sse.mdx b/src/content/docs/agents/api-reference/http-sse.mdx new file mode 100644 index 000000000000000..ef5916c26d340af --- /dev/null +++ b/src/content/docs/agents/api-reference/http-sse.mdx @@ -0,0 +1,114 @@ +--- +title: HTTP and Server-Sent Events +pcx_content_type: concept +sidebar: + order: 8 + +--- + +import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; + +The Agents SDK allows you to handle HTTP requests and has native support for [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE). This allows you build applications that can push data to clients and avoid buffering. + +### Handling HTTP requests + +Agents can handle HTTP requests using the `onRequest` method, which is called whenever an HTTP request is received by the Agent instance. The method takes a `Request` object as a parameter and returns a `Response` object. + + + +```ts +class MyAgent extends Agent { + // Handle HTTP requests coming to this Agent instance + // Returns a Response object + async onRequest(request: Request) { + return new Response("Hello from Agent!"); + } + + async callAIModel(prompt: string) { + // Implement AI model call here + } +} +``` + + + +Review the [Agents API reference](/agents/api-reference/agents-api/) to learn more about the `Agent` class and its methods. + +### Implementing Server-Sent Events + +The Agents SDK support Server-Sent Events directly: you can use SSE to stream data back to the client over a long running connection. This avoids buffering large responses, which can both make your Agent feel slow, and forces you to buffer the entire response in memory. + +When an Agent is deployed to Cloudflare Workers, there is no effective limit on the total time it takes to stream the response back: large AI model responses that take several minutes to reason and then respond will not be prematurely terminated. + +Note that this does not mean the client can't potentially disconnect during the streaming process: you can account for this by either [writing to the Agent's stateful storage](/agents/api-reference/store-and-sync-state/) and/or [using WebSockets](/agents/api-reference/websockets/). Because you can always [route to the same Agent](/agents/api-reference/calling-agents/), you do not need to use a centralized session store to pick back up where you left off when a client disconnects. + +The following example uses the AI SDK to generate text and stream it back to the client. It will automatically stream the response back to the client as the model generates it: + + + +```ts +import { Agent, AgentNamespace, getAgentByName, routeAgentRequest } from 'agents'; +import { streamText } from 'ai'; +import { createOpenAI, openai } from '@ai-sdk/openai'; + +interface Env { + MyAgent: AgentNamespace; + OPENAI_API_KEY: string; +} + +export class MyAgent extends Agent { + async onRequest(request: Request) { + // Test it via: + // curl -d '{"prompt": "Write me a Cloudflare Worker"}' + let data = await request.json<{ prompt: string }>(); + let stream = await this.callAIModel(data.prompt); + // This uses Server-Sent Events (SSE) + return stream.toTextStreamResponse({ + headers: { + 'Content-Type': 'text/x-unknown', + 'content-encoding': 'identity', + 'transfer-encoding': 'chunked', + }, + }); + } + + async callAIModel(prompt: string) { + const openai = createOpenAI({ + apiKey: this.env.OPENAI_API_KEY, + }); + + return streamText({ + model: openai('gpt-4o'), + prompt: prompt, + }); + } +} + +export default { + async fetch(request: Request, env: Env) { + let agentId = new URL(request.url).searchParams.get('agent-id') || ''; + const agent = await getAgentByName(env.MyAgent, agentId); + return agent.fetch(request); + }, +}; +``` + + + +### WebSockets vs. Server-Sent Events + +Both WebSockets and Server-Sent Events (SSE) enable real-time communication between clients and Agents. Agents built on the Agents SDK can expose both WebSocket and SSE endpoints directly. + +* WebSockets provide full-duplex communication, allowing data to flow in both directions simultaneously. SSE only supports server-to-client communication, requiring additional HTTP requests if the client needs to send data back. +* WebSockets establish a single persistent connection that stays open for the duration of the session. SSE, being built on HTTP, may experience more overhead due to reconnection attempts and header transmission with each reconnection, especially when there is a lot of client-server communication. +* While SSE works well for simple streaming scenarios, WebSockets are better suited for applications requiring minutes or hours of connection time, as they maintain a more stable connection with built-in ping/pong mechanisms to keep connections alive. +* WebSockets use their own protocol (ws:// or wss://), separating them from HTTP after the initial handshake. This separation allows WebSockets to better handle binary data transmission and implement custom subprotocols for specialized use cases. + +If you're unsure of which is better for your use-case, we recommend WebSockets. The [WebSockets API documentation](/agents/api-reference/websockets/) provides detailed information on how to use WebSockets with the Agents SDK. + +### Next steps + +* Review the [API documentation](/agents/api-reference/agents-api/) for the Agents class to learn how to define them. +* [Build a chat Agent](/agents/getting-started/build-a-chat-agent/) using the Agents SDK and deploy it to Workers. +* Learn more [using WebSockets](/agents/api-reference/websockets/) to build interactive Agents and stream data back from your Agent. +* [Orchestrate asynchronous workflows](/agents/api-reference/run-workflows) from your Agent by combining the Agents SDK and [Workflows](/workflows). diff --git a/src/content/docs/agents/api-reference/index.mdx b/src/content/docs/agents/api-reference/index.mdx index 3db3271d4f644a3..c06356d063d9f84 100644 --- a/src/content/docs/agents/api-reference/index.mdx +++ b/src/content/docs/agents/api-reference/index.mdx @@ -2,11 +2,11 @@ title: API Reference pcx_content_type: navigation sidebar: - order: 5 - group: - hideIndex: true + order: 3 --- import { DirectoryListing } from "~/components" +Learn more about what Agents can do, the `Agent` class, and the APIs that Agents expose: + diff --git a/src/content/docs/agents/examples/rag.mdx b/src/content/docs/agents/api-reference/rag.mdx similarity index 80% rename from src/content/docs/agents/examples/rag.mdx rename to src/content/docs/agents/api-reference/rag.mdx index c836faa12478995..b29014c20452f39 100644 --- a/src/content/docs/agents/examples/rag.mdx +++ b/src/content/docs/agents/api-reference/rag.mdx @@ -2,15 +2,15 @@ title: Retrieval Augmented Generation pcx_content_type: concept sidebar: - order: 7 + order: 9 --- import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; -Agents can use Retrieval Augmented Generation (RAG) to retrieve relevant information and use it augment [calls to AI models](/agents/examples/using-ai-models/). Store a user's chat history to use as context for future conversations, summarize documents to bootstrap an Agent's knowledge base, and/or use data from your Agent's [web browsing](/agents/examples/browse-the-web/) tasks to enhance your Agent's capabilities. +Agents can use Retrieval Augmented Generation (RAG) to retrieve relevant information and use it augment [calls to AI models](/agents/api-reference/using-ai-models/). Store a user's chat history to use as context for future conversations, summarize documents to bootstrap an Agent's knowledge base, and/or use data from your Agent's [web browsing](/agents/api-reference/browse-the-web/) tasks to enhance your Agent's capabilities. -You can use the Agent's own [SQL database](/agents/examples/manage-and-sync-state) as the source of truth for your data and store embeddings in [Vectorize](/vectorize/) (or any other vector-enabled database) to allow your Agent to retrieve relevant information. +You can use the Agent's own [SQL database](/agents/api-reference/store-and-sync-state) as the source of truth for your data and store embeddings in [Vectorize](/vectorize/) (or any other vector-enabled database) to allow your Agent to retrieve relevant information. ### Vector search @@ -27,7 +27,7 @@ Here's an example of how to give an Agent retrieval capabilties: ```ts -import { Agent } from "agents-sdk"; +import { Agent } from "agents"; interface Env { AI: Ai; diff --git a/src/content/docs/agents/examples/run-workflows.mdx b/src/content/docs/agents/api-reference/run-workflows.mdx similarity index 99% rename from src/content/docs/agents/examples/run-workflows.mdx rename to src/content/docs/agents/api-reference/run-workflows.mdx index d0c9049a95fd3a4..442ba327df4ca26 100644 --- a/src/content/docs/agents/examples/run-workflows.mdx +++ b/src/content/docs/agents/api-reference/run-workflows.mdx @@ -2,7 +2,7 @@ title: Run Workflows pcx_content_type: concept sidebar: - order: 4 + order: 5 --- diff --git a/src/content/docs/agents/examples/schedule-tasks.mdx b/src/content/docs/agents/api-reference/schedule-tasks.mdx similarity index 98% rename from src/content/docs/agents/examples/schedule-tasks.mdx rename to src/content/docs/agents/api-reference/schedule-tasks.mdx index f654eb984bd4268..8d39c8ab52a9f29 100644 --- a/src/content/docs/agents/examples/schedule-tasks.mdx +++ b/src/content/docs/agents/api-reference/schedule-tasks.mdx @@ -2,7 +2,7 @@ title: Schedule tasks pcx_content_type: concept sidebar: - order: 5 + order: 4 --- import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; @@ -18,7 +18,7 @@ You can call `this.schedule` within any method on an Agent, and schedule tens-of ```ts -import { Agent } from "agents-sdk" +import { Agent } from "agents" export class SchedulingAgent extends Agent { async onRequest(request) { diff --git a/src/content/docs/agents/api-reference/sdk.mdx b/src/content/docs/agents/api-reference/sdk.mdx deleted file mode 100644 index 258a4d5c0753a2b..000000000000000 --- a/src/content/docs/agents/api-reference/sdk.mdx +++ /dev/null @@ -1,162 +0,0 @@ ---- -title: Agents SDK -pcx_content_type: concept -sidebar: - order: 2 - ---- - -import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; - -At its most basic, an Agent is a JavaScript class that extends the `Agent` class from the `agents-sdk` package. An Agent encapsulates all of the logic for an Agent, including how clients can connect to it, how it stores state, the methods it exposes, and any error handling. - - - -```ts -import { Agent } from "agents-sdk"; - -class MyAgent extends Agent { - // Define methods on the Agent -} - -export default MyAgent; -``` - - - -An Agent can have many (millions of) instances: each instance is a separate micro-server that runs independently of the others. This allows Agents to scale horizontally: an Agent can be associated with a single user, or many thousands of users, depending on the agent you're building. - -Instances of an Agent are addressed by a unique identifier: that identifier (ID) can be the user ID, an email address, GitHub username, a flight ticket number, an invoice ID, or any other identifier that helps to uniquely identify the instance and for whom it is acting on behalf of. - -## The Agent class - -Writing an Agent requires you to define a class that extends the `Agent` class from the `agents-sdk` package. An Agent encapsulates all of the logic for an Agent, including how clients can connect to it, how it stores state, the methods it exposes, and any error handling. - -An Agent has the following class methods: - - - -```ts -import { Agent } from "agents-sdk"; - -interface Env { - // Define environment variables & bindings here -} - -// Pass the Env as a TypeScript type argument -// Any services connected to your Agent or Worker as Bindings -// are then available on this.env. -class MyAgent extends Agent { - // Called when an Agent is started (or woken up) - async onStart() { - // Can access this.env and this.state - console.log('Agent started'); - } - - // Called when a HTTP request is received - // Can be connected to routeAgentRequest to automatically route - // requests to an individual Agent. - async onRequest(request: Request) { - console.log("Received request!"); - } - - // Called when a WebSocket connection is established - async onConnect(connection: Connection, ctx: ConnectionContext) { - console.log("Connected!"); - // Check the request at ctx.request - // Authenticate the client - // Give them the OK. - connection.accept(); - } - - // Called for each message received on the WebSocket connection - async onMessage(connection: Connection, message: WSMessage) { - console.log(`message from client ID: ${connection.id}`) - // Send messages back to the client - connection.send("Hello!"); - } - - // WebSocket error and disconnection (close) handling. - async onError(connection: Connection, error: unknown): Promise { - console.error(`WS error: ${error}`); - } - - async onClose(connection: Connection, code: number, reason: string, wasClean: boolean): Promise { - console.log(`WS closed: ${code} - ${reason} - wasClean: ${wasClean}`); - connection.close(); - } - - // Called when the Agent's state is updated - // via this.setState or the useAgent hook from the agents-sdk/react package. - async onStateUpdate(state: any) { - // 'state' will be typed if you supply a type parameter to the Agent class. - } -} - -export default MyAgent; -``` - - - -:::note - -To learn more about how to manage state within an Agent, refer to the documentation on [managing and syncing state](/agents/examples/manage-and-sync-state/). - -::: - -You can also define your own methods on an Agent: it's technically valid to publish an Agent only has your own methods exposed, and create/get Agents directly from a Worker. - -Your own methods can access the Agent's environment variables and bindings on `this.env`, state on `this.setState`, and call other methods on the Agent via `this.yourMethodName`. - -## Calling Agents from Workers - -You can create and run an instance of an Agent directly from a Worker in one of three ways: - -1. Using the `routeAgentRequest` helper: this will automatically map requests to an individual Agent based on the `/agents/:agent/:name` URL pattern. The value of `:agent` will be the name of your Agent class converted to `kebab-case`, and the value of `:name` will be the name of the Agent instance you want to create or retrieve. -2. Calling `getAgentByName`, which will create a new Agent instance if none exists by that name, or retrieve a handle to an existing instance. -3. The [Durable Objects stub API](/durable-objects/api/id/), which provides a lower level API for creating and retrieving Agents. - -These three patterns are shown below: we recommend using either `routeAgentRequest` or `getAgentByName`, which help avoid some boilerplate. - - - -```ts -import { Agent, AgentNamespace, getAgentByName, routeAgentRequest } from 'agents-sdk'; - -interface Env { - // Define your Agent on the environment here - // Passing your Agent class as a TypeScript type parameter allows you to call - // methods defined on your Agent. - MyAgent: AgentNamespace; -} - -export default { - async fetch(request, env, ctx): Promise { - // Routed addressing - // Automatically routes HTTP requests and/or WebSocket connections to /agents/:agent/:name - // Best for: connecting React apps directly to Agents using useAgent from agents-sdk/react - (await routeAgentRequest(request, env)) || Response.json({ msg: 'no agent here' }, { status: 404 }); - - // Named addressing - // Best for: convenience method for creating or retrieving an agent by name/ID. - let namedAgent = getAgentByName(env.MyAgent, 'my-unique-agent-id'); - // Pass the incoming request straight to your Agent - let namedResp = (await namedAgent).fetch(request); - - // Durable Objects-style addressing - // Best for: controlling ID generation, associating IDs with your existing systems, - // and customizing when/how an Agent is created or invoked - const id = env.MyAgent.newUniqueId(); - const agent = env.MyAgent.get(id); - // Pass the incoming request straight to your Agent - let resp = await agent.fetch(request); - - return Response.json({ hello: 'visit https://developers.cloudflare.com/agents for more' }); - }, -} satisfies ExportedHandler; - -export class MyAgent extends Agent { - // Your Agent implementation goes here -} -``` - diff --git a/src/content/docs/agents/examples/manage-and-sync-state.mdx b/src/content/docs/agents/api-reference/store-and-sync-state.mdx similarity index 79% rename from src/content/docs/agents/examples/manage-and-sync-state.mdx rename to src/content/docs/agents/api-reference/store-and-sync-state.mdx index 723ad60cb9dd987..fea3f3949f54de9 100644 --- a/src/content/docs/agents/examples/manage-and-sync-state.mdx +++ b/src/content/docs/agents/api-reference/store-and-sync-state.mdx @@ -1,5 +1,5 @@ --- -title: Manage and sync state +title: Store and sync state pcx_content_type: concept sidebar: order: 6 @@ -7,14 +7,17 @@ sidebar: import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; -Every Agent has built-in state management capabilities, including built-in storage and synchronization between the Agent and frontend applications. State within an Agent is: +Every Agent has built-in state management capabilities, including built-in storage and synchronization between the Agent and frontend applications. -* Persisted across Agent restarts: data is permanently persisted within the Agent. +State within an Agent is: + +* Persisted across Agent restarts: data is permanently stored within an Agent. * Automatically serialized/deserialized: you can store any JSON-serializable data. * Immediately consistent within the Agent: read your own writes. * Thread-safe for concurrent updates +* Fast: state is colocated wherever the Agent is running. Reads and writes do not need to traverse the network. -Agent state is stored in a SQL database that is embedded within each individual Agent instance: you can interact with it using the higher-level `this.setState` API (recommended) or by directly querying the database with `this.sql`. +Agent state is stored in a SQL database that is embedded within each individual Agent instance: you can interact with it using the higher-level `this.setState` API (recommended), which allows you to sync state and trigger events on state changes, or by directly querying the database with `this.sql`. #### State API @@ -23,7 +26,7 @@ Every Agent has built-in state management capabilities. You can set and update t ```ts -import { Agent } from "agents-sdk"; +import { Agent } from "agents"; export class MyAgent extends Agent { // Update state in response to events @@ -58,7 +61,7 @@ If you're using TypeScript, you can also provide a type for your Agent's state b ```ts -import { Agent } from "agents-sdk"; +import { Agent } from "agents"; interface Env {} @@ -90,9 +93,39 @@ export class MyAgent extends Agent { +### Set the initial state for an Agent + +You can also set the initial state for an Agent via the `initialState` property on the `Agent` class: + + + +```ts +type State = { + counter: number; + text: string; + color: string; +}; + +class MyAgent extends Agent { + // Set a default, initial state + initialState = { + counter: 0, + text: "", + color: "#3B82F6", + }; + + doSomething() { + console.log(this.state); // {counter: 0, text: "", color: "#3B82F6"}, if you haven't set the state yet + } +} +``` + + +Any initial state is synced to clients connecting via [the `useAgent` hook](#synchronizing-state). + ### Synchronizing state -Clients can connect to an Agent and stay synchronized with its state using the React hooks provided as part of `agents-sdk/react`. +Clients can connect to an Agent and stay synchronized with its state using the React hooks provided as part of `agents/react`. A React application can call `useAgent` to connect to a named Agent over WebSockets at @@ -100,7 +133,7 @@ A React application can call `useAgent` to connect to a named Agent over WebSock ```ts import { useState } from "react"; -import { useAgent } from "agents-sdk/react"; +import { useAgent } from "agents/react"; function StateInterface() { const [state, setState] = useState({ counter: 0 }); @@ -198,7 +231,7 @@ The SQL API exposed to an Agent is similar to the one [within Durable Objects](/ ### Use Agent state as model context -You can combine the state and SQL APIs in your Agent with its ability to [call AI models](/agents/examples/using-ai-models/) to include historical context within your prompts to a model. Modern Large Language Models (LLMs) often have very large context windows (up to millions of tokens), which allows you to pull relevant context into your prompt directly. +You can combine the state and SQL APIs in your Agent with its ability to [call AI models](/agents/api-reference/using-ai-models/) to include historical context within your prompts to a model. Modern Large Language Models (LLMs) often have very large context windows (up to millions of tokens), which allows you to pull relevant context into your prompt directly. For example, you can use an Agent's built-in SQL database to pull history, query a model with it, and append to that history ahead of the next call to the model: @@ -249,3 +282,9 @@ export class ReasoningAgent extends Agent { This works because each instance of an Agent has its _own_ database, the state stored in that database is private to that Agent: whether it's acting on behalf of a single user, a room or channel, or a deep research tool. By default, you don't have to manage contention or reach out over the network to a centralized database to retrieve and store state. +### Next steps + +* Review the [API documentation](/agents/api-reference/agents-api/) for the Agents class to learn how to define them. +* [Build a chat Agent](/agents/getting-started/build-a-chat-agent/) using the Agents SDK and deploy it to Workers. +* Learn more [using WebSockets](/agents/api-reference/websockets/) to build interactive Agents and stream data back from your Agent. +* [Orchestrate asynchronous workflows](/agents/api-reference/run-workflows) from your Agent by combining the Agents SDK and [Workflows](/workflows). diff --git a/src/content/docs/agents/examples/using-ai-models.mdx b/src/content/docs/agents/api-reference/using-ai-models.mdx similarity index 83% rename from src/content/docs/agents/examples/using-ai-models.mdx rename to src/content/docs/agents/api-reference/using-ai-models.mdx index 5287b0fa5819150..f2451666a5aeff8 100644 --- a/src/content/docs/agents/examples/using-ai-models.mdx +++ b/src/content/docs/agents/api-reference/using-ai-models.mdx @@ -2,21 +2,29 @@ title: Using AI Models pcx_content_type: concept sidebar: - order: 7 + order: 3 --- import { AnchorHeading, MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; -Agents can communicate with AI models hosted on any provider, including [Workers AI](/workers-ai/), OpenAI, Anthropic, and Google's Gemini, and use the model routing features in [AI Gateway](/ai-gateway/) to route across providers, eval responses, and manage AI provider rate limits. +Agents can communicate with AI models hosted on any provider, including: -Because Agents are built on top of [Durable Objects](/durable-objects/), each Agent or chat session is associated with a stateful compute instance. Tradtional serverless architectures often present challenges for persistent connections needed in real-time applications like chat. +* [Workers AI](/workers-ai/) +* The [AI SDK](https://sdk.vercel.ai/docs/ai-sdk-core/overview) +* [OpenAI](https://platform.openai.com/docs/quickstart?language=javascript) +* [Anthropic](https://docs.anthropic.com/en/api/client-sdks#typescript +* [Google's Gemini](https://ai.google.dev/gemini-api/docs/openai) + +You can also use the model routing features in [AI Gateway](/ai-gateway/) to route across providers, eval responses, and manage AI provider rate limits. + +Because Agents are built on top of [Durable Objects](/durable-objects/), each Agent or chat session is associated with a stateful compute instance. Traditional serverless architectures often present challenges for persistent connections needed in real-time applications like chat. A user can disconnect during a long-running response from a modern reasoning model (such as `o3-mini` or DeepSeek R1), or lose conversational context when refreshing the browser. Instead of relying on request-response patterns and managing an external database to track & store conversation state, state can be stored directly within the Agent. If a client disconnects, the Agent can write to its own distributed storage, and catch the client up as soon as it reconnects: even if it's hours or days later. ## Calling AI Models -You can call models from any method within an Agent, including from HTTP requests using the [`onRequest`](/agents/api-reference/sdk/) handler, when a [scheduled task](/agents/examples/schedule-tasks/) runs, when handling a WebSocket message in the [`onMessage`](/agents/examples/websockets/) handler, or from any of your own methods. +You can call models from any method within an Agent, including from HTTP requests using the [`onRequest`](/agents/api-reference/agents-api/) handler, when a [scheduled task](/agents/api-reference/schedule-tasks/) runs, when handling a WebSocket message in the [`onMessage`](/agents/api-reference/websockets/) handler, or from any of your own methods. Importantly, Agents can call AI models on their own — autonomously — and can handle long-running responses that can take minutes (or longer) to respond in full. @@ -24,18 +32,17 @@ Importantly, Agents can call AI models on their own — autonomously — and can Modern [reasoning models](https://platform.openai.com/docs/guides/reasoning) or "thinking" model can take some time to both generate a response _and_ stream the response back to the client. -Instead of buffering the entire response, or risking the client disconecting, you can stream the response back to the client by using the [WebSocket API](/agents/examples/websockets/). +Instead of buffering the entire response, or risking the client disconecting, you can stream the response back to the client by using the [WebSocket API](/agents/api-reference/websockets/). ```ts -import { Agent } from "agents-sdk" +import { Agent } from "agents" import { OpenAI } from "openai" export class MyAgent extends Agent { async onConnect(connection: Connection, ctx: ConnectionContext) { - // Omitted for simplicity: authenticating the user - connection.accept() + // } async onMessage(connection: Connection, message: WSMessage) { @@ -75,7 +82,7 @@ export class MyAgent extends Agent { -You can also persist AI model responses back to [Agent's internal state](/agents/examples/manage-and-sync-state/) by using the `this.setState` method. For example, if you run a [scheduled task](/agents/examples/schedule-tasks/), you can store the output of the task and read it later. Or, if a user disconnects, read the message history back and send it to the user when they reconnect. +You can also persist AI model responses back to [Agent's internal state](/agents/api-reference/store-and-sync-state/) by using the `this.setState` method. For example, if you run a [scheduled task](/agents/api-reference/schedule-tasks/), you can store the output of the task and read it later. Or, if a user disconnects, read the message history back and send it to the user when they reconnect. ### Workers AI @@ -88,7 +95,7 @@ Workers AI supports streaming responses out-of-the-box by setting `stream: true` ```ts -import { Agent } from "agents-sdk" +import { Agent } from "agents" interface Env { AI: Ai; @@ -138,7 +145,7 @@ Model routing allows you to route requests to different AI models based on wheth ```ts -import { Agent } from "agents-sdk" +import { Agent } from "agents" interface Env { AI: Ai; @@ -192,7 +199,7 @@ npm install ai @ai-sdk/openai ```ts -import { Agent } from "agents-sdk" +import { Agent } from "agents" import { generateText } from 'ai'; import { openai } from '@ai-sdk/openai'; @@ -214,12 +221,12 @@ export class MyAgent extends Agent { Agents can call models across any service, including those that support the OpenAI API. For example, you can use the OpenAI SDK to use one of [Google's Gemini models](https://ai.google.dev/gemini-api/docs/openai#node.js) directly from your Agent. -Agents can stream responses back over HTTP using Server Sent Events (SSE) from within an `onRequest` handler, or by using the native [WebSockets](/agents/examples/websockets/) API in your Agent to responses back to a client, which is especially useful for larger models that can take over 30+ seconds to reply. +Agents can stream responses back over HTTP using Server Sent Events (SSE) from within an `onRequest` handler, or by using the native [WebSockets](/agents/api-reference/websockets/) API in your Agent to responses back to a client, which is especially useful for larger models that can take over 30+ seconds to reply. ```ts -import { Agent } from "agents-sdk" +import { Agent } from "agents" import { OpenAI } from "openai" export class MyAgent extends Agent { diff --git a/src/content/docs/agents/examples/websockets.mdx b/src/content/docs/agents/api-reference/websockets.mdx similarity index 72% rename from src/content/docs/agents/examples/websockets.mdx rename to src/content/docs/agents/api-reference/websockets.mdx index 8eccb861b04b4eb..6348a15808bb7bb 100644 --- a/src/content/docs/agents/examples/websockets.mdx +++ b/src/content/docs/agents/api-reference/websockets.mdx @@ -2,7 +2,7 @@ title: Using WebSockets pcx_content_type: concept sidebar: - order: 2 + order: 10 --- @@ -20,28 +20,13 @@ Here's an example of an Agent that echoes back any message it receives: ```ts -import { Agent, Connection } from "agents-sdk"; +import { Agent, Connection } from "agents"; export class ChatAgent extends Agent { - async onConnect(connection: Connection, ctx: ConnectionContext) { - // Access the request to verify any authentication tokens - // provided in headers or cookies - let token = ctx.request.headers.get("Authorization"); - if (!token) { - await connection.close(4000, "Unauthorized"); - return; - } - - // Handle auth using your favorite library and/or auth scheme: - // try { - // await jwt.verify(token, env.JWT_SECRET); - // } catch (error) { - // connection.close(4000, 'Invalid Authorization header'); - // return; - // } - - // Accept valid connections - connection.accept() + async onConnect(connection: Connection, ctx: ConnectionContext) { + // Connections are automatically accepted by the SDK. + // You can also explicitly close a connection here with connection.close() + // Access the Request on ctx.request to inspect headers, cookies and the URL } async onMessage(connection: Connection, message: WSMessage) { @@ -53,14 +38,14 @@ export class ChatAgent extends Agent { -## Connecting clients +### Connecting clients -The Agent framework includes a useful helper package for connecting directly to your Agent (or other Agents) from a client application. Import `agents-sdk/client`, create an instance of `AgentClient` and use it to connect to an instance of your Agent: +The Agent framework includes a useful helper package for connecting directly to your Agent (or other Agents) from a client application. Import `agents/client`, create an instance of `AgentClient` and use it to connect to an instance of your Agent: ```ts -import { AgentClient } from "agents-sdk/client"; +import { AgentClient } from "agents/client"; const connection = new AgentClient({ agent: "dialogue-agent", @@ -81,14 +66,14 @@ connection.send( -## React clients +### React clients -React-based applications can import `agents-sdk/react` and use the `useAgent` hook to connect to an instance of an Agent directly: +React-based applications can import `agents/react` and use the `useAgent` hook to connect to an instance of an Agent directly: ```ts -import { useAgent } from "agents-sdk/react"; +import { useAgent } from "agents/react"; function AgentInterface() { const connection = useAgent({ @@ -120,16 +105,16 @@ function AgentInterface() { ``` -The `useAgent` hook automatically handles the lifecycle of the connection, ensuring that it is properly initialized and cleaned up when the component mounts and unmounts. You can also [combine `useAgent` with `useState`](/agents/examples/manage-and-sync-state/) to automatically synchronize state across all clients connected to your Agent. +The `useAgent` hook automatically handles the lifecycle of the connection, ensuring that it is properly initialized and cleaned up when the component mounts and unmounts. You can also [combine `useAgent` with `useState`](/agents/api-reference/store-and-sync-state/) to automatically synchronize state across all clients connected to your Agent. -## Handling WebSocket events +### Handling WebSocket events Define `onError` and `onClose` methods on your Agent to explicitly handle WebSocket client errors and close events. Log errors, clean up state, and/or emit metrics: ```ts -import { Agent, Connection } from "agents-sdk"; +import { Agent, Connection } from "agents"; export class ChatAgent extends Agent { // onConnect and onMessage methods diff --git a/src/content/docs/agents/examples/index.mdx b/src/content/docs/agents/examples/index.mdx deleted file mode 100644 index 34f41dbf12ee2ec..000000000000000 --- a/src/content/docs/agents/examples/index.mdx +++ /dev/null @@ -1,12 +0,0 @@ ---- -pcx_content_type: reference -title: Examples -sidebar: - order: 3 ---- - -import { DirectoryListing, PackageManagers } from "~/components"; - -Agents running on Cloudflare can: - - 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 2d5b78b88399e0d..a22a297ccc70a0f 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 @@ -5,5 +5,5 @@ external_link: https://github.com/cloudflare/agents-starter sidebar: order: 3 head: [] -description: A starter template for building AI-powered chat agents using Cloudflare's Agent platform, powered by agents-sdk. This project provides a foundation for creating interactive chat experiences with AI, complete with a modern UI and tool integration capabilities. +description: A starter template for building AI-powered chat agents using Cloudflare's Agent platform, powered by the Agents SDK. This project provides a foundation for creating interactive chat experiences with AI, complete with a modern UI and tool integration capabilities. --- \ No newline at end of file diff --git a/src/content/docs/agents/getting-started/prompting.mdx b/src/content/docs/agents/getting-started/prompting.mdx index 10736b5ab43eaad..463edb7e413db2f 100644 --- a/src/content/docs/agents/getting-started/prompting.mdx +++ b/src/content/docs/agents/getting-started/prompting.mdx @@ -5,5 +5,5 @@ external_link: /workers/get-started/prompting/ sidebar: order: 10 head: [] -description: Use the Workers "mega prompt" to build a Agents using your preferred AI tools and/or IDEs. The prompt understands agents-sdk APIs, best practices and guidelines, and makes it easier to build valid Agents and Workers. +description: Use the Workers "mega prompt" to build a Agents using your preferred AI tools and/or IDEs. The prompt understands the Agents SDK APIs, best practices and guidelines, and makes it easier to build valid Agents and Workers. --- 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 d5b2cf20c7aae38..49a177ec2034b84 100644 --- a/src/content/docs/agents/getting-started/testing-your-agent.mdx +++ b/src/content/docs/agents/getting-started/testing-your-agent.mdx @@ -2,7 +2,7 @@ title: Testing your Agents pcx_content_type: get-started sidebar: - order: 10 + order: 9 --- @@ -16,7 +16,7 @@ Because Agents run on Cloudflare Workers and Durable Objects, they can be tested :::note -The `agents-sdk-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.js` file. ::: diff --git a/src/content/docs/agents/examples/build-mcp-server.mdx b/src/content/docs/agents/guides/build-mcp-server.mdx similarity index 100% rename from src/content/docs/agents/examples/build-mcp-server.mdx rename to src/content/docs/agents/guides/build-mcp-server.mdx diff --git a/src/content/docs/agents/guides/human-in-the-loop.mdx b/src/content/docs/agents/guides/human-in-the-loop.mdx index 20b69c099ab7b85..af9554f744ac504 100644 --- a/src/content/docs/agents/guides/human-in-the-loop.mdx +++ b/src/content/docs/agents/guides/human-in-the-loop.mdx @@ -5,5 +5,5 @@ external_link: https://github.com/cloudflare/agents/tree/main/guides/anthropic-p sidebar: order: 3 head: [] -description: Implement common agent patterns using the `agents-sdk` framework. +description: Implement common agent patterns using the Agents SDK framework. --- diff --git a/src/content/docs/agents/index.mdx b/src/content/docs/agents/index.mdx index 9105bdabe87bbdc..752e856a1633af1 100644 --- a/src/content/docs/agents/index.mdx +++ b/src/content/docs/agents/index.mdx @@ -21,13 +21,14 @@ import { Render, TabItem, Tabs, + TypeScriptExample, } from "~/components"; -Build and deploy AI-powered Agents on Cloudflare that can autonomously perform tasks, communicate with clients in real time, persist state, execute long-running and repeat tasks on a schedule, send emails, run asynchronous workflows, browse the web, query data from your Postgres database, call AI models, support human-in-the-loop use-cases, and more. +The Agents SDK enables you to build and deploy AI-powered agents that can autonomously perform tasks, communicate with clients in real time, call AI models, persist state, schedule tasks, run asynchronous workflows, browse the web, query data from your database, support human-in-the-loop interactions, and [a lot more](/agents/api-reference/). -#### Ship your first Agent +### Ship your first Agent -Use the agent starter template to create your first Agent with the `agents-sdk`: +To use the Agent starter template and create your first Agent with the Agents SDK: ```sh # install it @@ -36,29 +37,49 @@ npm create cloudflare@latest agents-starter -- --template=cloudflare/agents-star npx wrangler@latest deploy ``` -Head to the guide on [building a chat agent](/agents/getting-started/build-a-chat-agent) to learn how to build and deploy an Agent to prod. +Head to the guide on [building a chat agent](/agents/getting-started/build-a-chat-agent) to learn how the starter project is built and how to use it as a foundation for your own agents. -If you're already building on [Workers](/workers/), you can install the `agents-sdk` package directly into an existing project: +If you're already building on [Workers](/workers/), you can install the `agents` package directly into an existing project: ```sh -npm i agents-sdk +npm i agents ``` -Dive into the [Agent SDK reference](/agents/api-reference/sdk/) to learn more about how to use the `agents-sdk` package and defining an `Agent`. +And then define your first Agent by creating a class that extends the `Agent` class: -#### Why build agents on Cloudflare? + -We built the `agents-sdk` with a few things in mind: +```ts +import { Agent, AgentNamespace } from 'agents'; -- **Batteries (state) included**: Agents come with [built-in state management](/agents/examples/manage-and-sync-state/), with the ability to automatically sync state between an Agent and clients, trigger events on state changes, and read+write to each Agent's SQL database. -- **Communicative**: You can connect to an Agent via [WebSockets](/agents/examples/websockets/) and stream updates back to client in real-time. Handle a long-running response from a reasoning model, the results of an [asynchronous workflow](/agents/examples/run-workflows/), or build a chat app that builds on the `useAgent` hook included in the `agents-sdk`. -- **Extensible**: Agents are code. Use the [AI models](/agents/examples/using-ai-models/) you want, bring-your-own headless browser service, pull data from your database hosted in another cloud, add your own methods to your Agent and call them. +export class MyAgent extends Agent { + // Define methods on the Agent: + // https://developers.cloudflare.com/agents/api-reference/agents-api/ + // + // Every Agent has built in state via this.setState and this.sql + // Built-in scheduling via this.schedule + // Agents support WebSockets, HTTP requests, state synchronization and + // can run for seconds, minutes or hours: as long as the tasks need. +} +``` + + + +Dive into the [Agent SDK reference](/agents/api-reference/agents-api/) to learn more about how to use the Agents SDK package and defining an `Agent`. + +### Why build agents on Cloudflare? + +We built the Agents SDK with a few things in mind: + +- **Batteries (state) included**: Agents come with [built-in state management](/agents/api-reference/store-and-sync-state/), with the ability to automatically sync state between an Agent and clients, trigger events on state changes, and read+write to each Agent's SQL database. +- **Communicative**: You can connect to an Agent via [WebSockets](/agents/api-reference/websockets/) and stream updates back to client in real-time. Handle a long-running response from a reasoning model, the results of an [asynchronous workflow](/agents/api-reference/run-workflows/), or build a chat app that builds on the `useAgent` hook included in the Agents SDK. +- **Extensible**: Agents are code. Use the [AI models](/agents/api-reference/using-ai-models/) you want, bring-your-own headless browser service, pull data from your database hosted in another cloud, add your own methods to your Agent and call them. -Agents built with `agents-sdk` can be deployed directly to Cloudflare and run on top of [Durable Objects](/durable-objects/) — which you can think of as stateful micro-servers that can scale to tens of millions — and are able to run wherever they need to. Run your Agents close to a user for low-latency interactivity, close to your data for throughput, and/or anywhere in between. +Agents built with Agents SDK can be deployed directly to Cloudflare and run on top of [Durable Objects](/durable-objects/) — which you can think of as stateful micro-servers that can scale to tens of millions — and are able to run wherever they need to. Run your Agents close to a user for low-latency interactivity, close to your data for throughput, and/or anywhere in between. --- -#### Build on the Cloudflare Platform +### Build on the Cloudflare Platform diff --git a/src/content/docs/agents/platform/index.mdx b/src/content/docs/agents/platform/index.mdx index 77d033f1bfa25aa..59ce231e2cb7b76 100644 --- a/src/content/docs/agents/platform/index.mdx +++ b/src/content/docs/agents/platform/index.mdx @@ -1,6 +1,6 @@ --- pcx_content_type: reference -title: Reference +title: Platform sidebar: order: 10 group: @@ -9,6 +9,4 @@ sidebar: import { DirectoryListing } from "~/components"; -Build AI Agents on Cloudflare - diff --git a/src/content/docs/agents/platform/limits.mdx b/src/content/docs/agents/platform/limits.mdx index b805824abf27759..7279c9b4a661861 100644 --- a/src/content/docs/agents/platform/limits.mdx +++ b/src/content/docs/agents/platform/limits.mdx @@ -24,6 +24,6 @@ Many limits are inherited from those applied to Workers scripts and/or Durable O [^1]: Yes, really. You can have tens of millions of Agents running concurrently, as each Agent is mapped to a [unique Durable Object](/durable-objects/what-are-durable-objects/) (actor). [^2]: You can deploy up to [500 scripts per account](/workers/platform/limits/), but each script (project) can define multiple Agents. Each deployed script can be up to 10 MB on the [Workers Paid Plan](/workers/platform/pricing/#workers) -[^3]: Compute (CPU) time per Agent is limited to 30 seconds, but this is refreshed when an Agent receives a new HTTP request, runs a [scheduled task](/agents/examples/schedule-tasks/), or an incoming WebSocket message. +[^3]: Compute (CPU) time per Agent is limited to 30 seconds, but this is refreshed when an Agent receives a new HTTP request, runs a [scheduled task](/agents/api-reference/schedule-tasks/), or an incoming WebSocket message. diff --git a/src/content/docs/agents/platform/llms.txt.mdx b/src/content/docs/agents/platform/llms.txt.mdx deleted file mode 100644 index 9e4d540f2fd35de..000000000000000 --- a/src/content/docs/agents/platform/llms.txt.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -pcx_content_type: navigation -title: llms.txt -external_link: /llms.txt -sidebar: - order: 99 -head: [] -description: Provide context to your AI models & tools when building on Cloudflare. ---- diff --git a/src/content/partials/agents/unique-agents.mdx b/src/content/partials/agents/unique-agents.mdx new file mode 100644 index 000000000000000..06526e2952ae928 --- /dev/null +++ b/src/content/partials/agents/unique-agents.mdx @@ -0,0 +1,14 @@ +--- +{} + +--- + +:::note + +An instance of an Agent is globally unique: given the same name (or ID), you will always get the same instance of an agent. + +This allows you to avoid synchronizing state across requests: if an Agent instance represents a specific user, team, channel or other entity, you can use the Agent instance to store state for that entity. No need to set up a centralized session store. + +If the client disconnects, you can always route the client back to the exact same Agent and pick up where they left off. + +::: \ No newline at end of file diff --git a/src/content/partials/prompts/base-prompt.txt b/src/content/partials/prompts/base-prompt.txt index 067eaa68c1e60f9..d362183520b836c 100644 --- a/src/content/partials/prompts/base-prompt.txt +++ b/src/content/partials/prompts/base-prompt.txt @@ -157,12 +157,12 @@ You are an advanced assistant specialized in generating Cloudflare Workers code. -- Strongly prefer the `agents-sdk` to build AI Agents when asked. +- Strongly prefer the `agents` to build AI Agents when asked. - Refer to the for Agents. - Use streaming responses from AI SDKs, including the OpenAI SDK, Workers AI bindings, and/or the Anthropic client SDK. - Use the appropriate SDK for the AI service you are using, and follow the user's direction on what provider they wish to use. - Prefer the `this.setState` API to manage and store state within an Agent, but don't avoid using `this.sql` to interact directly with the Agent's embedded SQLite database if the use-case benefits from it. -- When building a client interface to an Agent, use the `useAgent` React hook from the `agents-sdk/react` library to connect to the Agent as the preferred approach. +- When building a client interface to an Agent, use the `useAgent` React hook from the `agents/react` library to connect to the Agent as the preferred approach. - When extending the `Agent` class, ensure you provide the `Env` and the optional state as type parameters - for example, `class AIAgent extends Agent { ... }`. - Include valid Durable Object bindings in the `wrangler.jsonc` configuration for an Agent. - You MUST set the value of `migrations[].new_sqlite_classes` to the name of the Agent class in `wrangler.jsonc`. @@ -925,15 +925,15 @@ export default { - + -Build an AI Agent on Cloudflare Workers, using the agents-sdk, and the state management and syncing APIs built into the agents-sdk. +Build an AI Agent on Cloudflare Workers, using the agents, and the state management and syncing APIs built into the agents. // src/index.ts -import { Agent, AgentNamespace, Connection, ConnectionContext, getAgentByName, routeAgentRequest, WSMessage } from 'agents-sdk'; +import { Agent, AgentNamespace, Connection, ConnectionContext, getAgentByName, routeAgentRequest, WSMessage } from 'agents'; import { OpenAI } from "openai"; interface Env { @@ -1141,7 +1141,7 @@ export default { // client.js -import { AgentClient } from "agents-sdk/client"; +import { AgentClient } from "agents/client"; const connection = new AgentClient({ agent: "dialogue-agent", @@ -1162,8 +1162,8 @@ connection.send( // app.tsx -// React client hook for the agents-sdk -import { useAgent } from "agents-sdk/react"; +// React client hook for the agents +import { useAgent } from "agents/react"; import { useState } from "react"; // useAgent client API @@ -1237,7 +1237,7 @@ function StateInterface() { -- Imports the `Agent` class from the `agents-sdk` package +- Imports the `Agent` class from the `agents` package - Extends the `Agent` class and implements the methods exposed by the `Agent`, including `onRequest` for HTTP requests, or `onConnect` and `onMessage` for WebSockets. - Uses the `this.schedule` scheduling API to schedule future tasks. - Uses the `this.setState` API within the Agent for syncing state, and uses type parameters to ensure the state is typed.