@falai/agent 0.3.11 → 0.3.20

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 (101) hide show
  1. package/README.md +164 -0
  2. package/dist/adapters/MongoAdapter.d.ts +97 -0
  3. package/dist/adapters/MongoAdapter.d.ts.map +1 -0
  4. package/dist/adapters/MongoAdapter.js +163 -0
  5. package/dist/adapters/MongoAdapter.js.map +1 -0
  6. package/dist/adapters/PostgreSQLAdapter.d.ts +71 -0
  7. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  8. package/dist/adapters/PostgreSQLAdapter.js +256 -0
  9. package/dist/adapters/PostgreSQLAdapter.js.map +1 -0
  10. package/dist/adapters/PrismaAdapter.d.ts +115 -0
  11. package/dist/adapters/PrismaAdapter.d.ts.map +1 -0
  12. package/dist/adapters/PrismaAdapter.js +331 -0
  13. package/dist/adapters/PrismaAdapter.js.map +1 -0
  14. package/dist/adapters/RedisAdapter.d.ts +71 -0
  15. package/dist/adapters/RedisAdapter.d.ts.map +1 -0
  16. package/dist/adapters/RedisAdapter.js +226 -0
  17. package/dist/adapters/RedisAdapter.js.map +1 -0
  18. package/dist/adapters/index.d.ts +12 -0
  19. package/dist/adapters/index.d.ts.map +1 -0
  20. package/dist/adapters/index.js +8 -0
  21. package/dist/adapters/index.js.map +1 -0
  22. package/dist/cjs/adapters/MongoAdapter.d.ts +97 -0
  23. package/dist/cjs/adapters/MongoAdapter.d.ts.map +1 -0
  24. package/dist/cjs/adapters/MongoAdapter.js +167 -0
  25. package/dist/cjs/adapters/MongoAdapter.js.map +1 -0
  26. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +71 -0
  27. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -0
  28. package/dist/cjs/adapters/PostgreSQLAdapter.js +260 -0
  29. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -0
  30. package/dist/cjs/adapters/PrismaAdapter.d.ts +115 -0
  31. package/dist/cjs/adapters/PrismaAdapter.d.ts.map +1 -0
  32. package/dist/cjs/adapters/PrismaAdapter.js +335 -0
  33. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -0
  34. package/dist/cjs/adapters/RedisAdapter.d.ts +71 -0
  35. package/dist/cjs/adapters/RedisAdapter.d.ts.map +1 -0
  36. package/dist/cjs/adapters/RedisAdapter.js +230 -0
  37. package/dist/cjs/adapters/RedisAdapter.js.map +1 -0
  38. package/dist/cjs/adapters/index.d.ts +12 -0
  39. package/dist/cjs/adapters/index.d.ts.map +1 -0
  40. package/dist/cjs/adapters/index.js +15 -0
  41. package/dist/cjs/adapters/index.js.map +1 -0
  42. package/dist/cjs/core/Agent.d.ts +10 -0
  43. package/dist/cjs/core/Agent.d.ts.map +1 -1
  44. package/dist/cjs/core/Agent.js +23 -0
  45. package/dist/cjs/core/Agent.js.map +1 -1
  46. package/dist/cjs/core/PersistenceManager.d.ts +77 -0
  47. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -0
  48. package/dist/cjs/core/PersistenceManager.js +153 -0
  49. package/dist/cjs/core/PersistenceManager.js.map +1 -0
  50. package/dist/cjs/index.d.ts +10 -0
  51. package/dist/cjs/index.d.ts.map +1 -1
  52. package/dist/cjs/index.js +12 -1
  53. package/dist/cjs/index.js.map +1 -1
  54. package/dist/cjs/types/agent.d.ts +3 -0
  55. package/dist/cjs/types/agent.d.ts.map +1 -1
  56. package/dist/cjs/types/agent.js.map +1 -1
  57. package/dist/cjs/types/index.d.ts +1 -0
  58. package/dist/cjs/types/index.d.ts.map +1 -1
  59. package/dist/cjs/types/persistence.d.ts +194 -0
  60. package/dist/cjs/types/persistence.d.ts.map +1 -0
  61. package/dist/cjs/types/persistence.js +7 -0
  62. package/dist/cjs/types/persistence.js.map +1 -0
  63. package/dist/core/Agent.d.ts +10 -0
  64. package/dist/core/Agent.d.ts.map +1 -1
  65. package/dist/core/Agent.js +23 -0
  66. package/dist/core/Agent.js.map +1 -1
  67. package/dist/core/PersistenceManager.d.ts +77 -0
  68. package/dist/core/PersistenceManager.d.ts.map +1 -0
  69. package/dist/core/PersistenceManager.js +149 -0
  70. package/dist/core/PersistenceManager.js.map +1 -0
  71. package/dist/index.d.ts +10 -0
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +6 -0
  74. package/dist/index.js.map +1 -1
  75. package/dist/types/agent.d.ts +3 -0
  76. package/dist/types/agent.d.ts.map +1 -1
  77. package/dist/types/agent.js.map +1 -1
  78. package/dist/types/index.d.ts +1 -0
  79. package/dist/types/index.d.ts.map +1 -1
  80. package/dist/types/persistence.d.ts +194 -0
  81. package/dist/types/persistence.d.ts.map +1 -0
  82. package/dist/types/persistence.js +6 -0
  83. package/dist/types/persistence.js.map +1 -0
  84. package/docs/ADAPTERS.md +127 -0
  85. package/docs/API_REFERENCE.md +337 -0
  86. package/docs/PERSISTENCE.md +513 -0
  87. package/examples/prisma-persistence.ts +313 -0
  88. package/examples/prisma-schema.example.prisma +74 -0
  89. package/examples/redis-persistence.ts +89 -0
  90. package/package.json +29 -1
  91. package/src/adapters/MongoAdapter.ts +295 -0
  92. package/src/adapters/PostgreSQLAdapter.ts +417 -0
  93. package/src/adapters/PrismaAdapter.ts +510 -0
  94. package/src/adapters/RedisAdapter.ts +365 -0
  95. package/src/adapters/index.ts +28 -0
  96. package/src/core/Agent.ts +31 -0
  97. package/src/core/PersistenceManager.ts +222 -0
  98. package/src/index.ts +36 -0
  99. package/src/types/agent.ts +3 -0
  100. package/src/types/index.ts +14 -0
  101. package/src/types/persistence.ts +234 -0
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Example: Using Prisma ORM for Persistence
3
+ *
4
+ * This example shows how to use @falai/agent with Prisma for automatic
5
+ * session and message persistence - as easy as using an AI provider!
6
+ */
7
+
8
+ import {
9
+ Agent,
10
+ GeminiProvider,
11
+ PrismaAdapter,
12
+ createMessageEvent,
13
+ EventSource,
14
+ } from "../src/index";
15
+
16
+ // @ts-ignore
17
+ import { PrismaClient } from "@prisma/client";
18
+
19
+ /**
20
+ * Setup Steps:
21
+ *
22
+ * 1. Install dependencies:
23
+ * npm install prisma @prisma/client
24
+ *
25
+ * 2. Initialize Prisma:
26
+ * npx prisma init
27
+ *
28
+ * 3. Copy schema from examples/prisma-schema.example.prisma
29
+ * to your prisma/schema.prisma file
30
+ *
31
+ * 4. Generate Prisma client:
32
+ * npx prisma generate
33
+ *
34
+ * 5. Run migrations:
35
+ * npx prisma migrate dev --name init
36
+ */
37
+
38
+ // Example context type
39
+ interface ConversationContext {
40
+ userId: string;
41
+ sessionId: string;
42
+ userName: string;
43
+ preferences: {
44
+ language: string;
45
+ theme: string;
46
+ };
47
+ }
48
+
49
+ async function example() {
50
+ // Initialize Prisma client
51
+ const prisma = new PrismaClient();
52
+
53
+ const userId = "user_123";
54
+
55
+ /**
56
+ * Create Agent with Persistence - Simple Provider Pattern! ✨
57
+ */
58
+ const agent = new Agent<ConversationContext>({
59
+ name: "Shopping Assistant",
60
+ description: "A helpful shopping assistant",
61
+ ai: new GeminiProvider({
62
+ apiKey: process.env.GEMINI_API_KEY!,
63
+ model: "models/gemini-2.0-flash-exp",
64
+ }),
65
+ context: {
66
+ userId,
67
+ sessionId: "", // Will be set when we create/load a session
68
+ userName: "Alice",
69
+ preferences: {
70
+ language: "en",
71
+ theme: "light",
72
+ },
73
+ },
74
+ // ✨ Just pass the adapter - that's it!
75
+ persistence: {
76
+ adapter: new PrismaAdapter({ prisma }),
77
+ autoSave: true,
78
+ userId,
79
+ },
80
+ });
81
+
82
+ /**
83
+ * Get persistence manager from agent
84
+ */
85
+ const persistence = agent.getPersistenceManager();
86
+
87
+ if (!persistence) {
88
+ throw new Error("Persistence not configured");
89
+ }
90
+
91
+ /**
92
+ * Create or find a session
93
+ */
94
+ let session = await persistence.findActiveSession(userId);
95
+
96
+ if (!session) {
97
+ session = await persistence.createSession({
98
+ userId,
99
+ agentName: "Shopping Assistant",
100
+ initialData: {
101
+ language: "en",
102
+ theme: "light",
103
+ },
104
+ });
105
+ console.log("✨ Created new session:", session.id);
106
+ } else {
107
+ console.log("📂 Found active session:", session.id);
108
+ }
109
+
110
+ // Update context with session ID
111
+ await agent.updateContext({
112
+ sessionId: session.id,
113
+ } as Partial<ConversationContext>);
114
+
115
+ /**
116
+ * Load conversation history
117
+ */
118
+ const history = await persistence.loadSessionHistory(session.id);
119
+ console.log(`📜 Loaded ${history.length} messages from history`);
120
+
121
+ /**
122
+ * Send a message
123
+ */
124
+ const userMessage = createMessageEvent(
125
+ EventSource.CUSTOMER,
126
+ "Alice",
127
+ "I'm looking for a winter jacket"
128
+ );
129
+
130
+ // Save user message
131
+ await persistence.saveMessage({
132
+ sessionId: session.id,
133
+ userId,
134
+ role: "user",
135
+ content: "I'm looking for a winter jacket",
136
+ event: userMessage,
137
+ });
138
+
139
+ history.push(userMessage);
140
+
141
+ // Generate agent response
142
+ const response = await agent.respond({ history });
143
+ console.log("🤖 Agent:", response.message);
144
+
145
+ // Save agent message
146
+ await persistence.saveMessage({
147
+ sessionId: session.id,
148
+ userId,
149
+ role: "agent",
150
+ content: response.message,
151
+ route: response.route?.id,
152
+ state: response.state?.id,
153
+ toolCalls: response.toolCalls,
154
+ });
155
+
156
+ /**
157
+ * Query sessions and messages
158
+ */
159
+ const userSessions = await persistence.getUserSessions(userId);
160
+ console.log(`👤 User has ${userSessions.length} total sessions`);
161
+
162
+ const messages = await persistence.getSessionMessages(session.id);
163
+ console.log(`💬 Session has ${messages.length} messages`);
164
+
165
+ /**
166
+ * Complete the session
167
+ */
168
+ await persistence.completeSession(session.id);
169
+ console.log("✅ Session completed");
170
+
171
+ /**
172
+ * Cleanup
173
+ */
174
+ await prisma.$disconnect();
175
+ }
176
+
177
+ /**
178
+ * Advanced Example: Using with Lifecycle Hooks
179
+ */
180
+ async function advancedExample() {
181
+ const prisma = new PrismaClient();
182
+ const userId = "user_123";
183
+
184
+ const agent = new Agent<ConversationContext>({
185
+ name: "Smart Assistant",
186
+ description: "An intelligent assistant with persistent state",
187
+ ai: new GeminiProvider({
188
+ apiKey: process.env.GEMINI_API_KEY!,
189
+ model: "models/gemini-2.0-flash-exp",
190
+ }),
191
+ context: {
192
+ userId,
193
+ sessionId: "",
194
+ userName: "Alice",
195
+ preferences: {
196
+ language: "en",
197
+ theme: "light",
198
+ },
199
+ },
200
+ // Lifecycle hooks for automatic context sync
201
+ hooks: {
202
+ // Load fresh context before each response
203
+ beforeRespond: async (currentContext) => {
204
+ const persistence = agent.getPersistenceManager();
205
+ if (!persistence) return currentContext;
206
+
207
+ const freshSession = await persistence.getSession(
208
+ currentContext.sessionId
209
+ );
210
+ return {
211
+ ...currentContext,
212
+ preferences:
213
+ (
214
+ freshSession?.collectedData as {
215
+ preferences?: typeof currentContext.preferences;
216
+ }
217
+ )?.preferences || currentContext.preferences,
218
+ };
219
+ },
220
+ // Automatically persist context updates
221
+ onContextUpdate: async (newContext) => {
222
+ const persistence = agent.getPersistenceManager();
223
+ if (!persistence) return;
224
+
225
+ await persistence.updateCollectedData(newContext.sessionId, {
226
+ preferences: newContext.preferences,
227
+ });
228
+ },
229
+ },
230
+ // ✨ Same simple adapter pattern!
231
+ persistence: {
232
+ adapter: new PrismaAdapter({ prisma }),
233
+ autoSave: true,
234
+ userId,
235
+ },
236
+ });
237
+
238
+ // Create a session
239
+ const persistence = agent.getPersistenceManager();
240
+ const session = await persistence!.createSession({
241
+ userId,
242
+ agentName: "Smart Assistant",
243
+ });
244
+
245
+ await agent.updateContext({
246
+ sessionId: session.id,
247
+ } as Partial<ConversationContext>);
248
+
249
+ // Now context updates are automatically persisted!
250
+ await agent.updateContext({
251
+ preferences: {
252
+ language: "es",
253
+ theme: "dark",
254
+ },
255
+ } as Partial<ConversationContext>);
256
+
257
+ console.log("🎉 Context updates automatically saved to database!");
258
+
259
+ await prisma.$disconnect();
260
+ }
261
+
262
+ /**
263
+ * Minimal Example - Quick Start
264
+ */
265
+ async function quickStart() {
266
+ const prisma = new PrismaClient();
267
+
268
+ // That's it! Just create the adapter and pass it
269
+ const agent = new Agent({
270
+ name: "My Agent",
271
+ description: "A helpful assistant",
272
+ ai: new GeminiProvider({
273
+ apiKey: process.env.GEMINI_API_KEY!,
274
+ model: "models/gemini-2.5-flash",
275
+ }),
276
+ persistence: {
277
+ adapter: new PrismaAdapter({ prisma }), // ✨ Simple!
278
+ userId: "user_123",
279
+ },
280
+ });
281
+
282
+ // Get persistence manager
283
+ const persistence = agent.getPersistenceManager();
284
+ if (!persistence) return;
285
+
286
+ // Create session
287
+ const session = await persistence.createSession({
288
+ userId: "user_123",
289
+ agentName: "My Agent",
290
+ });
291
+
292
+ // Load history and respond
293
+ const history = await persistence.loadSessionHistory(session.id);
294
+ const response = await agent.respond({ history });
295
+
296
+ // Save message
297
+ await persistence.saveMessage({
298
+ sessionId: session.id,
299
+ role: "agent",
300
+ content: response.message,
301
+ });
302
+
303
+ console.log("✅ Done! Messages automatically saved to Prisma.");
304
+
305
+ await prisma.$disconnect();
306
+ }
307
+
308
+ // Run the example
309
+ if (require.main === module) {
310
+ example().catch(console.error);
311
+ }
312
+
313
+ export { example, advancedExample, quickStart };
@@ -0,0 +1,74 @@
1
+ // This is an example Prisma schema file for @falai/agent persistence
2
+ // Copy and adapt this to your needs
3
+
4
+ datasource db {
5
+ provider = "postgresql" // or "mysql", "sqlite", "sqlserver", "mongodb"
6
+ url = env("DATABASE_URL")
7
+ }
8
+
9
+ generator client {
10
+ provider = "prisma-client-js"
11
+ }
12
+
13
+ // Agent Session model
14
+ // Stores conversation session state
15
+ model AgentSession {
16
+ id String @id @default(cuid())
17
+ userId String? @map("user_id")
18
+ agentName String? @map("agent_name")
19
+ status String @default("active") // "active" | "completed" | "abandoned"
20
+ currentRoute String? @map("current_route")
21
+ currentState String? @map("current_state")
22
+ collectedData Json? @map("collected_data")
23
+ messageCount Int @default(0) @map("message_count")
24
+ lastMessageAt DateTime? @map("last_message_at")
25
+ completedAt DateTime? @map("completed_at")
26
+ createdAt DateTime @default(now()) @map("created_at")
27
+ updatedAt DateTime @updatedAt @map("updated_at")
28
+
29
+ // Relations
30
+ messages AgentMessage[]
31
+
32
+ @@index([userId])
33
+ @@index([status])
34
+ @@index([userId, status])
35
+ @@map("agent_sessions")
36
+ }
37
+
38
+ // Agent Message model
39
+ // Stores individual messages in a conversation
40
+ model AgentMessage {
41
+ id String @id @default(cuid())
42
+ sessionId String @map("session_id")
43
+ userId String? @map("user_id")
44
+ role String // "user" | "agent" | "system"
45
+ content String @db.Text
46
+ route String?
47
+ state String?
48
+ toolCalls Json? @map("tool_calls")
49
+ event Json? // Optional: store full event data
50
+ createdAt DateTime @default(now()) @map("created_at")
51
+
52
+ // Relations
53
+ session AgentSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
54
+
55
+ @@index([sessionId])
56
+ @@index([userId])
57
+ @@index([sessionId, createdAt])
58
+ @@map("agent_messages")
59
+ }
60
+
61
+ // Alternative: If you want different table names, you can customize:
62
+ //
63
+ // model ConversationSession {
64
+ // id String @id @default(cuid())
65
+ // ...
66
+ // @@map("conversations")
67
+ // }
68
+ //
69
+ // model ChatMessage {
70
+ // id String @id @default(cuid())
71
+ // ...
72
+ // @@map("chat_messages")
73
+ // }
74
+
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Example: Using Redis for Persistence
3
+ *
4
+ * Fast, in-memory persistence perfect for:
5
+ * - High-throughput applications
6
+ * - Session caching
7
+ * - Real-time chat applications
8
+ * - Temporary conversation storage
9
+ */
10
+
11
+ import { Agent, GeminiProvider, RedisAdapter } from "../src/index";
12
+ // @ts-ignore
13
+ import Redis from "ioredis";
14
+
15
+ /**
16
+ * Setup Steps:
17
+ *
18
+ * 1. Install Redis and client:
19
+ * brew install redis (macOS) or apt-get install redis (Linux)
20
+ * npm install ioredis
21
+ *
22
+ * 2. Start Redis:
23
+ * redis-server
24
+ *
25
+ * 3. Run this example
26
+ */
27
+
28
+ async function example() {
29
+ // Initialize Redis client
30
+ const redis = new Redis();
31
+
32
+ // Create agent with Redis persistence
33
+ const agent = new Agent({
34
+ name: "Chat Assistant",
35
+ description: "Fast, real-time chat assistant",
36
+ ai: new GeminiProvider({
37
+ apiKey: process.env.GEMINI_API_KEY!,
38
+ model: "models/gemini-2.0-flash-exp",
39
+ }),
40
+ // ✨ Redis adapter with custom options
41
+ persistence: {
42
+ adapter: new RedisAdapter({
43
+ redis,
44
+ keyPrefix: "chat:", // Custom prefix
45
+ sessionTTL: 24 * 60 * 60, // 24 hours
46
+ messageTTL: 7 * 24 * 60 * 60, // 7 days
47
+ }),
48
+ autoSave: true,
49
+ userId: "user_123",
50
+ },
51
+ });
52
+
53
+ const persistence = agent.getPersistenceManager();
54
+ if (!persistence) return;
55
+
56
+ // Create session
57
+ const session = await persistence.createSession({
58
+ userId: "user_123",
59
+ agentName: "Chat Assistant",
60
+ initialData: { chatType: "support" },
61
+ });
62
+
63
+ console.log("✨ Session created in Redis:", session.id);
64
+
65
+ // Save a message
66
+ await persistence.saveMessage({
67
+ sessionId: session.id,
68
+ role: "user",
69
+ content: "Hello! I need help",
70
+ });
71
+
72
+ // Load messages
73
+ const messages = await persistence.getSessionMessages(session.id);
74
+ console.log(`💬 ${messages.length} messages in session`);
75
+
76
+ // Complete session
77
+ await persistence.completeSession(session.id);
78
+ console.log("✅ Session completed");
79
+
80
+ // Cleanup
81
+ await redis.quit();
82
+ }
83
+
84
+ // Run the example
85
+ if (require.main === module) {
86
+ example().catch(console.error);
87
+ }
88
+
89
+ export { example };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@falai/agent",
3
- "version": "0.3.11",
3
+ "version": "0.3.20",
4
4
  "description": "Standalone, strongly-typed AI Agent framework with route DSL and AI provider strategy",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -80,5 +80,33 @@
80
80
  "@anthropic-ai/sdk": "^0.65.0",
81
81
  "@google/genai": "^0.3.0",
82
82
  "openai": "^6.3.0"
83
+ },
84
+ "peerDependencies": {
85
+ "@prisma/client": "^6.0.0",
86
+ "ioredis": "^5.7.0",
87
+ "redis": "^4.6.0 || ^5.0.0",
88
+ "mongodb": "^6.0.0 || ^7.0.0",
89
+ "pg": "^8.11.0",
90
+ "mysql2": "^3.2.0"
91
+ },
92
+ "peerDependenciesMeta": {
93
+ "@prisma/client": {
94
+ "optional": true
95
+ },
96
+ "ioredis": {
97
+ "optional": true
98
+ },
99
+ "redis": {
100
+ "optional": true
101
+ },
102
+ "mongodb": {
103
+ "optional": true
104
+ },
105
+ "pg": {
106
+ "optional": true
107
+ },
108
+ "mysql2": {
109
+ "optional": true
110
+ }
83
111
  }
84
112
  }