@projectaria/cf-agents 0.1.1 → 0.1.3
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 +358 -253
- package/dist/AriaCFChatAgent.d.ts +37 -0
- package/dist/AriaCFChatAgent.d.ts.map +1 -0
- package/dist/AriaCFChatAgent.js +203 -0
- package/dist/AriaCFChatAgent.js.map +1 -0
- package/dist/CloudflareSessionStore.d.ts +37 -0
- package/dist/CloudflareSessionStore.d.ts.map +1 -0
- package/dist/CloudflareSessionStore.js +101 -0
- package/dist/CloudflareSessionStore.js.map +1 -0
- package/dist/aria-to-ui-stream.d.ts +21 -0
- package/dist/aria-to-ui-stream.d.ts.map +1 -0
- package/dist/aria-to-ui-stream.js +118 -0
- package/dist/aria-to-ui-stream.js.map +1 -0
- package/dist/index.d.ts +25 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -23
- package/dist/index.js.map +1 -1
- package/dist/message-format.d.ts +39 -0
- package/dist/message-format.d.ts.map +1 -0
- package/dist/message-format.js +124 -0
- package/dist/message-format.js.map +1 -0
- package/dist/types.d.ts +59 -146
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -7
- package/dist/types.js.map +1 -1
- package/package.json +3 -2
- package/dist/AriaAgent.d.ts +0 -186
- package/dist/AriaAgent.d.ts.map +0 -1
- package/dist/AriaAgent.js +0 -756
- package/dist/AriaAgent.js.map +0 -1
- package/dist/aria-agent-integration.d.ts +0 -52
- package/dist/aria-agent-integration.d.ts.map +0 -1
- package/dist/aria-agent-integration.js +0 -186
- package/dist/aria-agent-integration.js.map +0 -1
- package/dist/message-converter.d.ts +0 -48
- package/dist/message-converter.d.ts.map +0 -1
- package/dist/message-converter.js +0 -138
- package/dist/message-converter.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @projectaria/cf-agents
|
|
2
2
|
|
|
3
|
-
ARIA integration for Cloudflare Workers with Durable Objects. Build stateful AI agents with persistent memory, session management, and multi-turn conversations.
|
|
3
|
+
ARIA integration for Cloudflare Workers with Durable Objects. Build stateful AI agents with persistent memory, session management, and multi-turn conversations using structured flows.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,45 +8,228 @@ ARIA integration for Cloudflare Workers with Durable Objects. Build stateful AI
|
|
|
8
8
|
npm install @projectaria/cf-agents agents @cloudflare/ai-chat ai
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Message Flow Architecture
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
15
|
+
│ MESSAGE FLOW DIAGRAM │
|
|
16
|
+
├─────────────────────────────────────────────────────────────────────────────┤
|
|
17
|
+
│ │
|
|
18
|
+
│ CLIENT SIDE SERVER SIDE │
|
|
19
|
+
│ ──────────── ──────────── │
|
|
20
|
+
│ │
|
|
21
|
+
│ User Input │
|
|
22
|
+
│ │ │
|
|
23
|
+
│ ▼ │
|
|
24
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
25
|
+
│ │ Cloudflare AIChatAgent │ │
|
|
26
|
+
│ │ this.messages (UIMessage[]) ←── WebSocket/HTTP │ │
|
|
27
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
28
|
+
│ │ │
|
|
29
|
+
│ │ onChatMessage() │
|
|
30
|
+
│ ▼ │
|
|
31
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
32
|
+
│ │ AriaCFChatAgent │ │
|
|
33
|
+
│ │ │ │
|
|
34
|
+
│ │ 1. extractLastUserInput() → userText │ │
|
|
35
|
+
│ │ 2. cloudflareToAriaSession() → AgentSession │ │
|
|
36
|
+
│ │ │ │ │
|
|
37
|
+
│ │ ▼ │ │
|
|
38
|
+
│ │ 3. ariaAgent.streamText({ input, session }) │ │
|
|
39
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
40
|
+
│ │ │
|
|
41
|
+
│ │ (AsyncIterable<AriaStreamPart>) │
|
|
42
|
+
│ ▼ │
|
|
43
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
44
|
+
│ │ ARIA Agent │ │
|
|
45
|
+
│ │ createAgent() │ │
|
|
46
|
+
│ │ │ │ │
|
|
47
|
+
│ │ ▼ │ │
|
|
48
|
+
│ │ streamText() │ │
|
|
49
|
+
│ │ │ │ │
|
|
50
|
+
│ │ ▼ │ │
|
|
51
|
+
│ │ ┌────────────────────────────────────────────────────────────────┐ │ │
|
|
52
|
+
│ │ │ PromptBuilder + Conversation Context │ │ │
|
|
53
|
+
│ │ └────────────────────────────────────────────────────────────────┘ │ │
|
|
54
|
+
│ │ │ │ │
|
|
55
|
+
│ │ ▼ │ │
|
|
56
|
+
│ │ ┌────────────────────────────────────────────────────────────────┐ │ │
|
|
57
|
+
│ │ │ AI SDK LanguageModel │ │ │
|
|
58
|
+
│ │ │ streamText(model, messages, tools) │ │ │
|
|
59
|
+
│ │ └────────────────────────────────────────────────────────────────┘ │ │
|
|
60
|
+
│ │ │ │ │
|
|
61
|
+
│ │ ▼ (stream of TextStreamPart) │ │
|
|
62
|
+
│ │ ┌────────────────────────────────────────────────────────────────┐ │ │
|
|
63
|
+
│ │ │ ResponseService / Tool Execution │ │ │
|
|
64
|
+
│ │ └────────────────────────────────────────────────────────────────┘ │ │
|
|
65
|
+
│ │ │ │ │
|
|
66
|
+
│ │ ▼ (AriaStreamPart: text-delta, tool-call, tool-result, ...) │ │
|
|
67
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
68
|
+
│ │ │
|
|
69
|
+
│ │ ariaToUIStream() │
|
|
70
|
+
│ ▼ │
|
|
71
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
72
|
+
│ │ aria-to-ui-stream.ts │ │
|
|
73
|
+
│ │ AriaStreamPart → TextUIPart | ToolCallUIPart | ToolResultUIPart │ │
|
|
74
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
75
|
+
│ │ │
|
|
76
|
+
│ │ createUIMessageStreamResponse() │
|
|
77
|
+
│ ▼ │
|
|
78
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
79
|
+
│ │ Response (SSE/WebSocket) │ │
|
|
80
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
81
|
+
│ │ │
|
|
82
|
+
│ ▼ │
|
|
83
|
+
│ CLIENT UI ←───────────────────────────────────────────────────────────────
|
|
84
|
+
│ │
|
|
85
|
+
├─────────────────────────────────────────────────────────────────────────────┤
|
|
86
|
+
│ SESSION & STATE FLOW │
|
|
87
|
+
├─────────────────────────────────────────────────────────────────────────────┤
|
|
88
|
+
│ │
|
|
89
|
+
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
90
|
+
│ │ VoltRuntime │ │
|
|
91
|
+
│ │ │ │
|
|
92
|
+
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
|
|
93
|
+
│ │ │ FlowSupervisor │ │ │
|
|
94
|
+
│ │ │ • Selects active flow based on intent │ │ │
|
|
95
|
+
│ │ │ • Handles flow switching mid-conversation │ │ │
|
|
96
|
+
│ │ └───────────────────────────────────────────────────────────────┘ │ │
|
|
97
|
+
│ │ │ │ │
|
|
98
|
+
│ │ ▼ │ │
|
|
99
|
+
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
|
|
100
|
+
│ │ │ StreamingFlowManager │ │ │
|
|
101
|
+
│ │ │ • Executes current node │ │ │
|
|
102
|
+
│ │ │ • Validates extracted data │ │ │
|
|
103
|
+
│ │ │ • Evaluates transitions │ │ │
|
|
104
|
+
│ │ └───────────────────────────────────────────────────────────────┘ │ │
|
|
105
|
+
│ │ │ │ │
|
|
106
|
+
│ │ ▼ │ │
|
|
107
|
+
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
|
|
108
|
+
│ │ │ CombinedAnalysisService │ │ │
|
|
109
|
+
│ │ │ • LLM validation of extracted fields │ │ │
|
|
110
|
+
│ │ │ • Structured data extraction │ │ │
|
|
111
|
+
│ │ └───────────────────────────────────────────────────────────────┘ │ │
|
|
112
|
+
│ │ │ │ │
|
|
113
|
+
│ │ ▼ │ │
|
|
114
|
+
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
|
|
115
|
+
│ │ │ ProgressionEngine │ │ │
|
|
116
|
+
│ │ │ • Evaluates condition expressions │ │ │
|
|
117
|
+
│ │ │ • Determines next node │ │ │
|
|
118
|
+
│ │ └───────────────────────────────────────────────────────────────┘ │ │
|
|
119
|
+
│ │ │ │ │
|
|
120
|
+
│ │ ▼ │ │
|
|
121
|
+
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
|
|
122
|
+
│ │ │ SessionStore (SQLite via D1) │ │ │
|
|
123
|
+
│ │ │ • Persists session.history │ │ │
|
|
124
|
+
│ │ │ • Persists session.workingMemory │ │ │
|
|
125
|
+
│ │ │ • Restores sessions on agent restart │ │ │
|
|
126
|
+
│ │ └───────────────────────────────────────────────────────────────┘ │ │
|
|
127
|
+
│ │ │ │
|
|
128
|
+
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
129
|
+
│ │
|
|
130
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
131
|
+
```
|
|
12
132
|
|
|
13
|
-
|
|
133
|
+
## Message Handling Sequence
|
|
14
134
|
|
|
15
135
|
```typescript
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
136
|
+
// 1. Client sends message via WebSocket or HTTP
|
|
137
|
+
// → Cloudflare AIChatAgent receives it
|
|
138
|
+
// → Stores in this.messages
|
|
139
|
+
|
|
140
|
+
// 2. AriaCFChatAgent.onChatMessage() is called
|
|
141
|
+
async onChatMessage(onFinish, options) {
|
|
142
|
+
// 2a. Extract user text from last message
|
|
143
|
+
const userText = extractLastUserInput(this.messages);
|
|
144
|
+
|
|
145
|
+
// 2b. Convert Cloudflare messages to ARIA session format
|
|
146
|
+
const ariaSession = cloudflareToAriaSession(this.messages, this.state);
|
|
20
147
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
148
|
+
// 2c. Start session in VoltRuntime (loads or creates)
|
|
149
|
+
await this.voltRuntime.startSession(ariaSession.sessionId);
|
|
150
|
+
|
|
151
|
+
// 2d. Stream from ARIA agent
|
|
152
|
+
const result = await this.ariaAgent.streamText({
|
|
153
|
+
input: userText,
|
|
154
|
+
session: ariaSession,
|
|
28
155
|
});
|
|
29
156
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const session = this.getSession();
|
|
34
|
-
const lastMessage = session.messages[session.messages.length - 1];
|
|
157
|
+
// 2e. Convert ARIA stream parts to UI format
|
|
158
|
+
return createARIAStreamResponse(result.fullStream, onFinish);
|
|
159
|
+
}
|
|
35
160
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
161
|
+
// 3. ARIA Agent processes the stream
|
|
162
|
+
streamText({ input, session }) {
|
|
163
|
+
// 3a. Build prompt from flow + session history
|
|
164
|
+
const prompt = PromptBuilder.build({
|
|
165
|
+
flow: currentFlow,
|
|
166
|
+
session,
|
|
167
|
+
instructions,
|
|
168
|
+
guidelines,
|
|
169
|
+
});
|
|
39
170
|
|
|
40
|
-
|
|
41
|
-
|
|
171
|
+
// 3b. Call LLM with prompt + tools
|
|
172
|
+
return streamText(model, messages, tools);
|
|
173
|
+
}
|
|
42
174
|
|
|
43
|
-
|
|
44
|
-
|
|
175
|
+
// 4. Stream parts are emitted:
|
|
176
|
+
// - text-delta → UI text chunk
|
|
177
|
+
// - tool-call → UI tool call (input-available)
|
|
178
|
+
// - tool-result → UI tool result (output-available)
|
|
179
|
+
// - reasoning-delta → UI reasoning part
|
|
45
180
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
181
|
+
// 5. Session is updated with working memory changes
|
|
182
|
+
// → Persisted to SQLite via SessionStore
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Quick Start
|
|
186
|
+
|
|
187
|
+
### 1. Create Your Agent with a Flow
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// src/agent.ts
|
|
191
|
+
import { createAriaCFChatAgent } from "@projectaria/cf-agents";
|
|
192
|
+
import type { FlowDefinition } from "@projectaria/aria-agents";
|
|
193
|
+
import { z } from "zod";
|
|
194
|
+
|
|
195
|
+
interface Env {
|
|
196
|
+
AI: Ai;
|
|
197
|
+
DB: D1Database;
|
|
49
198
|
}
|
|
199
|
+
|
|
200
|
+
// Define a conversation flow
|
|
201
|
+
const greetingFlow: FlowDefinition = {
|
|
202
|
+
id: "greeting",
|
|
203
|
+
name: "Greeting Assistant",
|
|
204
|
+
startNodeId: "greet",
|
|
205
|
+
nodes: {
|
|
206
|
+
greet: {
|
|
207
|
+
id: "greet",
|
|
208
|
+
type: "task",
|
|
209
|
+
instructions: "Welcome the user and ask how you can help.",
|
|
210
|
+
transitions: [
|
|
211
|
+
{ nextNodeId: "help", condition: "intent == 'help'" },
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
help: {
|
|
215
|
+
id: "help",
|
|
216
|
+
type: "task",
|
|
217
|
+
instructions: "Provide helpful assistance.",
|
|
218
|
+
transitions: [
|
|
219
|
+
{ nextNodeId: "greet", condition: "always" },
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Create agent with any AI SDK model
|
|
226
|
+
const MyAgent = createAriaCFChatAgent<Env>({
|
|
227
|
+
flows: new Map([[greetingFlow.id, greetingFlow]]),
|
|
228
|
+
model: env.AI("@cf/meta/llama-3.1-8b-instruct"), // Any LanguageModel
|
|
229
|
+
instructions: "You are a friendly assistant.",
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
export { MyAgent };
|
|
50
233
|
```
|
|
51
234
|
|
|
52
235
|
### 2. Configure Your Worker
|
|
@@ -54,13 +237,12 @@ export class MyAssistant extends AriaAgent {
|
|
|
54
237
|
```typescript
|
|
55
238
|
// src/index.ts
|
|
56
239
|
import { routeAgentRequest } from "agents";
|
|
57
|
-
import {
|
|
240
|
+
import { MyAgent } from "./agent";
|
|
58
241
|
|
|
59
|
-
export {
|
|
242
|
+
export { MyAgent };
|
|
60
243
|
|
|
61
244
|
export default {
|
|
62
245
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
63
|
-
// Route requests to your agent
|
|
64
246
|
return (
|
|
65
247
|
(await routeAgentRequest(request, env)) ||
|
|
66
248
|
new Response("Not found", { status: 404 })
|
|
@@ -71,28 +253,18 @@ export default {
|
|
|
71
253
|
|
|
72
254
|
### 3. Configure Wrangler
|
|
73
255
|
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
},
|
|
89
|
-
"migrations": [
|
|
90
|
-
{
|
|
91
|
-
"tag": "v1",
|
|
92
|
-
"new_sqlite_classes": ["MyAssistant"]
|
|
93
|
-
}
|
|
94
|
-
]
|
|
95
|
-
}
|
|
256
|
+
```toml
|
|
257
|
+
# wrangler.toml
|
|
258
|
+
name = "my-assistant"
|
|
259
|
+
main = "src/index.ts"
|
|
260
|
+
compatibility_date = "2025-02-11"
|
|
261
|
+
|
|
262
|
+
[[d1_databases]]
|
|
263
|
+
binding = "DB"
|
|
264
|
+
database_name = "aria-sessions"
|
|
265
|
+
|
|
266
|
+
[ai]
|
|
267
|
+
binding = "AI"
|
|
96
268
|
```
|
|
97
269
|
|
|
98
270
|
### 4. Deploy
|
|
@@ -103,100 +275,160 @@ npx wrangler deploy
|
|
|
103
275
|
|
|
104
276
|
## Features
|
|
105
277
|
|
|
106
|
-
###
|
|
278
|
+
### Flow Orchestration
|
|
279
|
+
|
|
280
|
+
Define structured multi-turn conversations:
|
|
107
281
|
|
|
108
|
-
|
|
282
|
+
```typescript
|
|
283
|
+
const orderFlow: FlowDefinition = {
|
|
284
|
+
id: "order",
|
|
285
|
+
startNodeId: "collect-items",
|
|
286
|
+
nodes: {
|
|
287
|
+
"collect-items": {
|
|
288
|
+
id: "collect-items",
|
|
289
|
+
type: "task",
|
|
290
|
+
instructions: "Ask which items they want to order.",
|
|
291
|
+
transitions: [
|
|
292
|
+
{ nextNodeId: "confirm", condition: "items selected" },
|
|
293
|
+
],
|
|
294
|
+
},
|
|
295
|
+
confirm: {
|
|
296
|
+
id: "confirm",
|
|
297
|
+
type: "task",
|
|
298
|
+
instructions: "Show order summary and ask for confirmation.",
|
|
299
|
+
transitions: [
|
|
300
|
+
{ nextNodeId: "complete", condition: "confirmed" },
|
|
301
|
+
{ nextNodeId: "collect-items", condition: "cancelled" },
|
|
302
|
+
],
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
```
|
|
109
307
|
|
|
110
|
-
|
|
111
|
-
|-------------|-------|----------|
|
|
112
|
-
| **Session** | Current conversation | Message history, flow state |
|
|
113
|
-
| **State** | Working memory | Shopping cart, form data |
|
|
114
|
-
| **Memory** | Cross-session | User preferences, learned facts |
|
|
308
|
+
### Working Memory
|
|
115
309
|
|
|
116
|
-
|
|
310
|
+
Persist data across conversation turns:
|
|
117
311
|
|
|
118
312
|
```typescript
|
|
119
|
-
|
|
313
|
+
const MyAgent = createAriaCFChatAgent<Env>({
|
|
314
|
+
flows: myFlows,
|
|
315
|
+
model: env.AI("@cf/meta/llama-3.1-8b-instruct"),
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
class ShoppingAssistant extends MyAgent {
|
|
120
319
|
async onChatMessage(onFinish) {
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Retrieve working memory
|
|
125
|
-
const memory = this.getWorkingMemory();
|
|
126
|
-
console.log(memory.cart); // { items: ["item1", "item2"] }
|
|
320
|
+
// Working memory is automatically managed by ARIA
|
|
321
|
+
// Access via session.workingMemory in tools or flows
|
|
127
322
|
}
|
|
128
323
|
}
|
|
129
324
|
```
|
|
130
325
|
|
|
131
|
-
###
|
|
326
|
+
### Tools
|
|
327
|
+
|
|
328
|
+
Register custom tools for your agent:
|
|
132
329
|
|
|
133
330
|
```typescript
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
331
|
+
import { tool } from "ai";
|
|
332
|
+
import { z } from "zod";
|
|
333
|
+
|
|
334
|
+
const MyAgent = createAriaCFChatAgent<Env>({
|
|
335
|
+
flows: myFlows,
|
|
336
|
+
model: env.AI("@cf/meta/llama-3.1-8b-instruct"),
|
|
337
|
+
tools: {
|
|
338
|
+
searchProducts: tool({
|
|
339
|
+
description: "Search for products",
|
|
340
|
+
parameters: z.object({
|
|
341
|
+
query: z.string(),
|
|
342
|
+
category: z.string().optional(),
|
|
343
|
+
}),
|
|
344
|
+
execute: async ({ query, category }) => {
|
|
345
|
+
// Your implementation
|
|
346
|
+
return [{ id: "1", name: "Product", price: 9.99 }];
|
|
347
|
+
},
|
|
348
|
+
}),
|
|
349
|
+
},
|
|
350
|
+
});
|
|
151
351
|
```
|
|
152
352
|
|
|
153
|
-
###
|
|
353
|
+
### Multiple Model Providers
|
|
354
|
+
|
|
355
|
+
Use any AI SDK model:
|
|
154
356
|
|
|
155
357
|
```typescript
|
|
156
|
-
import {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
private orderFlow = createFlow({
|
|
160
|
-
id: "order-flow",
|
|
161
|
-
nodes: [
|
|
162
|
-
{ id: "collect-items", ... },
|
|
163
|
-
{ id: "confirm-order", ... },
|
|
164
|
-
{ id: "payment", ... },
|
|
165
|
-
],
|
|
166
|
-
});
|
|
358
|
+
import { openai } from "@ai-sdk/openai";
|
|
359
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
360
|
+
import { google } from "@ai-sdk/google";
|
|
167
361
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
362
|
+
// OpenAI
|
|
363
|
+
const agent1 = createAriaCFChatAgent({
|
|
364
|
+
model: openai("gpt-4o-mini"),
|
|
365
|
+
flows: myFlows,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// Anthropic
|
|
369
|
+
const agent2 = createAriaCFChatAgent({
|
|
370
|
+
model: anthropic("claude-sonnet-4-20250514"),
|
|
371
|
+
flows: myFlows,
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Google
|
|
375
|
+
const agent3 = createAriaCFChatAgent({
|
|
376
|
+
model: google("gemini-2.0-flash"),
|
|
377
|
+
flows: myFlows,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// Workers AI (Cloudflare)
|
|
381
|
+
const agent4 = createAriaCFChatAgent({
|
|
382
|
+
model: env.AI("@cf/meta/llama-3.1-8b-instruct"),
|
|
383
|
+
flows: myFlows,
|
|
384
|
+
});
|
|
173
385
|
```
|
|
174
386
|
|
|
175
387
|
## API Reference
|
|
176
388
|
|
|
177
|
-
###
|
|
389
|
+
### createAriaCFChatAgent
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
function createAriaCFChatAgent<Env>(
|
|
393
|
+
config: AriaCFChatAgentConfig
|
|
394
|
+
): new (ctx: AgentContext, env: Env) => AriaCFChatAgent<Env>;
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### AriaCFChatAgentConfig
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
interface AriaCFChatAgentConfig {
|
|
401
|
+
// Required
|
|
402
|
+
flows: Map<string, FlowDefinition>;
|
|
403
|
+
model: LanguageModel; // Any AI SDK model
|
|
404
|
+
|
|
405
|
+
// Optional
|
|
406
|
+
instructions?: string; // Agent instructions
|
|
407
|
+
guidelines?: string[]; // System guidelines
|
|
408
|
+
tools?: ToolRegistry; // Custom tools
|
|
409
|
+
historyLimit?: number; // Max history messages (default: 50)
|
|
410
|
+
enablePersistence?: boolean; // Enable session persistence (default: true)
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### AriaCFChatAgent
|
|
415
|
+
|
|
416
|
+
Base class extended by the factory:
|
|
178
417
|
|
|
179
418
|
```typescript
|
|
180
|
-
class
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
// ARIA Integration
|
|
194
|
-
runAriaAgent(agent, input, options?): Promise<{ text: string; session: AgentSession }>
|
|
195
|
-
streamAriaAgent(agent, input, options?): AsyncIterable<string>
|
|
196
|
-
|
|
197
|
-
// Flow Orchestration
|
|
198
|
-
registerFlow(flow: FlowDefinition): void
|
|
199
|
-
transitionFlow(flowId: string, toNodeId: string): void
|
|
419
|
+
abstract class AriaCFChatAgent<Env = any> extends AIChatAgent<Env, AriaCFState> {
|
|
420
|
+
// Configuration
|
|
421
|
+
protected readonly config: AriaCFChatAgentConfigResolved;
|
|
422
|
+
protected readonly ariaAgent: AriaAgent;
|
|
423
|
+
protected readonly voltRuntime: VoltRuntime;
|
|
424
|
+
|
|
425
|
+
// Override these in your subclass
|
|
426
|
+
protected abstract getConfig(): AriaCFChatAgentConfig;
|
|
427
|
+
|
|
428
|
+
// Optional overrides
|
|
429
|
+
protected getModel(): LanguageModel;
|
|
430
|
+
protected getModelId(): string;
|
|
431
|
+
protected getTools(): ToolRegistry;
|
|
200
432
|
}
|
|
201
433
|
```
|
|
202
434
|
|
|
@@ -226,58 +458,6 @@ function Chat() {
|
|
|
226
458
|
}
|
|
227
459
|
```
|
|
228
460
|
|
|
229
|
-
### Using React (State Synchronization)
|
|
230
|
-
|
|
231
|
-
The `useAgent` hook provides real-time state synchronization between your React app and the Agent:
|
|
232
|
-
|
|
233
|
-
```tsx
|
|
234
|
-
import { useState } from "react";
|
|
235
|
-
import { useAgent } from "agents/react";
|
|
236
|
-
|
|
237
|
-
function ShoppingCart() {
|
|
238
|
-
const [state, setState] = useState({
|
|
239
|
-
cart: [],
|
|
240
|
-
workingMemory: {}
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
// Connect to the agent and sync state
|
|
244
|
-
const agent = useAgent({
|
|
245
|
-
agent: "shopping-assistant",
|
|
246
|
-
name: "user-session-123",
|
|
247
|
-
onStateUpdate: (newState) => setState(newState),
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
const addToCart = (item: string) => {
|
|
251
|
-
// Update state on both client and server
|
|
252
|
-
agent.setState({
|
|
253
|
-
...state,
|
|
254
|
-
workingMemory: {
|
|
255
|
-
...state.workingMemory,
|
|
256
|
-
cart: [...(state.workingMemory.cart || []), item],
|
|
257
|
-
},
|
|
258
|
-
});
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
return (
|
|
262
|
-
<div>
|
|
263
|
-
<h2>Cart ({state.workingMemory.cart?.length || 0} items)</h2>
|
|
264
|
-
<ul>
|
|
265
|
-
{state.workingMemory.cart?.map((item, i) => (
|
|
266
|
-
<li key={i}>{item}</li>
|
|
267
|
-
))}
|
|
268
|
-
</ul>
|
|
269
|
-
<button onClick={() => addToCart("New Item")}>Add Item</button>
|
|
270
|
-
</div>
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
State synchronization features:
|
|
276
|
-
- Automatically syncs Agent state to all connected clients
|
|
277
|
-
- Handles disconnections and reconnections gracefully
|
|
278
|
-
- Provides immediate local updates
|
|
279
|
-
- Supports multiple simultaneous client connections
|
|
280
|
-
|
|
281
461
|
### Using WebSocket
|
|
282
462
|
|
|
283
463
|
```typescript
|
|
@@ -313,84 +493,9 @@ const response = await fetch("https://your-worker.workers.dev/agents/my-assistan
|
|
|
313
493
|
});
|
|
314
494
|
```
|
|
315
495
|
|
|
316
|
-
## Environment Configuration
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
// src/types.ts
|
|
320
|
-
interface Env {
|
|
321
|
-
MyAssistant: DurableObjectNamespace;
|
|
322
|
-
OPENAI_API_KEY: string;
|
|
323
|
-
}
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
```toml
|
|
327
|
-
# wrangler.toml (secrets)
|
|
328
|
-
[vars]
|
|
329
|
-
# Set via: npx wrangler secret put OPENAI_API_KEY
|
|
330
|
-
```
|
|
331
|
-
|
|
332
496
|
## Complete Example
|
|
333
497
|
|
|
334
|
-
|
|
335
|
-
// src/shopping-assistant.ts
|
|
336
|
-
import { AriaAgent } from "@projectaria/cf-agents";
|
|
337
|
-
import { createAgent } from "@projectaria/aria-agents";
|
|
338
|
-
import { openai } from "@ai-sdk/openai";
|
|
339
|
-
import { tool } from "ai";
|
|
340
|
-
import { z } from "zod";
|
|
341
|
-
|
|
342
|
-
export class ShoppingAssistant extends AriaAgent {
|
|
343
|
-
private agent = createAgent({
|
|
344
|
-
id: "shopping-assistant",
|
|
345
|
-
name: "Shopping Assistant",
|
|
346
|
-
instructions: `You are a helpful shopping assistant.
|
|
347
|
-
You remember user preferences and can help them find products.
|
|
348
|
-
Use the cart tools to manage their shopping cart.`,
|
|
349
|
-
model: openai("gpt-4o"),
|
|
350
|
-
tools: {
|
|
351
|
-
addToCart: tool({
|
|
352
|
-
description: "Add an item to the cart",
|
|
353
|
-
parameters: z.object({
|
|
354
|
-
item: z.string(),
|
|
355
|
-
quantity: z.number().default(1),
|
|
356
|
-
}),
|
|
357
|
-
execute: async ({ item, quantity }) => {
|
|
358
|
-
const cart = this.getWorkingMemory().cart || [];
|
|
359
|
-
cart.push({ item, quantity });
|
|
360
|
-
this.setWorkingMemory("cart", cart);
|
|
361
|
-
return { success: true, cart };
|
|
362
|
-
},
|
|
363
|
-
}),
|
|
364
|
-
viewCart: tool({
|
|
365
|
-
description: "View the current cart",
|
|
366
|
-
parameters: z.object({}),
|
|
367
|
-
execute: async () => {
|
|
368
|
-
return this.getWorkingMemory().cart || [];
|
|
369
|
-
},
|
|
370
|
-
}),
|
|
371
|
-
},
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
async onChatMessage(onFinish: () => void) {
|
|
375
|
-
const session = this.getSession();
|
|
376
|
-
const lastMessage = session.messages[session.messages.length - 1];
|
|
377
|
-
|
|
378
|
-
if (!lastMessage) return;
|
|
379
|
-
|
|
380
|
-
// Check for returning user preferences
|
|
381
|
-
const prefs = this.searchMemories({
|
|
382
|
-
types: ["preference"],
|
|
383
|
-
limit: 5,
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// Run agent with context
|
|
387
|
-
const result = await this.runAriaAgent(this.agent, lastMessage.content);
|
|
388
|
-
|
|
389
|
-
onFinish();
|
|
390
|
-
return new Response(result.text);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
```
|
|
498
|
+
See [`examples/ShoppingAgent.ts`](examples/ShoppingAgent.ts) for a full shopping assistant example with flows, tools, and persistence.
|
|
394
499
|
|
|
395
500
|
## License
|
|
396
501
|
|