@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
@@ -9,6 +9,7 @@ import type {
9
9
  AiProvider,
10
10
  GenerateMessageInput,
11
11
  GenerateMessageOutput,
12
+ GenerateMessageStreamChunk,
12
13
  AgentStructuredResponse,
13
14
  } from "../types/ai";
14
15
  import { withTimeoutAndRetry } from "../utils/retry";
@@ -164,6 +165,12 @@ export class OpenAIProvider implements AiProvider {
164
165
  return this.generateWithBackup(input);
165
166
  }
166
167
 
168
+ async *generateMessageStream<TContext = unknown>(
169
+ input: GenerateMessageInput<TContext>
170
+ ): AsyncGenerator<GenerateMessageStreamChunk> {
171
+ yield* this.generateStreamWithBackup(input);
172
+ }
173
+
167
174
  private async generateWithBackup<TContext = unknown>(
168
175
  input: GenerateMessageInput<TContext>
169
176
  ): Promise<GenerateMessageOutput> {
@@ -353,4 +360,154 @@ export class OpenAIProvider implements AiProvider {
353
360
  `OpenAI ${model}`
354
361
  );
355
362
  }
363
+
364
+ private async *generateStreamWithBackup<TContext = unknown>(
365
+ input: GenerateMessageInput<TContext>
366
+ ): AsyncGenerator<GenerateMessageStreamChunk> {
367
+ // Try primary model first
368
+ try {
369
+ yield* this.generateStreamWithModel(this.primaryModel, input);
370
+ } catch (primaryError: unknown) {
371
+ const primaryErrMsg = getErrorMessage(primaryError);
372
+ console.warn(
373
+ `[OPENAI] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
374
+ );
375
+
376
+ if (!shouldUseBackupModel(primaryError)) {
377
+ throw primaryError;
378
+ }
379
+
380
+ console.log(`[OPENAI] Trying backup models for streaming`);
381
+
382
+ let lastBackupError: unknown = primaryError;
383
+
384
+ for (let i = 0; i < this.backupModels.length; i++) {
385
+ const backupModel = this.backupModels[i];
386
+ console.log(
387
+ `[OPENAI] Trying backup model ${i + 1}/${
388
+ this.backupModels.length
389
+ }: ${backupModel}`
390
+ );
391
+
392
+ try {
393
+ yield* this.generateStreamWithModel(backupModel, input);
394
+ console.log(`[OPENAI] Backup model ${backupModel} succeeded`);
395
+ return;
396
+ } catch (backupError: unknown) {
397
+ const backupErrMsg = getErrorMessage(backupError);
398
+ console.warn(
399
+ `[OPENAI] Backup model ${backupModel} failed: ${backupErrMsg}`
400
+ );
401
+ lastBackupError = backupError;
402
+
403
+ if (
404
+ !shouldUseBackupModel(backupError) &&
405
+ i < this.backupModels.length - 1
406
+ ) {
407
+ console.log(
408
+ `[OPENAI] Backup model error doesn't qualify for further attempts`
409
+ );
410
+ break;
411
+ }
412
+ }
413
+ }
414
+
415
+ const lastBackupErrMsg = getErrorMessage(lastBackupError);
416
+ console.error(
417
+ `[OPENAI] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
418
+ );
419
+ throw lastBackupError;
420
+ }
421
+ }
422
+
423
+ private async *generateStreamWithModel<TContext = unknown>(
424
+ model: string,
425
+ input: GenerateMessageInput<TContext>
426
+ ): AsyncGenerator<GenerateMessageStreamChunk> {
427
+ const params = {
428
+ ...this.config,
429
+ model,
430
+ messages: [
431
+ {
432
+ role: "user" as const,
433
+ content: input.prompt,
434
+ },
435
+ ],
436
+ stream: true as const,
437
+ };
438
+
439
+ // Override with input parameters if provided
440
+ if (input.parameters?.maxOutputTokens !== undefined) {
441
+ params.max_tokens = input.parameters.maxOutputTokens;
442
+ }
443
+
444
+ // Use JSON mode if requested
445
+ // Note: OpenAI streaming doesn't support the responses.parse API,
446
+ // so we use response_format with JSON mode instead
447
+ if (input.parameters?.jsonMode) {
448
+ params.response_format = { type: "json_object" };
449
+ }
450
+
451
+ const stream = await this.client.chat.completions.create(params);
452
+
453
+ let accumulated = "";
454
+ let currentModel = model;
455
+ let finishReason: string | undefined;
456
+ let promptTokens: number | undefined;
457
+ let completionTokens: number | undefined;
458
+ let totalTokens: number | undefined;
459
+
460
+ for await (const chunk of stream) {
461
+ currentModel = chunk.model;
462
+ const delta = chunk.choices[0]?.delta?.content || "";
463
+
464
+ if (delta) {
465
+ accumulated += delta;
466
+ yield {
467
+ delta,
468
+ accumulated,
469
+ done: false,
470
+ };
471
+ }
472
+
473
+ if (chunk.choices[0]?.finish_reason) {
474
+ finishReason = chunk.choices[0].finish_reason;
475
+ }
476
+
477
+ // OpenAI includes usage in the final chunk for some models
478
+ if (chunk.usage) {
479
+ promptTokens = chunk.usage.prompt_tokens;
480
+ completionTokens = chunk.usage.completion_tokens;
481
+ totalTokens = chunk.usage.total_tokens;
482
+ }
483
+ }
484
+
485
+ // Parse JSON response if JSON mode was enabled
486
+ let structured: AgentStructuredResponse | undefined;
487
+ if (input.parameters?.jsonMode && accumulated) {
488
+ try {
489
+ structured = JSON.parse(accumulated) as AgentStructuredResponse;
490
+ } catch (error) {
491
+ console.warn(
492
+ "[OPENAI] Failed to parse JSON response in stream:",
493
+ error
494
+ );
495
+ }
496
+ }
497
+
498
+ // Yield final chunk
499
+ yield {
500
+ delta: "",
501
+ accumulated,
502
+ done: true,
503
+ metadata: {
504
+ model: currentModel,
505
+ finishReason,
506
+ tokensUsed: totalTokens,
507
+ promptTokens,
508
+ completionTokens,
509
+ },
510
+ structured,
511
+ };
512
+ }
356
513
  }
@@ -11,6 +11,7 @@ import type {
11
11
  AgentStructuredResponse,
12
12
  GenerateMessageInput,
13
13
  GenerateMessageOutput,
14
+ GenerateMessageStreamChunk,
14
15
  } from "../types/ai";
15
16
  import { withTimeoutAndRetry } from "../utils/retry";
16
17
 
@@ -174,6 +175,12 @@ export class OpenRouterProvider implements AiProvider {
174
175
  return this.generateWithBackup(input);
175
176
  }
176
177
 
178
+ async *generateMessageStream<TContext = unknown>(
179
+ input: GenerateMessageInput<TContext>
180
+ ): AsyncGenerator<GenerateMessageStreamChunk> {
181
+ yield* this.generateStreamWithBackup(input);
182
+ }
183
+
177
184
  private async generateWithBackup<TContext = unknown>(
178
185
  input: GenerateMessageInput<TContext>
179
186
  ): Promise<GenerateMessageOutput> {
@@ -363,4 +370,154 @@ export class OpenRouterProvider implements AiProvider {
363
370
  `OpenRouter ${model}`
364
371
  );
365
372
  }
373
+
374
+ private async *generateStreamWithBackup<TContext = unknown>(
375
+ input: GenerateMessageInput<TContext>
376
+ ): AsyncGenerator<GenerateMessageStreamChunk> {
377
+ // Try primary model first
378
+ try {
379
+ yield* this.generateStreamWithModel(this.primaryModel, input);
380
+ } catch (primaryError: unknown) {
381
+ const primaryErrMsg = getErrorMessage(primaryError);
382
+ console.warn(
383
+ `[OPENROUTER] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
384
+ );
385
+
386
+ if (!shouldUseBackupModel(primaryError)) {
387
+ throw primaryError;
388
+ }
389
+
390
+ console.log(`[OPENROUTER] Trying backup models for streaming`);
391
+
392
+ let lastBackupError: unknown = primaryError;
393
+
394
+ for (let i = 0; i < this.backupModels.length; i++) {
395
+ const backupModel = this.backupModels[i];
396
+ console.log(
397
+ `[OPENROUTER] Trying backup model ${i + 1}/${
398
+ this.backupModels.length
399
+ }: ${backupModel}`
400
+ );
401
+
402
+ try {
403
+ yield* this.generateStreamWithModel(backupModel, input);
404
+ console.log(`[OPENROUTER] Backup model ${backupModel} succeeded`);
405
+ return;
406
+ } catch (backupError: unknown) {
407
+ const backupErrMsg = getErrorMessage(backupError);
408
+ console.warn(
409
+ `[OPENROUTER] Backup model ${backupModel} failed: ${backupErrMsg}`
410
+ );
411
+ lastBackupError = backupError;
412
+
413
+ if (
414
+ !shouldUseBackupModel(backupError) &&
415
+ i < this.backupModels.length - 1
416
+ ) {
417
+ console.log(
418
+ `[OPENROUTER] Backup model error doesn't qualify for further attempts`
419
+ );
420
+ break;
421
+ }
422
+ }
423
+ }
424
+
425
+ const lastBackupErrMsg = getErrorMessage(lastBackupError);
426
+ console.error(
427
+ `[OPENROUTER] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
428
+ );
429
+ throw lastBackupError;
430
+ }
431
+ }
432
+
433
+ private async *generateStreamWithModel<TContext = unknown>(
434
+ model: string,
435
+ input: GenerateMessageInput<TContext>
436
+ ): AsyncGenerator<GenerateMessageStreamChunk> {
437
+ const params = {
438
+ ...this.config,
439
+ model,
440
+ messages: [
441
+ {
442
+ role: "user" as const,
443
+ content: input.prompt,
444
+ },
445
+ ],
446
+ stream: true as const,
447
+ };
448
+
449
+ // Override with input parameters if provided
450
+ if (input.parameters?.maxOutputTokens !== undefined) {
451
+ params.max_tokens = input.parameters.maxOutputTokens;
452
+ }
453
+
454
+ // Use JSON mode if requested
455
+ // Note: OpenRouter streaming doesn't support the responses.parse API,
456
+ // so we use response_format with JSON mode instead
457
+ if (input.parameters?.jsonMode) {
458
+ params.response_format = { type: "json_object" };
459
+ }
460
+
461
+ const stream = await this.client.chat.completions.create(params);
462
+
463
+ let accumulated = "";
464
+ let currentModel = model;
465
+ let finishReason: string | undefined;
466
+ let promptTokens: number | undefined;
467
+ let completionTokens: number | undefined;
468
+ let totalTokens: number | undefined;
469
+
470
+ for await (const chunk of stream) {
471
+ currentModel = chunk.model;
472
+ const delta = chunk.choices[0]?.delta?.content || "";
473
+
474
+ if (delta) {
475
+ accumulated += delta;
476
+ yield {
477
+ delta,
478
+ accumulated,
479
+ done: false,
480
+ };
481
+ }
482
+
483
+ if (chunk.choices[0]?.finish_reason) {
484
+ finishReason = chunk.choices[0].finish_reason;
485
+ }
486
+
487
+ // OpenRouter may include usage in the final chunk
488
+ if (chunk.usage) {
489
+ promptTokens = chunk.usage.prompt_tokens;
490
+ completionTokens = chunk.usage.completion_tokens;
491
+ totalTokens = chunk.usage.total_tokens;
492
+ }
493
+ }
494
+
495
+ // Parse JSON response if JSON mode was enabled
496
+ let structured: AgentStructuredResponse | undefined;
497
+ if (input.parameters?.jsonMode && accumulated) {
498
+ try {
499
+ structured = JSON.parse(accumulated) as AgentStructuredResponse;
500
+ } catch (error) {
501
+ console.warn(
502
+ "[OPENROUTER] Failed to parse JSON response in stream:",
503
+ error
504
+ );
505
+ }
506
+ }
507
+
508
+ // Yield final chunk
509
+ yield {
510
+ delta: "",
511
+ accumulated,
512
+ done: true,
513
+ metadata: {
514
+ model: currentModel,
515
+ finishReason,
516
+ tokensUsed: totalTokens,
517
+ promptTokens,
518
+ completionTokens,
519
+ },
520
+ structured,
521
+ };
522
+ }
366
523
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * AI Provider exports
3
+ * Centralized export point for all AI provider implementations
4
+ */
5
+
6
+ export { AnthropicProvider } from "./AnthropicProvider";
7
+ export type { AnthropicProviderOptions } from "./AnthropicProvider";
8
+
9
+ export { GeminiProvider } from "./GeminiProvider";
10
+ export type { GeminiProviderOptions } from "./GeminiProvider";
11
+
12
+ export { OpenAIProvider } from "./OpenAIProvider";
13
+ export type { OpenAIProviderOptions } from "./OpenAIProvider";
14
+
15
+ export { OpenRouterProvider } from "./OpenRouterProvider";
16
+ export type { OpenRouterProviderOptions } from "./OpenRouterProvider";
@@ -5,6 +5,7 @@
5
5
  import type { AiProvider } from "./ai";
6
6
  import type { ToolRef } from "./tool";
7
7
  import type { RouteOptions } from "./route";
8
+ import type { PersistenceConfig } from "./persistence";
8
9
 
9
10
  /**
10
11
  * Composition mode determines how the agent processes and structures responses
@@ -85,6 +86,8 @@ export interface AgentOptions<TContext = unknown> {
85
86
  routes?: RouteOptions[];
86
87
  /** Initial observations for disambiguation */
87
88
  observations?: ObservationOptions[];
89
+ /** Optional persistence configuration for auto-saving sessions and messages */
90
+ persistence?: PersistenceConfig;
88
91
  }
89
92
 
90
93
  /**
package/src/types/ai.ts CHANGED
@@ -94,6 +94,31 @@ export interface GenerateMessageOutput {
94
94
  structured?: AgentStructuredResponse;
95
95
  }
96
96
 
97
+ /**
98
+ * Stream chunk from AI message generation
99
+ */
100
+ export interface GenerateMessageStreamChunk {
101
+ /** The delta/chunk of the message */
102
+ delta: string;
103
+ /** Accumulated message so far */
104
+ accumulated: string;
105
+ /** Whether this is the final chunk */
106
+ done: boolean;
107
+ /** Optional metadata about generation */
108
+ metadata?: {
109
+ /** Model used */
110
+ model?: string;
111
+ /** Tokens consumed */
112
+ tokensUsed?: number;
113
+ /** Finish reason */
114
+ finishReason?: string;
115
+ /** Additional provider-specific data */
116
+ [key: string]: unknown;
117
+ };
118
+ /** Structured response data (only available when done=true and JSON mode is enabled) */
119
+ structured?: AgentStructuredResponse;
120
+ }
121
+
97
122
  /**
98
123
  * AI provider interface (strategy pattern)
99
124
  */
@@ -107,4 +132,11 @@ export interface AiProvider {
107
132
  generateMessage<TContext = unknown>(
108
133
  input: GenerateMessageInput<TContext>
109
134
  ): Promise<GenerateMessageOutput>;
135
+
136
+ /**
137
+ * Generate a message as a stream based on prompt and context
138
+ */
139
+ generateMessageStream<TContext = unknown>(
140
+ input: GenerateMessageInput<TContext>
141
+ ): AsyncGenerator<GenerateMessageStreamChunk>;
110
142
  }
@@ -54,3 +54,17 @@ export { SectionStatus } from "./prompt";
54
54
 
55
55
  // Observation types
56
56
  export type { Observation, ObservationOptions } from "./observation";
57
+
58
+ // Persistence types
59
+ export type {
60
+ SessionData,
61
+ MessageData,
62
+ SessionStatus,
63
+ MessageRole,
64
+ SessionRepository,
65
+ MessageRepository,
66
+ PersistenceAdapter,
67
+ PersistenceConfig,
68
+ CreateSessionOptions,
69
+ SaveMessageOptions,
70
+ } from "./persistence";
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Persistence-related type definitions
3
+ * Support for optional database persistence (Prisma, etc.)
4
+ */
5
+
6
+ import type { Event } from "./history";
7
+
8
+ /**
9
+ * Session status enum
10
+ */
11
+ export type SessionStatus = "active" | "completed" | "abandoned";
12
+
13
+ /**
14
+ * Message role enum
15
+ */
16
+ export type MessageRole = "user" | "agent" | "system";
17
+
18
+ /**
19
+ * Base session data structure
20
+ */
21
+ export interface SessionData {
22
+ id: string;
23
+ userId?: string;
24
+ agentName?: string;
25
+ status: SessionStatus;
26
+ currentRoute?: string;
27
+ currentState?: string;
28
+ collectedData?: Record<string, unknown>;
29
+ messageCount?: number;
30
+ lastMessageAt?: Date;
31
+ completedAt?: Date;
32
+ createdAt: Date;
33
+ updatedAt: Date;
34
+ }
35
+
36
+ /**
37
+ * Base message data structure
38
+ */
39
+ export interface MessageData {
40
+ id: string;
41
+ sessionId: string;
42
+ userId?: string;
43
+ role: MessageRole;
44
+ content: string;
45
+ route?: string;
46
+ state?: string;
47
+ toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
48
+ event?: Event; // Optional: store full event data
49
+ createdAt: Date;
50
+ }
51
+
52
+ /**
53
+ * Repository interface for sessions
54
+ * Implement this interface with your database of choice
55
+ */
56
+ export interface SessionRepository {
57
+ /**
58
+ * Create a new session
59
+ */
60
+ create(
61
+ data: Omit<SessionData, "id" | "createdAt" | "updatedAt">
62
+ ): Promise<SessionData>;
63
+
64
+ /**
65
+ * Find session by ID
66
+ */
67
+ findById(id: string): Promise<SessionData | null>;
68
+
69
+ /**
70
+ * Find active session by user ID
71
+ */
72
+ findActiveByUserId(userId: string): Promise<SessionData | null>;
73
+
74
+ /**
75
+ * Find all sessions for a user
76
+ */
77
+ findByUserId(userId: string, limit?: number): Promise<SessionData[]>;
78
+
79
+ /**
80
+ * Update session
81
+ */
82
+ update(
83
+ id: string,
84
+ data: Partial<Omit<SessionData, "id" | "createdAt">>
85
+ ): Promise<SessionData | null>;
86
+
87
+ /**
88
+ * Update session status
89
+ */
90
+ updateStatus(
91
+ id: string,
92
+ status: SessionStatus,
93
+ completedAt?: Date
94
+ ): Promise<SessionData | null>;
95
+
96
+ /**
97
+ * Update collected data
98
+ */
99
+ updateCollectedData(
100
+ id: string,
101
+ collectedData: Record<string, unknown>
102
+ ): Promise<SessionData | null>;
103
+
104
+ /**
105
+ * Update current route and state
106
+ */
107
+ updateRouteState(
108
+ id: string,
109
+ route?: string,
110
+ state?: string
111
+ ): Promise<SessionData | null>;
112
+
113
+ /**
114
+ * Increment message count
115
+ */
116
+ incrementMessageCount(id: string): Promise<SessionData | null>;
117
+
118
+ /**
119
+ * Delete session
120
+ */
121
+ delete(id: string): Promise<boolean>;
122
+ }
123
+
124
+ /**
125
+ * Repository interface for messages
126
+ * Implement this interface with your database of choice
127
+ */
128
+ export interface MessageRepository {
129
+ /**
130
+ * Create a new message
131
+ */
132
+ create(data: Omit<MessageData, "id" | "createdAt">): Promise<MessageData>;
133
+
134
+ /**
135
+ * Find message by ID
136
+ */
137
+ findById(id: string): Promise<MessageData | null>;
138
+
139
+ /**
140
+ * Find all messages for a session
141
+ */
142
+ findBySessionId(sessionId: string, limit?: number): Promise<MessageData[]>;
143
+
144
+ /**
145
+ * Find messages for a user
146
+ */
147
+ findByUserId(userId: string, limit?: number): Promise<MessageData[]>;
148
+
149
+ /**
150
+ * Delete message by ID
151
+ */
152
+ delete(id: string): Promise<boolean>;
153
+
154
+ /**
155
+ * Delete all messages for a session
156
+ */
157
+ deleteBySessionId(sessionId: string): Promise<number>;
158
+
159
+ /**
160
+ * Delete all messages for a user
161
+ */
162
+ deleteByUserId(userId: string): Promise<number>;
163
+ }
164
+
165
+ /**
166
+ * Persistence adapter interface
167
+ * Implement this to create adapters for different databases
168
+ */
169
+ export interface PersistenceAdapter {
170
+ /**
171
+ * Session repository
172
+ */
173
+ readonly sessionRepository: SessionRepository;
174
+
175
+ /**
176
+ * Message repository
177
+ */
178
+ readonly messageRepository: MessageRepository;
179
+
180
+ /**
181
+ * Initialize the adapter (create tables, indexes, etc.)
182
+ * Called automatically when adapter is created
183
+ */
184
+ initialize?(): Promise<void>;
185
+
186
+ /**
187
+ * Disconnect/cleanup resources
188
+ */
189
+ disconnect?(): Promise<void>;
190
+ }
191
+
192
+ /**
193
+ * Configuration for persistence
194
+ */
195
+ export interface PersistenceConfig {
196
+ /**
197
+ * Persistence adapter instance (e.g., PrismaAdapter)
198
+ */
199
+ adapter: PersistenceAdapter;
200
+
201
+ /**
202
+ * Whether to auto-save messages (default: true)
203
+ */
204
+ autoSave?: boolean;
205
+
206
+ /**
207
+ * User ID to associate with sessions/messages
208
+ * Can also be provided per-call in methods
209
+ */
210
+ userId?: string;
211
+ }
212
+
213
+ /**
214
+ * Options for creating a session
215
+ */
216
+ export interface CreateSessionOptions {
217
+ userId?: string;
218
+ agentName?: string;
219
+ initialData?: Record<string, unknown>;
220
+ }
221
+
222
+ /**
223
+ * Options for saving a message
224
+ */
225
+ export interface SaveMessageOptions {
226
+ sessionId: string;
227
+ userId?: string;
228
+ role: MessageRole;
229
+ content: string;
230
+ route?: string;
231
+ state?: string;
232
+ toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
233
+ event?: Event;
234
+ }