@falai/agent 0.3.10 → 0.3.12

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 (131) hide show
  1. package/README.md +192 -16
  2. package/dist/adapters/PrismaAdapter.d.ts +115 -0
  3. package/dist/adapters/PrismaAdapter.d.ts.map +1 -0
  4. package/dist/adapters/PrismaAdapter.js +331 -0
  5. package/dist/adapters/PrismaAdapter.js.map +1 -0
  6. package/dist/adapters/index.d.ts +6 -0
  7. package/dist/adapters/index.d.ts.map +1 -0
  8. package/dist/adapters/index.js +5 -0
  9. package/dist/adapters/index.js.map +1 -0
  10. package/dist/cjs/adapters/PrismaAdapter.d.ts +115 -0
  11. package/dist/cjs/adapters/PrismaAdapter.d.ts.map +1 -0
  12. package/dist/cjs/adapters/PrismaAdapter.js +335 -0
  13. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -0
  14. package/dist/cjs/adapters/index.d.ts +6 -0
  15. package/dist/cjs/adapters/index.d.ts.map +1 -0
  16. package/dist/cjs/adapters/index.js +9 -0
  17. package/dist/cjs/adapters/index.js.map +1 -0
  18. package/dist/cjs/core/Agent.d.ts +35 -0
  19. package/dist/cjs/core/Agent.d.ts.map +1 -1
  20. package/dist/cjs/core/Agent.js +153 -0
  21. package/dist/cjs/core/Agent.js.map +1 -1
  22. package/dist/cjs/core/PersistenceManager.d.ts +77 -0
  23. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -0
  24. package/dist/cjs/core/PersistenceManager.js +153 -0
  25. package/dist/cjs/core/PersistenceManager.js.map +1 -0
  26. package/dist/cjs/index.d.ts +6 -0
  27. package/dist/cjs/index.d.ts.map +1 -1
  28. package/dist/cjs/index.js +8 -1
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/cjs/providers/AnthropicProvider.d.ts +43 -0
  31. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -0
  32. package/dist/cjs/providers/AnthropicProvider.js +328 -0
  33. package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
  34. package/dist/cjs/providers/GeminiProvider.d.ts +4 -1
  35. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  36. package/dist/cjs/providers/GeminiProvider.js +96 -0
  37. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  38. package/dist/cjs/providers/OpenAIProvider.d.ts +4 -1
  39. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  40. package/dist/cjs/providers/OpenAIProvider.js +115 -0
  41. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  42. package/dist/cjs/providers/OpenRouterProvider.d.ts +4 -1
  43. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  44. package/dist/cjs/providers/OpenRouterProvider.js +115 -0
  45. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  46. package/dist/cjs/providers/index.d.ts +13 -0
  47. package/dist/cjs/providers/index.d.ts.map +1 -0
  48. package/dist/cjs/providers/index.js +16 -0
  49. package/dist/cjs/providers/index.js.map +1 -0
  50. package/dist/cjs/types/agent.d.ts +3 -0
  51. package/dist/cjs/types/agent.d.ts.map +1 -1
  52. package/dist/cjs/types/agent.js.map +1 -1
  53. package/dist/cjs/types/ai.d.ts +28 -0
  54. package/dist/cjs/types/ai.d.ts.map +1 -1
  55. package/dist/cjs/types/index.d.ts +1 -0
  56. package/dist/cjs/types/index.d.ts.map +1 -1
  57. package/dist/cjs/types/persistence.d.ts +194 -0
  58. package/dist/cjs/types/persistence.d.ts.map +1 -0
  59. package/dist/cjs/types/persistence.js +7 -0
  60. package/dist/cjs/types/persistence.js.map +1 -0
  61. package/dist/core/Agent.d.ts +35 -0
  62. package/dist/core/Agent.d.ts.map +1 -1
  63. package/dist/core/Agent.js +153 -0
  64. package/dist/core/Agent.js.map +1 -1
  65. package/dist/core/PersistenceManager.d.ts +77 -0
  66. package/dist/core/PersistenceManager.d.ts.map +1 -0
  67. package/dist/core/PersistenceManager.js +149 -0
  68. package/dist/core/PersistenceManager.js.map +1 -0
  69. package/dist/index.d.ts +6 -0
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +4 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/providers/AnthropicProvider.d.ts +43 -0
  74. package/dist/providers/AnthropicProvider.d.ts.map +1 -0
  75. package/dist/providers/AnthropicProvider.js +321 -0
  76. package/dist/providers/AnthropicProvider.js.map +1 -0
  77. package/dist/providers/GeminiProvider.d.ts +4 -1
  78. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  79. package/dist/providers/GeminiProvider.js +96 -0
  80. package/dist/providers/GeminiProvider.js.map +1 -1
  81. package/dist/providers/OpenAIProvider.d.ts +4 -1
  82. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  83. package/dist/providers/OpenAIProvider.js +115 -0
  84. package/dist/providers/OpenAIProvider.js.map +1 -1
  85. package/dist/providers/OpenRouterProvider.d.ts +4 -1
  86. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  87. package/dist/providers/OpenRouterProvider.js +115 -0
  88. package/dist/providers/OpenRouterProvider.js.map +1 -1
  89. package/dist/providers/index.d.ts +13 -0
  90. package/dist/providers/index.d.ts.map +1 -0
  91. package/dist/providers/index.js +9 -0
  92. package/dist/providers/index.js.map +1 -0
  93. package/dist/types/agent.d.ts +3 -0
  94. package/dist/types/agent.d.ts.map +1 -1
  95. package/dist/types/agent.js.map +1 -1
  96. package/dist/types/ai.d.ts +28 -0
  97. package/dist/types/ai.d.ts.map +1 -1
  98. package/dist/types/index.d.ts +1 -0
  99. package/dist/types/index.d.ts.map +1 -1
  100. package/dist/types/persistence.d.ts +194 -0
  101. package/dist/types/persistence.d.ts.map +1 -0
  102. package/dist/types/persistence.js +6 -0
  103. package/dist/types/persistence.js.map +1 -0
  104. package/docs/API_REFERENCE.md +260 -2
  105. package/docs/PERSISTENCE.md +419 -0
  106. package/docs/PROVIDERS.md +139 -2
  107. package/examples/business-onboarding.ts +5 -4
  108. package/examples/declarative-agent.ts +1 -1
  109. package/examples/domain-scoping.ts +5 -4
  110. package/examples/healthcare-agent.ts +4 -4
  111. package/examples/openai-agent.ts +6 -4
  112. package/examples/prisma-persistence.ts +313 -0
  113. package/examples/prisma-schema.example.prisma +74 -0
  114. package/examples/rules-prohibitions.ts +4 -4
  115. package/examples/streaming-agent.ts +371 -0
  116. package/examples/travel-agent.ts +7 -4
  117. package/package.json +10 -1
  118. package/src/adapters/PrismaAdapter.ts +510 -0
  119. package/src/adapters/index.ts +10 -0
  120. package/src/core/Agent.ts +205 -0
  121. package/src/core/PersistenceManager.ts +222 -0
  122. package/src/index.ts +23 -0
  123. package/src/providers/AnthropicProvider.ts +467 -0
  124. package/src/providers/GeminiProvider.ts +135 -0
  125. package/src/providers/OpenAIProvider.ts +157 -0
  126. package/src/providers/OpenRouterProvider.ts +157 -0
  127. package/src/providers/index.ts +16 -0
  128. package/src/types/agent.ts +3 -0
  129. package/src/types/ai.ts +32 -0
  130. package/src/types/index.ts +14 -0
  131. package/src/types/persistence.ts +234 -0
