@projectaria/cf-agents 0.1.1 → 0.1.2

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 +200 -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/dist/AriaAgent.js DELETED
@@ -1,756 +0,0 @@
1
- /**
2
- * ARIA Agent - Cloudflare Agents integration with proper memory primitives
3
- *
4
- * Memory Architecture:
5
- * 1. Session: Current conversation thread with chronological messages
6
- * 2. State: Temporary data within the current conversation (working memory)
7
- * 3. Memory: Searchable, cross-session information (knowledge base)
8
- *
9
- * AI SDK 6.0 Message Types (matching agents@0.3.3):
10
- * - UIMessage: Format with UI metadata (id, role, parts)
11
- * - ModelMessage: Format expected by LLM models
12
- * - convertToModelMessages: Converts UIMessage[] to ModelMessage[]
13
- */
14
- import { AIChatAgent } from "agents/ai-chat-agent";
15
- import { nanoid } from "nanoid";
16
- import { batchAriaToChat, batchChatToAria, extractConversationSummary, } from "./message-converter";
17
- /**
18
- * Default configuration
19
- */
20
- const DEFAULT_CONFIG = {
21
- historyLimit: 50,
22
- enableMemory: true,
23
- memoryRetentionMs: 30 * 24 * 60 * 60 * 1000, // 30 days
24
- trackTransitions: true,
25
- generateSessionId: () => crypto.randomUUID(),
26
- };
27
- /**
28
- * ARIA Agent extending AIChatAgent
29
- *
30
- * Provides:
31
- * - Session management with conversation history
32
- * - State management (working memory) for session-local data
33
- * - Memory layer for cross-session knowledge
34
- * - Flow orchestration integration
35
- * - Multi-turn conversation support
36
- */
37
- export class AriaAgent extends AIChatAgent {
38
- config;
39
- flowDefinitions;
40
- constructor(ctx, env) {
41
- super(ctx, env);
42
- this.config = { ...DEFAULT_CONFIG };
43
- this.flowDefinitions = new Map();
44
- // Create ARIA-specific tables
45
- this.initializeTables();
46
- }
47
- /**
48
- * Initialize ARIA-specific database tables
49
- */
50
- initializeTables() {
51
- // Memory table for cross-session knowledge
52
- this.sql `
53
- create table if not exists aria_memory (
54
- id text primary key,
55
- session_id text,
56
- key text not null,
57
- value text not null,
58
- type text not null check(type in ('preference', 'fact', 'context', 'entity', 'custom')),
59
- created_at integer default (unixepoch()),
60
- last_accessed_at integer default (unixepoch()),
61
- access_count integer default 1,
62
- embedding text,
63
- metadata text
64
- )
65
- `;
66
- this.sql `create index if not exists idx_memory_session
67
- on aria_memory(session_id)`;
68
- this.sql `create index if not exists idx_memory_key
69
- on aria_memory(key)`;
70
- this.sql `create index if not exists idx_memory_type
71
- on aria_memory(type)`;
72
- // Flow transitions table for tracking execution history
73
- this.sql `
74
- create table if not exists aria_flow_transitions (
75
- id text primary key,
76
- flow_id text not null,
77
- from_node_id text,
78
- to_node_id text not null,
79
- transitioned_at integer default (unixepoch()),
80
- metadata text
81
- )
82
- `;
83
- this.sql `create index if not exists idx_flow_transitions_flow
84
- on aria_flow_transitions(flow_id, transitioned_at)`;
85
- // Session history table (in addition to AIChatAgent's messages)
86
- this.sql `
87
- create table if not exists aria_session_events (
88
- id text primary key,
89
- event_type text not null,
90
- event_data text,
91
- occurred_at integer default (unixepoch())
92
- )
93
- `;
94
- }
95
- /**
96
- * Initial state when no session exists
97
- */
98
- initialState = {
99
- workingMemory: {},
100
- activeFlowId: undefined,
101
- activeNodeId: undefined,
102
- historyLimit: DEFAULT_CONFIG.historyLimit,
103
- };
104
- // ============================================================
105
- // SESSION MANAGEMENT
106
- // ============================================================
107
- /**
108
- * Get the current session
109
- * Session = Current conversation thread with chronological messages
110
- */
111
- getSession() {
112
- const state = this.state;
113
- return {
114
- id: this.name,
115
- messages: batchChatToAria(this.messages),
116
- activeFlow: state.activeFlowId && state.activeNodeId
117
- ? {
118
- flowId: state.activeFlowId,
119
- currentNodeId: state.activeNodeId,
120
- enteredAt: Date.now(),
121
- }
122
- : undefined,
123
- historyLimit: state.historyLimit,
124
- createdAt: this.getCreatedAt(),
125
- updatedAt: Date.now(),
126
- };
127
- }
128
- /**
129
- * Get session creation time from storage
130
- */
131
- getCreatedAt() {
132
- const row = this.sql `
133
- select min(created_at) as created_at from aria_session_events
134
- `;
135
- return row?.[0]?.created_at || Date.now();
136
- }
137
- /**
138
- * Record a session event for tracking
139
- */
140
- recordSessionEvent(eventType, eventData) {
141
- this.sql `
142
- insert into aria_session_events (id, event_type, event_data)
143
- values (${nanoid()}, ${eventType}, ${JSON.stringify(eventData)})
144
- `;
145
- }
146
- // ============================================================
147
- // STATE MANAGEMENT (Session-Local Data)
148
- // ============================================================
149
- /**
150
- * Get working memory (state within current conversation)
151
- * Examples: shopping cart items, user preferences mentioned in this session
152
- */
153
- getWorkingMemory() {
154
- return this.state.workingMemory || {};
155
- }
156
- /**
157
- * Set a value in working memory
158
- */
159
- setWorkingMemory(key, value) {
160
- const current = this.getWorkingMemory();
161
- this.setState({
162
- ...this.state,
163
- workingMemory: {
164
- ...current,
165
- [key]: value,
166
- },
167
- });
168
- }
169
- /**
170
- * Clear all working memory
171
- */
172
- clearWorkingMemory() {
173
- this.setState({
174
- ...this.state,
175
- workingMemory: {},
176
- });
177
- }
178
- /**
179
- * Handle state updates (called by Cloudflare Agents framework)
180
- * This is triggered whenever setState is called, either from the server or from a connected client.
181
- *
182
- * Use cases:
183
- * - React state synchronization via useAgent hook
184
- * - Logging state changes
185
- * - Triggering side effects on state changes
186
- *
187
- * @param state - The updated state
188
- * @param source - "server" if update came from the agent, or a Connection object if from a client
189
- */
190
- onStateUpdate(state, source) {
191
- // Record state change for debugging/auditing
192
- this.recordSessionEvent("state_update", {
193
- source: source === "server" ? "server" : "client",
194
- workingMemoryKeys: Object.keys(state.workingMemory || {}),
195
- activeFlowId: state.activeFlowId,
196
- activeNodeId: state.activeNodeId,
197
- });
198
- }
199
- // ============================================================
200
- // MEMORY LAYER (Cross-Session Knowledge)
201
- // ============================================================
202
- /**
203
- * Store a memory for cross-session retrieval
204
- * Memory = Searchable, cross-session information (knowledge base)
205
- */
206
- storeMemory(memory) {
207
- const id = nanoid();
208
- const now = Date.now();
209
- this.sql `
210
- insert into aria_memory (
211
- id, session_id, key, value, type,
212
- created_at, last_accessed_at, access_count, metadata
213
- )
214
- values (
215
- ${id},
216
- ${memory.sessionId ?? null},
217
- ${memory.key},
218
- ${JSON.stringify(memory.value)},
219
- ${memory.type},
220
- ${Math.floor(now / 1000)},
221
- ${Math.floor(now / 1000)},
222
- 1,
223
- ${memory.metadata ? JSON.stringify(memory.metadata) : null}
224
- )
225
- `;
226
- return id;
227
- }
228
- /**
229
- * Search memory by query
230
- * Returns relevant memories across all sessions
231
- */
232
- searchMemories(query) {
233
- const limit = query.limit || 10;
234
- let rows = [];
235
- // Use different queries based on search criteria
236
- // Note: SQLite tagged template literals don't support dynamic queries
237
- if (query.query && query.types && query.types.length > 0) {
238
- // Search with text and type filter
239
- const typeList = query.types.join(",");
240
- const searchPattern = `%${query.query}%`;
241
- rows = this.sql `
242
- select * from aria_memory
243
- where key like ${searchPattern}
244
- and type in (${typeList})
245
- order by access_count desc, last_accessed_at desc
246
- limit ${limit}
247
- ` || [];
248
- }
249
- else if (query.query) {
250
- // Search with text only
251
- const searchPattern = `%${query.query}%`;
252
- rows = this.sql `
253
- select * from aria_memory
254
- where key like ${searchPattern}
255
- order by access_count desc, last_accessed_at desc
256
- limit ${limit}
257
- ` || [];
258
- }
259
- else if (query.types && query.types.length > 0) {
260
- // Search with type filter only
261
- const typeList = query.types.join(",");
262
- rows = this.sql `
263
- select * from aria_memory
264
- where type in (${typeList})
265
- order by access_count desc, last_accessed_at desc
266
- limit ${limit}
267
- ` || [];
268
- }
269
- else {
270
- // Get all memories
271
- rows = this.sql `
272
- select * from aria_memory
273
- order by access_count desc, last_accessed_at desc
274
- limit ${limit}
275
- ` || [];
276
- }
277
- return rows.map((row) => ({
278
- memory: {
279
- id: row.id,
280
- sessionId: row.session_id,
281
- key: row.key,
282
- value: JSON.parse(row.value),
283
- type: row.type,
284
- createdAt: row.created_at * 1000,
285
- lastAccessedAt: row.last_accessed_at * 1000,
286
- accessCount: row.access_count,
287
- metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
288
- },
289
- score: Math.min(1, row.access_count / 10), // Simple relevance score
290
- relevance: row.access_count > 5 ? "high" : row.access_count > 2 ? "medium" : "low",
291
- }));
292
- }
293
- /**
294
- * Get a specific memory by key
295
- */
296
- getMemory(key) {
297
- const rows = this.sql `
298
- select * from aria_memory where key = ${key} limit 1
299
- `;
300
- if (!rows || rows.length === 0) {
301
- return null;
302
- }
303
- return {
304
- id: key,
305
- sessionId: null,
306
- key,
307
- value: JSON.parse(rows[0].value),
308
- type: rows[0].type,
309
- createdAt: Date.now(),
310
- lastAccessedAt: Date.now(),
311
- accessCount: 1,
312
- };
313
- }
314
- /**
315
- * Update memory access (increments access count and updates timestamp)
316
- */
317
- updateMemoryAccess(key) {
318
- this.sql `
319
- update aria_memory
320
- set access_count = access_count + 1, last_accessed_at = ${Math.floor(Date.now() / 1000)}
321
- where key = ${key}
322
- `;
323
- }
324
- /**
325
- * Clean up old memories based on retention policy
326
- */
327
- cleanupOldMemories() {
328
- const cutoff = Math.floor((Date.now() - this.config.memoryRetentionMs) / 1000);
329
- this.sql `delete from aria_memory where created_at < ${cutoff}`;
330
- }
331
- // ============================================================
332
- // FLOW ORCHESTRATION
333
- // ============================================================
334
- /**
335
- * Register a flow definition
336
- */
337
- registerFlow(flow) {
338
- this.flowDefinitions.set(flow.id, flow);
339
- }
340
- /**
341
- * Record a flow transition
342
- */
343
- recordFlowTransition(flowId, fromNodeId, toNodeId, metadata) {
344
- if (!this.config.trackTransitions) {
345
- return;
346
- }
347
- this.sql `
348
- insert into aria_flow_transitions (id, flow_id, from_node_id, to_node_id, metadata)
349
- values (${nanoid()}, ${flowId}, ${fromNodeId}, ${toNodeId}, ${metadata ? JSON.stringify(metadata) : null})
350
- `;
351
- this.setState({
352
- ...this.state,
353
- activeFlowId: flowId,
354
- activeNodeId: toNodeId,
355
- });
356
- }
357
- /**
358
- * Get flow transition history
359
- */
360
- getFlowHistory(flowId, limit = 100) {
361
- let query = "select * from aria_flow_transitions";
362
- if (flowId) {
363
- query += ` where flow_id = ${flowId}`;
364
- }
365
- query += ` order by transitioned_at desc limit ${limit}`;
366
- const rows = this.sql `
367
- ${query}
368
- `;
369
- return (rows || []).map((row) => ({
370
- id: row.id,
371
- flowId: row.flow_id,
372
- fromNodeId: row.from_node_id,
373
- toNodeId: row.to_node_id,
374
- transitionedAt: row.transitioned_at * 1000,
375
- metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
376
- }));
377
- }
378
- // ============================================================
379
- // MESSAGE HANDLING
380
- // ============================================================
381
- /**
382
- * Handle incoming chat messages
383
- * This is where ARIA's flow orchestration would be integrated
384
- */
385
- async onChatMessage(onFinish, options) {
386
- // Record session event
387
- this.recordSessionEvent("message_received", {
388
- messageCount: this.messages.length,
389
- workingMemoryKeys: Object.keys(this.getWorkingMemory()),
390
- });
391
- // Get current session
392
- const session = this.getSession();
393
- // Get conversation context from memory
394
- const relevantMemories = this.searchMemories({
395
- query: session.messages[session.messages.length - 1]?.content || "",
396
- limit: 5,
397
- types: ["context", "entity", "preference"],
398
- });
399
- // Build system prompt with context
400
- const systemPrompt = this.buildSystemPrompt(session, relevantMemories);
401
- // Here you would integrate ARIA's flow orchestration
402
- // For now, return a basic response
403
- // TODO: Integrate with @projectaria/aria VoltRuntime
404
- // Example: Save learned facts to memory
405
- const summary = extractConversationSummary(session.messages);
406
- for (const topic of summary.topics.slice(0, 3)) {
407
- this.storeMemory({
408
- sessionId: session.id,
409
- key: topic,
410
- value: { mentioned: true, count: 1 },
411
- type: "context",
412
- });
413
- }
414
- // Call parent implementation
415
- return super.onChatMessage(onFinish, options);
416
- }
417
- /**
418
- * Build system prompt with conversation context
419
- */
420
- buildSystemPrompt(session, memories) {
421
- const parts = [
422
- "You are a helpful AI assistant.",
423
- "You have access to conversation history and can recall information from previous conversations.",
424
- ];
425
- // Add active flow context
426
- if (session.activeFlow) {
427
- parts.push(`\nCurrent flow: ${session.activeFlow.flowId} (node: ${session.activeFlow.currentNodeId})`);
428
- }
429
- // Add working memory context
430
- const workingMemory = this.getWorkingMemory();
431
- if (Object.keys(workingMemory).length > 0) {
432
- parts.push("\nCurrent session data:");
433
- for (const [key, value] of Object.entries(workingMemory)) {
434
- parts.push(` - ${key}: ${JSON.stringify(value)}`);
435
- }
436
- }
437
- // Add memory context
438
- if (memories.length > 0) {
439
- parts.push("\nRelevant information from previous conversations:");
440
- for (const memory of memories) {
441
- parts.push(` - ${memory.memory.key}: ${JSON.stringify(memory.memory.value)}`);
442
- this.updateMemoryAccess(memory.memory.key);
443
- }
444
- }
445
- return parts.join("\n");
446
- }
447
- // ============================================================
448
- // ARIA AGENT INTEGRATION
449
- // ============================================================
450
- /**
451
- * Run an ARIA agent with persistence
452
- * This method allows you to use ARIA's createAgent() with persistent memory
453
- *
454
- * @param agent - The ARIA agent created via createAgent()
455
- * @param input - The user input
456
- * @returns The agent response with persisted session state
457
- */
458
- async runAriaAgent(agent, input) {
459
- // Get current session from persistent storage
460
- const currentSession = this.getSession();
461
- // Convert to ARIA AgentSession format
462
- const ariaSession = {
463
- sessionId: currentSession.id,
464
- conversationId: currentSession.id,
465
- history: batchAriaToChat(currentSession.messages),
466
- workingMemory: this.getWorkingMemory(),
467
- context: new Map(),
468
- createdAt: new Date(currentSession.createdAt).toISOString(),
469
- updatedAt: new Date(currentSession.updatedAt).toISOString(),
470
- };
471
- // Search for relevant memories
472
- const relevantMemories = this.searchMemories({
473
- query: input,
474
- limit: 5,
475
- types: ["preference", "fact", "context", "entity"],
476
- });
477
- // Build enhanced prompt with context
478
- const prompt = this.buildAriaAgentPrompt(currentSession, relevantMemories, this.getWorkingMemory());
479
- // Run the ARIA agent
480
- // Note: systemPrompt should be passed via the agent config, not metadata
481
- const result = await agent.generateText({
482
- input,
483
- session: ariaSession,
484
- });
485
- // Persist working memory changes
486
- if (result.session) {
487
- const stateBefore = JSON.stringify(ariaSession.workingMemory);
488
- const stateAfter = JSON.stringify(result.session.workingMemory);
489
- if (stateBefore !== stateAfter) {
490
- // Merge the updated working memory into our persistent state
491
- const currentWorkingMemory = this.getWorkingMemory();
492
- const updatedWorkingMemory = {
493
- ...currentWorkingMemory,
494
- ...result.session.workingMemory,
495
- };
496
- this.setState({
497
- ...this.state,
498
- workingMemory: updatedWorkingMemory,
499
- });
500
- }
501
- // Extract and store memories from the conversation
502
- await this.extractAndStoreMemories(result.session);
503
- }
504
- return {
505
- text: result.text,
506
- session: result.session,
507
- };
508
- }
509
- /**
510
- * Stream an ARIA agent response with persistence
511
- *
512
- * @param agent - The ARIA agent created via createAgent()
513
- * @param input - The user input
514
- * @returns Stream result with session
515
- */
516
- async streamAriaAgent(agent, input) {
517
- // Get current session from persistent storage
518
- const currentSession = this.getSession();
519
- // Convert to ARIA AgentSession format
520
- const ariaSession = {
521
- sessionId: currentSession.id,
522
- conversationId: currentSession.id,
523
- history: batchAriaToChat(currentSession.messages),
524
- workingMemory: this.getWorkingMemory(),
525
- context: new Map(),
526
- createdAt: new Date(currentSession.createdAt).toISOString(),
527
- updatedAt: new Date(currentSession.updatedAt).toISOString(),
528
- };
529
- // Search for relevant memories
530
- const relevantMemories = this.searchMemories({
531
- query: input,
532
- limit: 5,
533
- types: ["preference", "fact", "context", "entity"],
534
- });
535
- // Build enhanced prompt with context
536
- const prompt = this.buildAriaAgentPrompt(currentSession, relevantMemories, this.getWorkingMemory());
537
- // Stream the ARIA agent response
538
- // Note: systemPrompt should be passed via the agent config, not metadata
539
- const result = await agent.streamText({
540
- input,
541
- session: ariaSession,
542
- });
543
- // Note: For streaming, we need to handle persistence after the stream completes
544
- // This is typically done in the onFinish callback
545
- if (result.usage) {
546
- result.usage.then(async () => {
547
- await this.extractAndStoreMemories(ariaSession);
548
- });
549
- }
550
- return {
551
- fullStream: result.fullStream,
552
- textStream: result.textStream,
553
- usage: result.usage,
554
- };
555
- }
556
- /**
557
- * Build ARIA agent prompt with context from session and memories
558
- */
559
- buildAriaAgentPrompt(session, memories, workingMemory) {
560
- const parts = ["You are a helpful AI assistant with memory."];
561
- // Add working memory/state context
562
- if (Object.keys(workingMemory).length > 0) {
563
- parts.push("\n📋 Current Session Data:");
564
- for (const [key, value] of Object.entries(workingMemory)) {
565
- parts.push(` ${key}: ${JSON.stringify(value)}`);
566
- }
567
- }
568
- // Add memories from past conversations
569
- if (memories.length > 0) {
570
- parts.push("\n💭 Relevant Information from Past Conversations:");
571
- for (const memoryResult of memories) {
572
- const { memory } = memoryResult;
573
- parts.push(` [${memory.type}] ${memory.key}: ${JSON.stringify(memory.value)}`);
574
- // Update access count for relevance tracking
575
- this.updateMemoryAccess(memory.key);
576
- }
577
- }
578
- return parts.join("\n");
579
- }
580
- /**
581
- * Extract and store memories from ARIA agent conversation
582
- */
583
- async extractAndStoreMemories(ariaSession) {
584
- const conversation = ariaSession.history;
585
- // Analyze each message for memory extraction
586
- for (const message of conversation) {
587
- if (message.role === "user") {
588
- // Extract text content
589
- const text = message.parts
590
- .filter((p) => p.type === "text")
591
- .map((p) => p.text)
592
- .join(" ");
593
- const content = text.toLowerCase();
594
- // Detect preferences
595
- if (content.includes("prefer") ||
596
- content.includes("like") ||
597
- content.includes("want")) {
598
- const prefKey = this.extractPreferenceKey(text);
599
- if (prefKey) {
600
- this.storeMemory({
601
- sessionId: ariaSession.sessionId,
602
- key: prefKey,
603
- value: { stated: text, timestamp: Date.now() },
604
- type: "preference",
605
- });
606
- }
607
- }
608
- // Detect facts
609
- if (content.includes("my name is") ||
610
- content.includes("i live in") ||
611
- content.includes("i am a")) {
612
- const factKey = this.extractFactKey(text);
613
- if (factKey) {
614
- this.storeMemory({
615
- sessionId: null, // Global memory
616
- key: factKey,
617
- value: { stated: text, timestamp: Date.now() },
618
- type: "fact",
619
- });
620
- }
621
- }
622
- }
623
- }
624
- }
625
- /**
626
- * Extract preference key from message content
627
- */
628
- extractPreferenceKey(content) {
629
- const lower = content.toLowerCase();
630
- if (lower.includes("dark mode"))
631
- return "pref:theme:dark";
632
- if (lower.includes("light mode"))
633
- return "pref:theme:light";
634
- if (lower.includes("email updates"))
635
- return "pref:email-updates";
636
- if (lower.includes("notifications"))
637
- return "pref:notifications";
638
- // Pattern matching
639
- const preferMatch = content.match(/i (?:prefer|like|want) (.+?)(?:\.|,|!|$)/i);
640
- if (preferMatch) {
641
- return `pref:custom:${preferMatch[1].trim().toLowerCase()}`;
642
- }
643
- return null;
644
- }
645
- /**
646
- * Extract fact key from message content
647
- */
648
- extractFactKey(content) {
649
- const lower = content.toLowerCase();
650
- if (lower.includes("my name is")) {
651
- const name = content.match(/name is (\w+)/i)?.[1];
652
- return name ? `fact:name:${name}` : null;
653
- }
654
- if (lower.includes("i live in")) {
655
- const location = content.match(/live in (\w+(?: \w+)*)/i)?.[1];
656
- return location ? `fact:location:${location}` : null;
657
- }
658
- if (lower.includes("i am a")) {
659
- const role = content.match(/i am a (\w+(?: \w+)*)/i)?.[1];
660
- return role ? `fact:role:${role}` : null;
661
- }
662
- return null;
663
- }
664
- // ============================================================
665
- // LIFECYCLE
666
- // ============================================================
667
- /**
668
- * Called when agent starts
669
- */
670
- async onStart() {
671
- this.recordSessionEvent("session_started", {
672
- agentName: this.name,
673
- timestamp: Date.now(),
674
- });
675
- // Cleanup old memories periodically
676
- this.cleanupOldMemories();
677
- }
678
- /**
679
- * Called when a client connects
680
- */
681
- async onConnect(connection, ctx) {
682
- this.recordSessionEvent("client_connected", {
683
- connectionId: connection.id,
684
- });
685
- return super.onConnect(connection, ctx);
686
- }
687
- /**
688
- * Cleanup when destroyed
689
- */
690
- async destroy() {
691
- // Record session end
692
- this.recordSessionEvent("session_ended", {
693
- messageCount: this.messages.length,
694
- finalWorkingMemory: this.getWorkingMemory(),
695
- });
696
- // Drop ARIA tables
697
- this.sql `drop table if exists aria_memory`;
698
- this.sql `drop table if exists aria_flow_transitions`;
699
- this.sql `drop table if exists aria_session_events`;
700
- await super.destroy();
701
- }
702
- // ============================================================
703
- // HTTP ENDPOINTS
704
- // ============================================================
705
- /**
706
- * Handle HTTP requests
707
- */
708
- async onRequest(request) {
709
- const url = new URL(request.url);
710
- // GET /session - Get current session
711
- if (url.pathname === "/session" && request.method === "GET") {
712
- return Response.json(this.getSession());
713
- }
714
- // GET /working-memory - Get working memory
715
- if (url.pathname === "/working-memory" && request.method === "GET") {
716
- return Response.json(this.getWorkingMemory());
717
- }
718
- // PUT /working-memory - Set working memory value
719
- if (url.pathname === "/working-memory" && request.method === "PUT") {
720
- const body = await request.json();
721
- this.setWorkingMemory(body.key, body.value);
722
- return Response.json({ success: true });
723
- }
724
- // GET /memory - Search memories
725
- if (url.pathname === "/memory" && request.method === "GET") {
726
- const query = url.searchParams.get("q");
727
- const type = url.searchParams.get("type");
728
- const limit = parseInt(url.searchParams.get("limit") || "10", 10);
729
- const results = this.searchMemories({
730
- query: query || undefined,
731
- types: type ? [type] : undefined,
732
- limit,
733
- });
734
- return Response.json(results);
735
- }
736
- // POST /memory - Store memory
737
- if (url.pathname === "/memory" && request.method === "POST") {
738
- const body = await request.json();
739
- const id = this.storeMemory(body);
740
- return Response.json({ id, success: true });
741
- }
742
- // GET /flow-history - Get flow transition history
743
- if (url.pathname === "/flow-history" && request.method === "GET") {
744
- const flowId = url.searchParams.get("flowId") || undefined;
745
- const limit = parseInt(url.searchParams.get("limit") || "100", 10);
746
- return Response.json(this.getFlowHistory(flowId, limit));
747
- }
748
- // GET /summary - Get conversation summary
749
- if (url.pathname === "/summary" && request.method === "GET") {
750
- const summary = extractConversationSummary(batchChatToAria(this.messages));
751
- return Response.json(summary);
752
- }
753
- return super.onRequest(request);
754
- }
755
- }
756
- //# sourceMappingURL=AriaAgent.js.map