@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.
Files changed (38) hide show
  1. package/README.md +358 -253
  2. package/dist/AriaCFChatAgent.d.ts +37 -0
  3. package/dist/AriaCFChatAgent.d.ts.map +1 -0
  4. package/dist/AriaCFChatAgent.js +203 -0
  5. package/dist/AriaCFChatAgent.js.map +1 -0
  6. package/dist/CloudflareSessionStore.d.ts +37 -0
  7. package/dist/CloudflareSessionStore.d.ts.map +1 -0
  8. package/dist/CloudflareSessionStore.js +101 -0
  9. package/dist/CloudflareSessionStore.js.map +1 -0
  10. package/dist/aria-to-ui-stream.d.ts +21 -0
  11. package/dist/aria-to-ui-stream.d.ts.map +1 -0
  12. package/dist/aria-to-ui-stream.js +118 -0
  13. package/dist/aria-to-ui-stream.js.map +1 -0
  14. package/dist/index.d.ts +25 -22
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +21 -23
  17. package/dist/index.js.map +1 -1
  18. package/dist/message-format.d.ts +39 -0
  19. package/dist/message-format.d.ts.map +1 -0
  20. package/dist/message-format.js +124 -0
  21. package/dist/message-format.js.map +1 -0
  22. package/dist/types.d.ts +59 -146
  23. package/dist/types.d.ts.map +1 -1
  24. package/dist/types.js +8 -7
  25. package/dist/types.js.map +1 -1
  26. package/package.json +3 -2
  27. package/dist/AriaAgent.d.ts +0 -186
  28. package/dist/AriaAgent.d.ts.map +0 -1
  29. package/dist/AriaAgent.js +0 -756
  30. package/dist/AriaAgent.js.map +0 -1
  31. package/dist/aria-agent-integration.d.ts +0 -52
  32. package/dist/aria-agent-integration.d.ts.map +0 -1
  33. package/dist/aria-agent-integration.js +0 -186
  34. package/dist/aria-agent-integration.js.map +0 -1
  35. package/dist/message-converter.d.ts +0 -48
  36. package/dist/message-converter.d.ts.map +0 -1
  37. package/dist/message-converter.js +0 -138
  38. 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
- ## Quick Start
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
- ### 1. Create Your Agent
133
+ ## Message Handling Sequence
14
134
 
15
135
  ```typescript
16
- // src/agent.ts
17
- import { AriaAgent } from "@projectaria/cf-agents";
18
- import { createAgent } from "@projectaria/aria-agents";
19
- import { openai } from "@ai-sdk/openai";
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
- export class MyAssistant extends AriaAgent {
22
- // Create an ARIA agent with your configuration
23
- private ariaAgent = createAgent({
24
- id: "assistant",
25
- name: "My Assistant",
26
- instructions: "You are a helpful assistant that remembers user preferences.",
27
- model: openai("gpt-4o"),
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
- // Handle incoming chat messages
31
- async onChatMessage(onFinish: () => void) {
32
- // Get the current session with message history
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
- if (!lastMessage) {
37
- return;
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
- // Run the ARIA agent with automatic memory persistence
41
- const result = await this.runAriaAgent(this.ariaAgent, lastMessage.content);
171
+ // 3b. Call LLM with prompt + tools
172
+ return streamText(model, messages, tools);
173
+ }
42
174
 
43
- // Call onFinish to signal completion
44
- onFinish();
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
- // Return response (for HTTP) or it's already sent via WebSocket
47
- return new Response(result.text);
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 { MyAssistant } from "./agent";
240
+ import { MyAgent } from "./agent";
58
241
 
59
- export { MyAssistant };
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
- ```jsonc
75
- // wrangler.jsonc
76
- {
77
- "name": "my-assistant",
78
- "main": "src/index.ts",
79
- "compatibility_date": "2025-02-11",
80
- "compatibility_flags": ["nodejs_compat"],
81
- "durable_objects": {
82
- "bindings": [
83
- {
84
- "name": "MyAssistant",
85
- "class_name": "MyAssistant"
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
- ### Memory Primitives
278
+ ### Flow Orchestration
279
+
280
+ Define structured multi-turn conversations:
107
281
 
108
- AriaAgent provides three levels of memory:
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
- | Memory Type | Scope | Use Case |
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
- ### Working Memory (Session-scoped)
310
+ Persist data across conversation turns:
117
311
 
118
312
  ```typescript
119
- class MyAgent extends AriaAgent {
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
- // Store data for current session
122
- this.setWorkingMemory("cart", { items: ["item1", "item2"] });
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
- ### Cross-Session Memory
326
+ ### Tools
327
+
328
+ Register custom tools for your agent:
132
329
 
133
330
  ```typescript
134
- class MyAgent extends AriaAgent {
135
- async onChatMessage(onFinish) {
136
- // Store a preference that persists across sessions
137
- this.storeMemory({
138
- key: "user:theme",
139
- value: { theme: "dark", fontSize: "large" },
140
- type: "preference",
141
- });
142
-
143
- // Search memories
144
- const results = this.searchMemories({
145
- query: "theme",
146
- types: ["preference"],
147
- limit: 5,
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
- ### Flow Orchestration
353
+ ### Multiple Model Providers
354
+
355
+ Use any AI SDK model:
154
356
 
155
357
  ```typescript
156
- import { createFlow } from "@projectaria/aria-agents";
157
-
158
- class MyAgent extends AriaAgent {
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
- constructor(ctx, env) {
169
- super(ctx, env);
170
- this.registerFlow(this.orderFlow);
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
- ### AriaAgent Class
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 AriaAgent extends AIChatAgent<AriaEnv, AriaSessionState> {
181
- // Session Management
182
- getSession(): AriaSession
183
-
184
- // Working Memory
185
- getWorkingMemory(): WorkingMemory
186
- setWorkingMemory(key: string, value: unknown): void
187
- clearWorkingMemory(): void
188
-
189
- // Cross-Session Memory
190
- storeMemory(memory: Omit<AriaMemory, "id" | ...>): string
191
- searchMemories(query: MemorySearchQuery): MemorySearchResult[]
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
- ```typescript
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