Skip to content

Commit 60d0f2f

Browse files
committed
websockets
1 parent 32be3ca commit 60d0f2f

File tree

3 files changed

+174
-9
lines changed

3 files changed

+174
-9
lines changed

src/content/docs/agents/examples/browse-the-web.mdx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ npm install @cloudflare/puppeteer --save-dev
3838
<WranglerConfig>
3939

4040
```jsonc
41-
"browser": {
41+
{
42+
// ...
43+
"browser": {
4244
"binding": "MYBROWSER"
43-
},
45+
}
46+
// ...
47+
}
4448
```
4549

4650
</WranglerConfig>

src/content/docs/agents/examples/schedule-tasks.mdx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,48 @@ import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/com
99

1010
An Agent can schedule tasks to be run in the future by calling `this.schedule(when, callback, data)`, where `when` can be a delay, a `Date`, or a cron string; `callback` the function name to call, and `data` is an object of data to pass to the function.
1111

12-
Scheduled tasks can do anything a request or message from a user can: make requests, query databases, send emails, read+write state, etc.
12+
Scheduled tasks can do anything a request or message from a user can: make requests, query databases, send emails, read+write state: scheduled tasks can invoke any regular method on your Agent.
1313

1414
### Scheduling tasks
1515

16-
You can call `this.schedule` within any method on an Agent, and schedule tens-of-thousands of tasks per individual Agent.
16+
You can call `this.schedule` within any method on an Agent, and schedule tens-of-thousands of tasks per individual Agent:
17+
18+
```ts
19+
import { Agent } from "@cloudflare/agents"
20+
21+
export class SchedulingAgent extends Agent {
22+
async onRequest(request) {
23+
// Handle an incoming request
24+
// Schedule a task 5 minutes from now
25+
// Calls the "checkFlights" method
26+
let { taskId } = await this.schedule(600, "checkFlights", { flight: "DL264", date: "2025-02-23" });
27+
return Response.json({ taskId });
28+
}
29+
30+
async checkFlights(data) {
31+
// Invoked when our scheduled task runs
32+
// We can also call this.schedule here to schedule another task
33+
}
34+
}
35+
```
36+
</TypeScriptExample>
37+
38+
You can schedule tasks in multiple ways:
1739

1840
<TypeScriptExample>
1941