package/docs/PROVIDERS.md CHANGED
@@ -10,11 +10,111 @@ This guide covers the available AI providers and how to configure them for optim
10
10
  - ✅ Configure provider-specific settings
11
11
  - ✅ Use backup models for failover
12
12
  - ✅ Customize retry logic and timeouts
13
+ - ⚡ **Stream responses in real-time** (all providers)
14
+
15
+ ## Streaming Support
16
+
17
+ **All providers support real-time streaming** via the `respondStream()` method on the Agent class.
18
+
19
+ Streaming provides:
20
+
21
+ - 🌊 Real-time text generation for better UX
22
+ - 📊 Incremental delivery with `delta` and `accumulated` properties
23
+ - 🛑 Cancellable streams using AbortSignal
24
+ - ✅ Full compatibility with routes, states, and tool calls
25
+
26
+ **Example:**
27
+
28
+ ```typescript
29
+ for await (const chunk of agent.respondStream({ history })) {
30
+ process.stdout.write(chunk.delta); // Print incremental text
31
+
32
+ if (chunk.done) {
33
+ // Access final metadata
34
+ console.log("Route:", chunk.route?.title);
35
+ console.log("Tool calls:", chunk.toolCalls?.length);
36
+ }
37
+ }
38
+ ```
39
+
40
+ See [streaming-agent.ts](../examples/streaming-agent.ts) for comprehensive examples with all providers.
13
41
 
