agents 0.16.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -8
- package/dist/{agent-tool-types-CTw3UJUP.d.ts → agent-tool-types-Cd1TZPfB.d.ts} +587 -137
- package/dist/agent-tool-types.d.ts +34 -18
- package/dist/agent-tool-types.js +20 -1
- package/dist/agent-tool-types.js.map +1 -0
- package/dist/agent-tools-BXlsuX0d.js +304 -0
- package/dist/agent-tools-BXlsuX0d.js.map +1 -0
- package/dist/agent-tools-_E8wxUIK.d.ts +119 -0
- package/dist/agent-tools.d.ts +24 -18
- package/dist/agent-tools.js.map +1 -1
- package/dist/ai-chat-agent.d.ts +1 -1
- package/dist/ai-chat-agent.js +1 -2
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-chat-v5-migration.d.ts +1 -1
- package/dist/ai-chat-v5-migration.js +1 -2
- package/dist/ai-chat-v5-migration.js.map +1 -1
- package/dist/ai-react.d.ts +1 -1
- package/dist/ai-react.js +1 -2
- package/dist/ai-react.js.map +1 -1
- package/dist/ai-types.d.ts +1 -7
- package/dist/ai-types.js +2 -8
- package/dist/ai-types.js.map +1 -1
- package/dist/browser/ai.js +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/chat/index.d.ts +1918 -72
- package/dist/chat/index.js +1730 -245
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +602 -0
- package/dist/chat/react.js +1506 -0
- package/dist/chat/react.js.map +1 -0
- package/dist/chat-sdk/index.d.ts +4 -4
- package/dist/{classPrivateFieldGet2-CZ7QjTXN.js → classPrivateFieldGet2-DZBYAB34.js} +5 -5
- package/dist/{classPrivateMethodInitSpec-D-0__zd9.js → classPrivateMethodInitSpec-qMjJ6sHQ.js} +2 -2
- package/dist/{client-BXJ9n2f7.js → client-BZ-B3NhC.js} +2 -2
- package/dist/client-BZ-B3NhC.js.map +1 -0
- package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
- package/dist/client.d.ts +76 -57
- package/dist/client.js +33 -5
- package/dist/client.js.map +1 -1
- package/dist/{connector-CrKhowfD.js → connector-CdldGF3h.js} +5 -5
- package/dist/{connector-CrKhowfD.js.map → connector-CdldGF3h.js.map} +1 -1
- package/dist/email.js +1 -1
- package/dist/email.js.map +1 -1
- package/dist/{index-B7IbEeze.d.ts → index-CcbnKkNh.d.ts} +188 -14
- package/dist/index.d.ts +91 -71
- package/dist/index.js +562 -24
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +18 -14
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/index.d.ts +30 -30
- package/dist/mcp/index.js +7 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/{agent-tools-3zLG7MgA.js → message-builder-BymO4N_D.js} +45 -126
- package/dist/message-builder-BymO4N_D.js.map +1 -0
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.js +4 -2
- package/dist/observability/index.js.map +1 -1
- package/dist/react.d.ts +123 -110
- package/dist/react.js +44 -11
- package/dist/react.js.map +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/skills/compile.js +1 -1
- package/dist/skills/compile.js.map +1 -1
- package/dist/skills/index.js +5 -5
- package/dist/skills/index.js.map +1 -1
- package/dist/sub-routing.d.ts +6 -6
- package/dist/utils.js +1 -1
- package/dist/utils.js.map +1 -1
- package/dist/vite.js +5 -5
- package/dist/vite.js.map +1 -1
- package/dist/wire-types-nflOzNuU.js +240 -0
- package/dist/wire-types-nflOzNuU.js.map +1 -0
- package/dist/{workflow-types-SrZK_o9p.d.ts → workflow-types-Baz_PO5v.d.ts} +42 -22
- package/dist/workflow-types.d.ts +25 -21
- package/dist/workflow-types.js.map +1 -1
- package/dist/workflows.d.ts +22 -21
- package/dist/workflows.js +31 -7
- package/dist/workflows.js.map +1 -1
- package/docs/adding-to-existing-project.md +450 -0
- package/docs/agent-class.md +503 -0
- package/docs/agent-tools.md +552 -0
- package/docs/browse-the-web.md +430 -0
- package/docs/callable-methods.md +627 -0
- package/docs/chat-agents.md +1687 -0
- package/docs/chat-sdk.md +181 -0
- package/docs/client-sdk.md +520 -0
- package/docs/client-tools-continuation.md +177 -0
- package/docs/codemode.md +440 -0
- package/docs/configuration.md +775 -0
- package/docs/cross-domain-authentication.md +171 -0
- package/docs/durable-execution.md +537 -0
- package/docs/email.md +663 -0
- package/docs/get-current-agent.md +204 -0
- package/docs/getting-started.md +305 -0
- package/docs/http-websockets.md +668 -0
- package/docs/human-in-the-loop.md +661 -0
- package/docs/index.md +151 -0
- package/docs/long-running-agents.md +730 -0
- package/docs/mcp-client.md +620 -0
- package/docs/mcp-servers.md +526 -0
- package/docs/mcp-transports.md +308 -0
- package/docs/migration-to-ai-sdk-v5.md +96 -0
- package/docs/migration-to-ai-sdk-v6.md +163 -0
- package/docs/observability.md +261 -0
- package/docs/push-notifications.md +367 -0
- package/docs/queue.md +329 -0
- package/docs/readonly-connections.md +278 -0
- package/docs/resumable-streaming.md +127 -0
- package/docs/retries.md +444 -0
- package/docs/routing.md +749 -0
- package/docs/scheduling.md +898 -0
- package/docs/securing-mcp-servers.md +359 -0
- package/docs/server-driven-messages.md +477 -0
- package/docs/sessions.md +1024 -0
- package/docs/state.md +512 -0
- package/docs/sub-agents.md +389 -0
- package/docs/webhooks.md +604 -0
- package/docs/workflows.md +877 -0
- package/package.json +41 -14
- package/dist/agent-tools-3zLG7MgA.js.map +0 -1
- package/dist/agent-tools-DZhI5F6Q.d.ts +0 -14
- package/dist/client-BXJ9n2f7.js.map +0 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# `getCurrentAgent()`
|
|
2
|
+
|
|
3
|
+
## Automatic context for custom methods
|
|
4
|
+
|
|
5
|
+
The framework detects and wraps custom Agent methods during initialization so `getCurrentAgent()` can resolve the active agent inside them and the functions they call.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { AIChatAgent } from "@cloudflare/ai-chat";
|
|
11
|
+
import { getCurrentAgent } from "agents";
|
|
12
|
+
|
|
13
|
+
export class MyAgent extends AIChatAgent {
|
|
14
|
+
async customMethod() {
|
|
15
|
+
const { agent } = getCurrentAgent<MyAgent>();
|
|
16
|
+
// ✅ agent is automatically available!
|
|
17
|
+
console.log(agent.name);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async anotherMethod() {
|
|
21
|
+
// ✅ This works too - no setup needed!
|
|
22
|
+
const { agent } = getCurrentAgent<MyAgent>();
|
|
23
|
+
return agent.state;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Zero configuration required!** The framework automatically:
|
|
29
|
+
|
|
30
|
+
1. Scans your agent class for custom methods
|
|
31
|
+
2. Wraps them with agent context during initialization
|
|
32
|
+
3. Ensures `getCurrentAgent()` works in all external functions called from your methods
|
|
33
|
+
|
|
34
|
+
## Real-World Example
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { AIChatAgent } from "@cloudflare/ai-chat";
|
|
38
|
+
import { getCurrentAgent } from "agents";
|
|
39
|
+
import { generateText } from "ai";
|
|
40
|
+
import { openai } from "@ai-sdk/openai";
|
|
41
|
+
|
|
42
|
+
// External utility function that needs agent context
|
|
43
|
+
async function processWithAI(prompt: string) {
|
|
44
|
+
const { agent } = getCurrentAgent<MyAgent>();
|
|
45
|
+
// ✅ External functions can access the current agent!
|
|
46
|
+
|
|
47
|
+
return await generateText({
|
|
48
|
+
model: openai("gpt-4"),
|
|
49
|
+
prompt: `Agent ${agent?.name}: ${prompt}`
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class MyAgent extends AIChatAgent {
|
|
54
|
+
async customMethod(message: string) {
|
|
55
|
+
// Use this.* to access agent properties directly
|
|
56
|
+
console.log("Agent name:", this.name);
|
|
57
|
+
console.log("Agent state:", this.state);
|
|
58
|
+
|
|
59
|
+
// External functions automatically work!
|
|
60
|
+
const result = await processWithAI(message);
|
|
61
|
+
return result.text;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Built-in vs Custom Methods
|
|
67
|
+
|
|
68
|
+
- **Built-in methods** (onRequest, onEmail, onStateChanged): Already have context
|
|
69
|
+
- **Custom methods** (your methods): Automatically wrapped during initialization
|
|
70
|
+
- **External functions**: Access context through `getCurrentAgent()`
|
|
71
|
+
|
|
72
|
+
### The Context Flow
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// When you call a custom method:
|
|
76
|
+
agent.customMethod()
|
|
77
|
+
→ automatically wrapped with agentContext.run()
|
|
78
|
+
→ your method executes with full context
|
|
79
|
+
→ external functions can use getCurrentAgent()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Common Use Cases
|
|
83
|
+
|
|
84
|
+
### Working with AI SDK Tools
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { AIChatAgent } from "@cloudflare/ai-chat";
|
|
88
|
+
import { generateText } from "ai";
|
|
89
|
+
import { openai } from "@ai-sdk/openai";
|
|
90
|
+
|
|
91
|
+
export class MyAgent extends AIChatAgent {
|
|
92
|
+
async generateResponse(prompt: string) {
|
|
93
|
+
// AI SDK tools automatically work
|
|
94
|
+
const response = await generateText({
|
|
95
|
+
model: openai("gpt-4"),
|
|
96
|
+
prompt,
|
|
97
|
+
tools: {
|
|
98
|
+
// Tools that use getCurrentAgent() work perfectly
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return response.text;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Calling External Libraries
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { AIChatAgent } from "@cloudflare/ai-chat";
|
|
111
|
+
import { getCurrentAgent } from "agents";
|
|
112
|
+
|
|
113
|
+
async function saveToDatabase(data: any) {
|
|
114
|
+
const { agent } = getCurrentAgent<MyAgent>();
|
|
115
|
+
// Can access agent info for logging, context, etc.
|
|
116
|
+
console.log(`Saving data for agent: ${agent?.name}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export class MyAgent extends AIChatAgent {
|
|
120
|
+
async processData(data: any) {
|
|
121
|
+
// External functions automatically have context
|
|
122
|
+
await saveToDatabase(data);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## When context is lost
|
|
128
|
+
|
|
129
|
+
The agent context only propagates along the call tree of the original
|
|
130
|
+
invocation. Code reached outside that call tree starts with an empty context,
|
|
131
|
+
so `getCurrentAgent()` returns an object whose fields are `undefined`. Common
|
|
132
|
+
cases include:
|
|
133
|
+
|
|
134
|
+
- a host callback invoked through RPC from a Worker Loader child isolate, such
|
|
135
|
+
as sandboxed Codemode execution;
|
|
136
|
+
- a service binding or Durable Object RPC entrypoint;
|
|
137
|
+
- a queue consumer or another entrypoint that retains an agent reference.
|
|
138
|
+
|
|
139
|
+
Route the callback through a public method on the agent. Custom methods are
|
|
140
|
+
wrapped automatically, so calling `agent.someMethod()` re-enters that agent's
|
|
141
|
+
context:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { RpcTarget } from "cloudflare:workers";
|
|
145
|
+
|
|
146
|
+
class HostCallbackBridge extends RpcTarget {
|
|
147
|
+
constructor(private agent: MyMcpAgent) {
|
|
148
|
+
super();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Invoked through RPC from a Worker Loader child isolate. There is no context
|
|
152
|
+
// ancestry. Calling a public agent method restores it automatically.
|
|
153
|
+
async invoke() {
|
|
154
|
+
return this.agent.handleSandboxCallback();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export class MyMcpAgent extends McpAgent {
|
|
159
|
+
async handleSandboxCallback() {
|
|
160
|
+
const { agent } = getCurrentAgent<MyMcpAgent>();
|
|
161
|
+
// `agent` is available again.
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Context restored this way has `connection`, `request`, and `email` unset. It
|
|
167
|
+
is not tied to live client I/O.
|
|
168
|
+
|
|
169
|
+
Server-initiated MCP requests (`elicitInput`, `createMessage`, and `listRoots`)
|
|
170
|
+
on `McpAgent` do not require this indirection because the MCP transport retains
|
|
171
|
+
its owning agent.
|
|
172
|
+
|
|
173
|
+
## API reference
|
|
174
|
+
|
|
175
|
+
The agents package exports one main function for context management:
|
|
176
|
+
|
|
177
|
+
### `getCurrentAgent<T>()`
|
|
178
|
+
|
|
179
|
+
Gets the current agent from any context where it's available.
|
|
180
|
+
|
|
181
|
+
**Returns:**
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
{
|
|
185
|
+
agent: T | undefined,
|
|
186
|
+
connection: Connection | undefined,
|
|
187
|
+
request: Request | undefined
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Usage:**
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { AIChatAgent } from "@cloudflare/ai-chat";
|
|
195
|
+
import { getCurrentAgent } from "agents";
|
|
196
|
+
|
|
197
|
+
export class MyAgent extends AIChatAgent {
|
|
198
|
+
async customMethod() {
|
|
199
|
+
const { agent, connection, request } = getCurrentAgent<MyAgent>();
|
|
200
|
+
// agent is properly typed as MyAgent
|
|
201
|
+
// connection and request available if called from a request handler
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Build AI agents that persist, think, and act. Agents run on Cloudflare's global network, maintain state across requests, and connect to clients in real-time via WebSockets.
|
|
4
|
+
|
|
5
|
+
**What you'll build:** A counter agent with persistent state that syncs to a React frontend in real-time.
|
|
6
|
+
|
|
7
|
+
**Time:** ~10 minutes
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Create a New Project
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm create cloudflare@latest -- --template cloudflare/agents-starter
|
|
15
|
+
cd my-agent
|
|
16
|
+
npm install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This creates a project with:
|
|
20
|
+
|
|
21
|
+
- `src/server.ts` - Your agent code
|
|
22
|
+
- `src/client.tsx` - React frontend
|
|
23
|
+
- `wrangler.jsonc` - Cloudflare configuration
|
|
24
|
+
- `tsconfig.json` - Extends `agents/tsconfig` for correct decorator and module settings
|
|
25
|
+
- `vite.config.ts` - Includes the `agents/vite` plugin for decorator support
|
|
26
|
+
|
|
27
|
+
The starter template includes two SDK integrations that are required for `@callable()` decorators. If you are setting up a project manually, add both:
|
|
28
|
+
|
|
29
|
+
**tsconfig.json** — extends `agents/tsconfig`, which sets `target: "ES2021"` and other recommended options:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"extends": "agents/tsconfig"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**vite.config.ts** — includes the `agents()` plugin, which handles TC39 decorator transforms (required because Vite 8's Oxc transpiler does not support them yet):
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
41
|
+
import react from "@vitejs/plugin-react";
|
|
42
|
+
import agents from "agents/vite";
|
|
43
|
+
import { defineConfig } from "vite";
|
|
44
|
+
|
|
45
|
+
export default defineConfig({
|
|
46
|
+
plugins: [agents(), react(), cloudflare()]
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Start the dev server:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm run dev
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Open [http://localhost:5173](http://localhost:5173) to see your agent in action.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Your First Agent
|
|
61
|
+
|
|
62
|
+
Let's build a simple counter agent from scratch. Replace `src/server.ts`:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Agent, routeAgentRequest, callable } from "agents";
|
|
66
|
+
|
|
67
|
+
// Define the state shape
|
|
68
|
+
type CounterState = {
|
|
69
|
+
count: number;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Create the agent
|
|
73
|
+
export class Counter extends Agent<Env, CounterState> {
|
|
74
|
+
// Initial state for new instances
|
|
75
|
+
initialState: CounterState = { count: 0 };
|
|
76
|
+
|
|
77
|
+
// Methods marked with @callable can be called from the client
|
|
78
|
+
@callable()
|
|
79
|
+
increment() {
|
|
80
|
+
this.setState({ count: this.state.count + 1 });
|
|
81
|
+
return this.state.count;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@callable()
|
|
85
|
+
decrement() {
|
|
86
|
+
this.setState({ count: this.state.count - 1 });
|
|
87
|
+
return this.state.count;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@callable()
|
|
91
|
+
reset() {
|
|
92
|
+
this.setState({ count: 0 });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Route requests to agents
|
|
97
|
+
export default {
|
|
98
|
+
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
|
|
99
|
+
return (
|
|
100
|
+
(await routeAgentRequest(request, env)) ??
|
|
101
|
+
new Response("Not found", { status: 404 })
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Update `wrangler.jsonc` to register the agent:
|
|
108
|
+
|
|
109
|
+
```jsonc
|
|
110
|
+
{
|
|
111
|
+
"name": "my-agent",
|
|
112
|
+
"main": "src/server.ts",
|
|
113
|
+
"compatibility_date": "2025-01-01",
|
|
114
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
115
|
+
"durable_objects": {
|
|
116
|
+
"bindings": [
|
|
117
|
+
{
|
|
118
|
+
"name": "Counter",
|
|
119
|
+
"class_name": "Counter"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"migrations": [
|
|
124
|
+
{
|
|
125
|
+
"tag": "v1",
|
|
126
|
+
"new_sqlite_classes": ["Counter"]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Connect from React
|
|
135
|
+
|
|
136
|
+
Replace `src/client.tsx`:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { useAgent } from "agents/react";
|
|
140
|
+
|
|
141
|
+
// Match your agent's state type
|
|
142
|
+
type CounterState = {
|
|
143
|
+
count: number;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export default function App() {
|
|
147
|
+
// Connect to the Counter agent
|
|
148
|
+
const agent = useAgent<CounterState>({
|
|
149
|
+
agent: "Counter"
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<div style={{ padding: "2rem", fontFamily: "system-ui" }}>
|
|
154
|
+
<h1>Counter Agent</h1>
|
|
155
|
+
<p style={{ fontSize: "3rem" }}>{agent.state?.count ?? 0}</p>
|
|
156
|
+
<div style={{ display: "flex", gap: "1rem" }}>
|
|
157
|
+
<button onClick={() => agent.stub.decrement()}>-</button>
|
|
158
|
+
<button onClick={() => agent.stub.reset()}>Reset</button>
|
|
159
|
+
<button onClick={() => agent.stub.increment()}>+</button>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Key points:
|
|
167
|
+
|
|
168
|
+
- **`useAgent`** connects to your agent via WebSocket
|
|
169
|
+
- **`agent.state`** is reactive — the component re-renders when state changes
|
|
170
|
+
- **`agent.stub.methodName()`** calls methods marked with `@callable()` on your agent
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## What Just Happened?
|
|
175
|
+
|
|
176
|
+
When you clicked the button:
|
|
177
|
+
|
|
178
|
+
1. **Client** called `agent.stub.increment()` over WebSocket
|
|
179
|
+
2. **Agent** ran `increment()`, updated state with `setState()`
|
|
180
|
+
3. **State** persisted to SQLite automatically
|
|
181
|
+
4. **Broadcast** sent to all connected clients
|
|
182
|
+
5. **React** re-rendered with updated `agent.state`
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
┌─────────────┐ ┌─────────────┐
|
|
186
|
+
│ Browser │◄───────►│ Agent │
|
|
187
|
+
│ (React) │ WS │ (Counter) │
|
|
188
|
+
└─────────────┘ └──────┬──────┘
|
|
189
|
+
│
|
|
190
|
+
┌──────▼──────┐
|
|
191
|
+
│ SQLite │
|
|
192
|
+
│ (State) │
|
|
193
|
+
└─────────────┘
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Key Concepts
|
|
197
|
+
|
|
198
|
+
| Concept | What it means |
|
|
199
|
+
| -------------------- | ------------------------------------------------------------------------------------------- |
|
|
200
|
+
| **Agent instance** | Each unique name gets its own agent. `Counter:user-123` is separate from `Counter:user-456` |
|
|
201
|
+
| **Persistent state** | State survives restarts, deploys, and hibernation. It's stored in SQLite |
|
|
202
|
+
| **Real-time sync** | All clients connected to the same agent receive state updates instantly |
|
|
203
|
+
| **Hibernation** | When no clients are connected, the agent hibernates (no cost). It wakes on the next request |
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Connect from Vanilla JS
|
|
208
|
+
|
|
209
|
+
If you're not using React:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { AgentClient } from "agents/client";
|
|
213
|
+
|
|
214
|
+
const agent = new AgentClient({
|
|
215
|
+
agent: "Counter",
|
|
216
|
+
name: "my-counter", // optional, defaults to "default"
|
|
217
|
+
host: window.location.host
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
await agent.ready;
|
|
221
|
+
|
|
222
|
+
// Call methods
|
|
223
|
+
await agent.call("increment");
|
|
224
|
+
console.log("Current count:", agent.state?.count);
|
|
225
|
+
|
|
226
|
+
await agent.call("reset");
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Deploy to Cloudflare
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
npm run deploy
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Your agent is now live on Cloudflare's global network, running close to your users.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Next Steps
|
|
242
|
+
|
|
243
|
+
Now that you have a working agent, explore these topics:
|
|
244
|
+
|
|
245
|
+
- **[State Management](./state.md)** - Deep dive into `setState()`, `initialState`, and `onStateChanged()`
|
|
246
|
+
- **[Client SDK](./client-sdk.md)** - Full `useAgent` and `AgentClient` API reference
|
|
247
|
+
- **[Scheduling](./scheduling.md)** - Run tasks on a delay, schedule, or cron
|
|
248
|
+
- **[Agent Class](./agent-class.md)** - Lifecycle methods, HTTP handlers, and WebSocket events
|
|
249
|
+
|
|
250
|
+
### Common Patterns
|
|
251
|
+
|
|
252
|
+
| I want to... | Read... |
|
|
253
|
+
| ------------------------ | ---------------------------------------- |
|
|
254
|
+
| Add AI/LLM capabilities | [Chat Agents](./chat-agents.md) |
|
|
255
|
+
| Expose tools via MCP | [Creating MCP Servers](./mcp-servers.md) |
|
|
256
|
+
| Run background tasks | [Scheduling](./scheduling.md) |
|
|
257
|
+
| Handle emails | [Email Service](./email.md) |
|
|
258
|
+
| Use Cloudflare Workflows | [Workflows](./workflows.md) |
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Troubleshooting
|
|
263
|
+
|
|
264
|
+
### "Agent not found" / 404 errors
|
|
265
|
+
|
|
266
|
+
Make sure:
|
|
267
|
+
|
|
268
|
+
1. Agent class is exported from your server file
|
|
269
|
+
2. `wrangler.jsonc` has the binding and migration
|
|
270
|
+
3. Agent name in client matches the class name (case-insensitive)
|
|
271
|
+
|
|
272
|
+
### State not syncing
|
|
273
|
+
|
|
274
|
+
Check that:
|
|
275
|
+
|
|
276
|
+
1. You're calling `this.setState()`, not mutating `this.state` directly
|
|
277
|
+
2. Your agent has `initialState` defined (state is only sent on connect if the agent has state)
|
|
278
|
+
3. WebSocket connection is established (check browser dev tools)
|
|
279
|
+
|
|
280
|
+
### "Method X is not callable" errors
|
|
281
|
+
|
|
282
|
+
Make sure your methods are decorated with `@callable()`:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { callable } from "agents";
|
|
286
|
+
|
|
287
|
+
@callable()
|
|
288
|
+
increment() {
|
|
289
|
+
// ...
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Type errors with `agent.stub`
|
|
294
|
+
|
|
295
|
+
Add the agent type parameter:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
const agent = useAgent<Counter, CounterState>({
|
|
299
|
+
agent: "Counter",
|
|
300
|
+
onStateUpdate: (state) => setCount(state.count)
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Now agent.stub is fully typed
|
|
304
|
+
agent.stub.increment(); // ✓ TypeScript knows this method exists
|
|
305
|
+
```
|