2042
```ts
2143
// schedule a task to run in 10 seconds
22-
let task = await this.schedule(10, "myTask", { message: "hello" });
44+
let task = await this.schedule(10, "someTask", { message: "hello" });
2345

2446
// schedule a task to run at a specific date
25-
let task = await this.schedule(new Date("2025-01-01"), "myTask", { message: "hello" });
47+
let task = await this.schedule(new Date("2025-01-01"), "someTask", {});
2648

2749
// schedule a task to run every 10 seconds
28-
let { id } = await this.schedule("*/10 * * * *", "myTask", { message: "hello" });
50+
let { id } = await this.schedule("*/10 * * * *", "someTask", { message: "hello" });
2951

3052
// schedule a task to run every 10 seconds, but only on Mondays
31-
let task = await this.schedule("0 0 * * 1", "myTask", { message: "hello" });
53+
let task = await this.schedule("0 0 * * 1", "someTask", { message: "hello" });
3254

3355
// cancel a scheduled task
3456
this.cancelSchedule(task.id);

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

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,143 @@ sidebar:
88

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

11-
TODO
11+
Users and clients can connect to an Agent directly over WebSockets, allowing long-running, bi-directional communication with your Agent as it operates.
12+
13+
To enable an Agent to accept WebSockets, define `onConnect` and `onMessage` methods on your Agent.
14+
15+
* `onConnect(connection: Connection, ctx: ConnectionContext)` is called when a client establishes a new WebSocket connection. The original HTTP request, including request headers, cookies and the URL itself, are available on `ctx.request`.
16+
* `onMessage(connection: Connection, message: WSMessage)` is called for each incoming WebSocket message. Messages are one of `ArrayBuffer | ArrayBufferView | string`, and you can send messages back to a client using `connection.send()`. You can distinguish between client connections by checking `connection.id`, which is unique for each connected client.
17+
18+
Here's an example of an Agent that echoes back any message it receives:
19+
20+
<TypeScriptExample>
21+
22+
```ts
23+
import { Agent, Connection } from "@cloudflare/agents";
24+
25+
export class ChatAgent extends Agent {
26+
async onConnect(connection: Connection, ctx: ConnectionContext) {
27+
// Access the request to verify any authentication tokens
28+
// provided in headers or cookies
29+
let token = ctx.request.headers.get("Authorization");
30+
if (!token) {
31+
await connection.close(4000, "Unauthorized");
32+
return;
33+
}
34+
35+
// Handle auth using your favorite library and/or auth scheme:
36+
// try {
37+
// await jwt.verify(token, env.JWT_SECRET);
38+
// } catch (error) {
39+
// connection.close(4000, 'Invalid Authorization header');
40+
// return;
41+
// }
42+
43+
// Accept valid connections
44+
connection.accept()
45+
}
46+
47+
async onMessage(connection: Connection, message: WSMessage) {
48+
// const response = await longRunningAITask(message)
49+
await connection.send(message)
50+
}
51+
}
52+
```
53+
54+
</TypeScriptExample>
55+
56+
## Connecting clients
57+
58+
The Agent framework includes a useful helper package for connecting directly to your agent (or other agents) from a client application. Import `@cloudflare/agents/client`, create an instance of `AgentClient` and use it to connect to an instance of your Agent:
59+
60+
<TypeScriptExample>
61+
62+
```ts
63+
import { AgentClient } from "@cloudflare/agents/client";
64+
65+
const connection = new AgentClient({
66+
agent: "dialogue-agent",
67+
name: "insight-seeker",
68+
});
69+
70+
connection.addEventListener("message", (event) => {
71+
console.log("Received:", event.data);
72+
});
73+
74+
connection.send(
75+
JSON.stringify({
76+
type: "inquiry",
77+
content: "What patterns do you see?",
78+
})
79+
);
80+
```
81+
82+
</TypeScriptExample>
83+
84+
## React clients
85+
86+
React-based applications can import `@cloudflare/agents/react` and use the `useAgent` hook to connect to an instance of an Agent directly:
87+
88+
<TypeScriptExample>
89+
90+
```ts
91+
import { useAgent } from "@cloudflare/agents/react";
92+
93+
function AgentInterface() {
94+
const connection = useAgent({
95+
agent: "dialogue-agent",
96+
name: "insight-seeker",
97+
onMessage: (message) => {
98+
console.log("Understanding received:", message.data);
99+
},
100+
onOpen: () => console.log("Connection established"),
101+
onClose: () => console.log("Connection closed"),
102+
});
103+
104+
const inquire = () => {
105+
connection.send(
106+
JSON.stringify({
107+
type: "inquiry",
108+
content: "What insights have you gathered?",
109+
})
110+
);
111+
};
112+
113+
return (
114+
<div className="agent-interface">
115+
<button onClick={inquire}>Seek Understanding</button>
116+
</div>
117+
);
118+
}
119+
120+
```
121+
</TypeScriptExample>
122+
123+
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.
124+
125+
## Handling WebSocket events
126+
127+
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:
128+
129+
<TypeScriptExample>
130+
131+
```ts
132+
import { Agent, Connection } from "@cloudflare/agents";
133+
134+
export class ChatAgent extends Agent {
135+
// onConnect and onMessage methods
136+
// ...
137+
138+
// WebSocket error and disconnection (close) handling.
139+
async onError(connection: Connection, error: unknown): Promise<void> {
140+
console.error(`WS error: ${error}`);
141+
}
142+
async onClose(connection: Connection, code: number, reason: string, wasClean: boolean): Promise<void> {
143+
console.log(`WS closed: ${code} - ${reason} - wasClean: ${wasClean}`);
144+
connection.close();
145+
}
146+
}
147+
148+
```
149+
150+
</TypeScriptExample>

0 commit comments

Comments
 (0)