14
42
  ---
15
43
 
16
44
  ## Available Providers
17
45
 
46
+ ### 🤖 Anthropic (Claude)
47
+
48
+ **Package:** `@anthropic-ai/sdk`
49
+
50
+ #### Overview
51
+
52
+ Anthropic's Claude models are known for their exceptional reasoning, analysis, and long context windows. Claude 3.5 Sonnet offers:
53
+
54
+ - State-of-the-art reasoning and analysis
55
+ - 200K context window
56
+ - Excellent at following complex instructions
57
+ - Strong coding and writing capabilities
58
+
59
+ #### Installation
60
+
61
+ ```bash
62
+ bun add @anthropic-ai/sdk
63
+ # or
64
+ npm install @anthropic-ai/sdk
65
+ ```
66
+
67
+ #### Basic Usage
68
+
69
+ ```typescript
70
+ import { AnthropicProvider } from "@falai/agent";
71
+
72
+ const provider = new AnthropicProvider({
73
+ apiKey: process.env.ANTHROPIC_API_KEY!,
74
+ model: "claude-sonnet-4-5", // Latest Claude 4.5 Sonnet
75
+ });
76
+ ```
77
+
78
+ #### Configuration Options
79
+
80
+ All models are specified by the user - see [Anthropic Models](https://docs.anthropic.com/en/docs/models-overview) for available options.
81
+
82
+ ```typescript
83
+ const provider = new AnthropicProvider({
84
+ // Required
85
+ apiKey: string;
86
+ model: string; // e.g., "claude-sonnet-4-5", "claude-opus-4-1", etc.
87
+
88
+ // Optional
89
+ backupModels?: string[]; // Default: []
90
+ config?: Partial<Omit<MessageCreateParamsNonStreaming, "model" | "messages" | "max_tokens">>; // Uses @anthropic-ai/sdk types
91
+ retryConfig?: {
92
+ timeout?: number; // Default: 60000ms (60s)
93
+ retries?: number; // Default: 3
94
+ };
95
+ });
96
+ ```
97
+
98
+ #### Example: Advanced Configuration
99
+
100
+ ```typescript
101
+ const provider = new AnthropicProvider({
102
+ apiKey: process.env.ANTHROPIC_API_KEY!,
103
+ model: "claude-sonnet-4-5",
104
+ backupModels: ["claude-opus-4-1", "claude-sonnet-4-0"],
105
+ config: {
106
+ temperature: 0.7,
107
+ top_p: 0.9,
108
+ },
109
+ retryConfig: {
110
+ timeout: 45000,
111
+ retries: 2,
112
+ },
113
+ });
114
+ ```
115
+
116
+ ---
117
+
18
118
  ### 🌐 OpenRouter (Multi-Model Access)
19
119
 
20
120
  **Package:** `openai` (OpenRouter uses OpenAI-compatible API)
@@ -274,7 +374,22 @@ const provider = new OpenAIProvider({
274
374
  You can easily switch between providers:
275
375
 
276
376
  ```typescript
277
- import { Agent, GeminiProvider, OpenAIProvider } from "@falai/agent";
377
+ import {
378
+ Agent,
379
+ AnthropicProvider,
380
+ GeminiProvider,
381
+ OpenAIProvider,
382
+ OpenRouterProvider,
383
+ } from "@falai/agent";
384
+
385
+ // Use Anthropic (Claude)
386
+ const claudeAgent = new Agent({
387
+ name: "Claude Assistant",
388
+ ai: new AnthropicProvider({
389
+ apiKey: process.env.ANTHROPIC_API_KEY!,
390
+ model: "claude-sonnet-4-5",
391
+ }),
392
+ });
278
393
 
279
394
  // Use Gemini
280
395
  const geminiAgent = new Agent({
@@ -290,10 +405,20 @@ const openaiAgent = new Agent({
290
405
  name: "OpenAI Assistant",
291
406
  ai: new OpenAIProvider({
292
407
  apiKey: process.env.OPENAI_API_KEY!,
408
+ model: "gpt-5",
293
409
  }),
294
410
  });
295
411
 
296
- // Both agents have the same interface!
412
+ // Use OpenRouter (access to 200+ models)
413
+ const openrouterAgent = new Agent({
414
+ name: "OpenRouter Assistant",
415
+ ai: new OpenRouterProvider({
416
+ apiKey: process.env.OPENROUTER_API_KEY!,
417
+ model: "anthropic/claude-sonnet-4-5",
418
+ }),
419
+ });
420
+
421
+ // All agents have the same interface!
297
422
  ```
298
423
 
299
424
  ---
@@ -304,8 +429,10 @@ It's recommended to store API keys in environment variables:
304
429
 
305
430
  ```bash
306
431
  # .env
432
+ ANTHROPIC_API_KEY=your-anthropic-api-key-here
307
433
  GEMINI_API_KEY=your-gemini-api-key-here
308
434
  OPENAI_API_KEY=your-openai-api-key-here
435
+ OPENROUTER_API_KEY=your-openrouter-api-key-here
309
436
  ```
310
437
 
311
438
  Then load them:
@@ -314,6 +441,11 @@ Then load them:
314
441
  import { config } from "dotenv";
315
442
  config();
316
443
 
444
+ const anthropicProvider = new AnthropicProvider({
445
+ apiKey: process.env.ANTHROPIC_API_KEY!,
446
+ model: "claude-sonnet-4-5",
447
+ });
448
+
317
449
  const geminiProvider = new GeminiProvider({
318
450
  apiKey: process.env.GEMINI_API_KEY!,
319
451
  model: "models/gemini-2.5-flash",
@@ -323,6 +455,11 @@ const openaiProvider = new OpenAIProvider({
323
455
  apiKey: process.env.OPENAI_API_KEY!,
324
456
  model: "gpt-5",
325
457
  });
458
+
459
+ const openrouterProvider = new OpenRouterProvider({
460
+ apiKey: process.env.OPENROUTER_API_KEY!,
461
+ model: "anthropic/claude-sonnet-4-5",
462
+ });
326
463
  ```
327
464
 
328
465
  ---
@@ -13,10 +13,10 @@
13
13
  import {
14
14
  Agent,
15
15
  defineTool,
16
- GeminiProvider,
17
16
  END_ROUTE,
18
17
  EventSource,
19
18
  createMessageEvent,
19
+ OpenAIProvider,
20
20
  type ToolContext,
21
21
  } from "../src/index";
22
22
 
@@ -362,9 +362,10 @@ async function createBusinessOnboardingAgent(
362
362
  sessionId: string,
363
363
  initialData: OnboardingData = { routes: [] }
364
364
  ): Promise<Agent<OnboardingContext>> {
365
- const provider = new GeminiProvider({
366
- apiKey: process.env.GEMINI_API_KEY || "test-key",
367
- model: "models/gemini-2.0-flash-exp",
365
+ const provider = new OpenAIProvider({
366
+ apiKey: process.env.OPENAI_API_KEY || "test-key",
367
+ model: "gpt-5",
368
+ backupModels: ["gpt-5-mini"],
368
369
  retryConfig: {
369
370
  timeout: 60000,
370
371
  retries: 3,
@@ -13,10 +13,10 @@
13
13
 
14
14
  import {
15
15
  Agent,
16
- GeminiProvider,
17
16
  defineTool,
18
17
  createMessageEvent,
19
18
  EventSource,
19
+ GeminiProvider,
20
20
  type Term,
21
21
  type Guideline,
22
22
  type Capability,
@@ -6,12 +6,13 @@
6
6
  */
7
7
 
8
8
  import { Agent, createMessageEvent, EventSource } from "../src/index";
9
- import { GeminiProvider } from "../src/providers/GeminiProvider";
9
+ import { OpenRouterProvider } from "../src/providers";
10
10
 
11
11
  // Initialize AI provider
12
- const ai = new GeminiProvider({
13
- apiKey: process.env.GEMINI_API_KEY || "your-api-key-here",
14
- model: "gemini-2.0-flash-exp",
12
+ const ai = new OpenRouterProvider({
13
+ apiKey: process.env.OPENROUTER_API_KEY || "your-api-key-here",
14
+ model: "google/gemini-2.0-flash-exp",
15
+ backupModels: ["anthropic/claude-sonnet-4-5"],
15
16
  });
16
17
 
17
18
  // Create agent
@@ -5,7 +5,7 @@
5
5
  import {
6
6
  Agent,
7
7
  defineTool,
8
- GeminiProvider,
8
+ AnthropicProvider,
9
9
  END_ROUTE,
10
10
  EventSource,
11
11
  createMessageEvent,
@@ -63,9 +63,9 @@ const getLabResults = defineTool<HealthcareContext, [], object>(
63
63
  );
64
64
 
65
65
  async function createHealthcareAgent() {
66
- const provider = new GeminiProvider({
67
- apiKey: process.env.GEMINI_API_KEY || "test-key",
68
- model: "models/gemini-2.5-flash",
66
+ const provider = new AnthropicProvider({
67
+ apiKey: process.env.ANTHROPIC_API_KEY || "test-key",
68
+ model: "claude-sonnet-4-5",
69
69
  });
70
70
 
71
71
  const agent = new Agent<HealthcareContext>({
@@ -108,10 +108,12 @@ async function main() {
108
108
  chatState: "Ask which city they want weather for",
109
109
  });
110
110
 
111
- const fetchWeather = askLocation.transitionTo({
112
- toolState: getWeather,
113
- condition: "User provides a city name",
114
- });
111
+ const fetchWeather = askLocation.transitionTo(
112
+ {
113
+ toolState: getWeather,
114
+ },
115
+ "User provides a city name"
116
+ );
115
117
 
116
118
  const showWeather = fetchWeather.transitionTo({
117
119
  chatState:
@@ -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
+
@@ -6,12 +6,12 @@
6
6
  */
7
7
 
8
8
  import { Agent, createMessageEvent, EventSource } from "../src/index";
9
- import { GeminiProvider } from "../src/providers/GeminiProvider";
9
+ import { AnthropicProvider } from "../src/providers";
10
10
 
11
11
  // Initialize AI provider
12
- const ai = new GeminiProvider({
13
- apiKey: process.env.GEMINI_API_KEY || "your-api-key-here",
14
- model: "gemini-2.0-flash-exp",
12
+ const ai = new AnthropicProvider({
13
+ apiKey: process.env.ANTHROPIC_API_KEY || "your-api-key-here",
14
+ model: "claude-sonnet-4-5",
15
15
  });
16
16
 
17
17
  // Create WhatsApp support bot with different styles per route