Skip to content

Commit c43f550

Browse files
committed
state state state
1 parent 3363272 commit c43f550

File tree

3 files changed

+187
-10
lines changed

3 files changed

+187
-10
lines changed

src/content/docs/agents/api-reference/sdk.mdx

Lines changed: 131 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ sidebar:
66

77
---
88

9-
import { MetaInfo, Render, Type, WranglerConfig } from "~/components";
9+
import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components";
1010

1111
At its most basic, an Agent is a JavaScript class that extends the `Agent` class from the `@cloudflare/agents` 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.
1212

@@ -28,7 +28,135 @@ An Agent can have many (millions of) instances: each instance is a separate micr
2828

2929
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.
3030

31-
## Agent
31+
## The Agent class
3232

33-
TODO - agent class
33+
Writing an Agent requires you to define a class that extends the `Agent` class from the `@cloudflare/agents` 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.
3434

35+
An Agent has the following class methods:
36+
37+
<TypeScriptExample>
38+
39+
```ts
40+
import { Agent } from "@cloudflare/agents";
41+
42+
interface Env {
43+
// Define environment variables & bindings here
44+
}
45+
46+
// Pass the Env as a TypeScript type argument
47+
// Any services connected to your Agent or Worker as Bindings
48+
// are then available on this.env.<BINDING_NAME>
49+
class MyAgent extends Agent<Env> {
50+
// Called when an Agent is started (or woken up)
51+
async onStart() {
52+
// Can access this.env and this.state
53+
console.log('Agent started');
54+
}
55+
56+
// Called when a HTTP request is received
57+
// Can be connected to routeAgentRequest to automatically route
58+
// requests to an individual Agent.
59+
async onRequest(request: Request) {
60+
console.log("Received request!");
61+
}
62+
63+
// Called when a WebSocket connection is established
64+
async onConnect(connection: Connection, ctx: ConnectionContext) {
65+
console.log("Connected!");
66+
// Check the request at ctx.request
67+
// Authenticate the client
68+
// Give them the OK.
69+
connection.accept();
70+
}
71+
72+
// Called for each message received on the WebSocket connection
73+
async onMessage(connection: Connection, message: WSMessage) {
74+
console.log(`message from client ID: ${connection.id}`)
75+
// Send messages back to the client
76+
connection.send("Hello!");
77+
}
78+
79+
// WebSocket error and disconnection (close) handling.
80+
async onError(connection: Connection, error: unknown): Promise<void> {
81+
console.error(`WS error: ${error}`);
82+
}
83+
84+
async onClose(connection: Connection, code: number, reason: string, wasClean: boolean): Promise<void> {
85+
console.log(`WS closed: ${code} - ${reason} - wasClean: ${wasClean}`);
86+
connection.close();
87+
}
88+
89+
// Called when the Agent's state is updated
90+
// via this.setState or the useAgent hook from the @cloudflare/agents/react package.
91+
async onStateUpdate(state: any) {
92+
// 'state' will be typed if you supply a type parameter to the Agent class.
93+
}
94+
}
95+
96+
export default MyAgent;
97+
```
98+
99+
</TypeScriptExample>
100+
101+
:::note
102+
103+
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/).
104+
105+
:::
106+
107+
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.
108+
109+
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`.
110+
111+
## Calling Agents from Workers
112+
113+
You can create and run an instance of an Agent directly from a Worker in one of three ways:
114+
115+
1. Using the `routeAgentRequest` helper: this will automatically map requests to an individual Agent based on the `/agents/:agent/:name` URL pattern.
116+
2. Calling `getAgentByName`, which will create a new Agent instance if none exists by that name, or retrieve a handle to an existing instance.
117+
3. The [Durable Objects stub API](/durable-objects/api/id/), which provides a lower level API for creating and retrieving Agents.
118+
119+
These three patterns are shown below: we recommend using either `routeAgentRequest` or `getAgentByName`, which help avoid some boilerplate.
120+
121+
<TypeScriptExample>
122+
123+
```ts
124+
import { Agent, AgentNamespace, getAgentByName, routeAgentRequest } from '@cloudflare/agents';
125+
126+
interface Env {
127+
// Define your Agent on the environment here
128+
// Passing your Agent class as a TypeScript type parameter allows you to call
129+
// methods defined on your Agent.
130+
MyAgent: AgentNamespace<MyAgent>;
131+
}
132+
133+
export default {
134+
async fetch(request, env, ctx): Promise<Response> {
135+
// Routed addressing
136+
// Automatically routes HTTP requests and/or WebSocket connections to /agents/:agent/:name
137+
// Best for: connecting React apps directly to Agents using useAgent from @cloudflare/agents/react
138+
(await routeAgentRequest(request, env)) || Response.json({ msg: 'no agent here' }, { status: 404 });
139+
140+
// Named addressing
141+
// Best for: convenience method for creating or retrieving an agent by name/ID.
142+
let namedAgent = getAgentByName<Env, MyAgent>(env.MyAgent, 'my-unique-agent-id');
143+
// Pass the incoming request straight to your Agent
144+
let namedResp = (await namedAgent).fetch(request);
145+
146+
// Durable Objects-style addressing
147+
// Best for: controlling ID generation, associating IDs with your existing systems,
148+
// and customizing when/how an Agent is created or invoked
149+
const id = env.MyAgent.newUniqueId();
150+
const agent = env.MyAgent.get(id);
151+
// Pass the incoming request straight to your Agent
152+
let resp = await agent.fetch(request);
153+
154+
return Response.json({ hello: 'visit https://developers.cloudflare.com/agents for more' });
155+
},
156+
} satisfies ExportedHandler<Env>;
157+
158+
export class MyAgent extends Agent<Env> {
159+
// Your Agent implementation goes here
160+
}
161+
```
162+
</TypeScriptExample>

src/content/docs/agents/examples/index.mdx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ pcx_content_type: reference
33
title: Build
44
sidebar:
55
order: 4
6-
group:
7-
hideIndex: true
86
---
97

10-
import { DirectoryListing } from "~/components";
8+
import { DirectoryListing, PackageManagers } from "~/components";
119

12-
Build AI Agents on Cloudflare
10+
Agents running on Cloudflare can:
1311

1412
<DirectoryListing />

src/content/docs/agents/examples/manage-and-sync-state.mdx

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ Every Agent has built-in state management capabilities, including built-in stora
1414
* Immediately consistent within the Agent: read your own writes.
1515
* Thread-safe for concurrent updates
1616

17-
### State management
17+
Agent state is stored in SQL database that associate with each indidivual Agent instance: you can interact with it using the higher-level `this.setState` API (recommended) or by directly querying the database with `this.sql`.
1818

19-
Every agent has built-in state management capabilities. You can set and update the agent's state directly using `this.state`:
19+
### State API
20+
21+
Every agent has built-in state management capabilities. You can set and update the agent's state directly using `this.setState`:
2022

2123
<TypeScriptExample>
2224

@@ -51,6 +53,32 @@ export class MyAgent extends Agent {
5153

5254
</TypeScriptExample>
5355

56+
If you're using TypeScript, you can also provide a type for your Agent's state by passing in a type as a [type parameter](https://www.typescriptlang.org/docs/handbook/2/generics.html#using-type-parameters-in-generic-constraints) as the _second_ type parameter to the `Agent` class definition.
57+
58+
<TypeScriptExample>
59+
60+
```ts
61+
import { Agent } from "@cloudflare/agents";
62+
63+
interface Env {}
64+
65+
//
66+
interface FlightRecord {
67+
id: string;
68+
departureIata: string;
69+
arrival: Date;;
70+
arrivalIata: string;
71+
price: number;
72+
}
73+
74+
// Pass in the type of your Agent's state
75+
export class MyAgent extends Agent<Env, FlightRecord> {
76+
// This allows this.setState and
77+
}
78+
```
79+
80+
</TypeScriptExample>
81+
5482
### Synchronizing state
5583

5684
Clients can connect to an Agent and stay synchronized with its state using the React hooks provided as part of `@cloudflare/agents/react`:
@@ -78,4 +106,27 @@ Common use cases:
78106
* Multi-window/tab synchronization
79107
* Live updates across multiple devices
80108
* Maintaining consistent UI state across clients
81-
* When new clients connect, they automatically receive the current state from the agent, ensuring all clients start with the latest data.
109+
* When new clients connect, they automatically receive the current state from the agent, ensuring all clients start with the latest data.
110+
111+
### SQL API
112+
113+
Every individual Agent instance has its own SQL (SQLite) database that runs _within the same context_ as the Agent itself. This means that inserting or querying data within your Agent is effectively zero-latency: the Agent doesn't have to round-trip across a continent or the world to access its own data.
114+
115+
TODO
116+
117+
<TypeScriptExample>
118+
119+
```ts
120+
121+
122+
```
123+
124+
</TypeScriptExample>
125+
126+
:::note
127+
128+
Learn more about the zero-latency SQL storage that powers both Agents and Durable Objects [on our blog](https://blog.cloudflare.com/sqlite-in-durable-objects/).
129+
130+
:::
131+
132+
The SQL API exposed to an Agent is identical to the one [within by Durable Objects](/durable-objects/api/sql-storage/). This means that you can use the same SQL queries and commands to interact with the Agent's database.

0 commit comments

Comments
 (0)