@voltagent/libsql 0.1.0

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.
@@ -0,0 +1,519 @@
1
+ import { WorkflowHistoryEntry, WorkflowStepHistoryEntry, WorkflowTimelineEvent, WorkflowStats, MemoryOptions, Memory, MessageFilterOptions, MemoryMessage, NewTimelineEvent, CreateConversationInput, Conversation, ConversationQueryOptions } from '@voltagent/core';
2
+ import { Logger } from '@voltagent/logger';
3
+ import { Client } from '@libsql/client';
4
+
5
+ /**
6
+ * LibSQL extension for workflow memory operations
7
+ * This class provides workflow-specific storage operations for LibSQL
8
+ */
9
+ declare class LibSQLWorkflowExtension {
10
+ private client;
11
+ private _tablePrefix;
12
+ private logger;
13
+ constructor(client: Client, _tablePrefix?: string, logger?: Logger);
14
+ /**
15
+ * Store a workflow history entry
16
+ */
17
+ storeWorkflowHistory(entry: WorkflowHistoryEntry): Promise<void>;
18
+ /**
19
+ * Get a workflow history entry by ID
20
+ */
21
+ getWorkflowHistory(id: string): Promise<WorkflowHistoryEntry | null>;
22
+ /**
23
+ * Get all workflow history entries for a specific workflow
24
+ */
25
+ getWorkflowHistoryByWorkflowId(workflowId: string): Promise<WorkflowHistoryEntry[]>;
26
+ /**
27
+ * Update a workflow history entry
28
+ */
29
+ updateWorkflowHistory(id: string, updates: Partial<WorkflowHistoryEntry>): Promise<void>;
30
+ /**
31
+ * Delete a workflow history entry
32
+ */
33
+ deleteWorkflowHistory(id: string): Promise<void>;
34
+ /**
35
+ * Store a workflow step entry
36
+ */
37
+ storeWorkflowStep(step: WorkflowStepHistoryEntry): Promise<void>;
38
+ /**
39
+ * Get a workflow step by ID
40
+ */
41
+ getWorkflowStep(id: string): Promise<WorkflowStepHistoryEntry | null>;
42
+ /**
43
+ * Get all workflow steps for a specific workflow history
44
+ */
45
+ getWorkflowSteps(workflowHistoryId: string): Promise<WorkflowStepHistoryEntry[]>;
46
+ /**
47
+ * Update a workflow step
48
+ */
49
+ updateWorkflowStep(id: string, updates: Partial<WorkflowStepHistoryEntry>): Promise<void>;
50
+ /**
51
+ * Delete a workflow step
52
+ */
53
+ deleteWorkflowStep(id: string): Promise<void>;
54
+ /**
55
+ * Store a workflow timeline event
56
+ */
57
+ storeWorkflowTimelineEvent(event: WorkflowTimelineEvent): Promise<void>;
58
+ /**
59
+ * Get a workflow timeline event by ID
60
+ */
61
+ getWorkflowTimelineEvent(id: string): Promise<WorkflowTimelineEvent | null>;
62
+ /**
63
+ * Get all workflow timeline events for a specific workflow history
64
+ */
65
+ getWorkflowTimelineEvents(workflowHistoryId: string): Promise<WorkflowTimelineEvent[]>;
66
+ /**
67
+ * Delete a workflow timeline event
68
+ */
69
+ deleteWorkflowTimelineEvent(id: string): Promise<void>;
70
+ /**
71
+ * Get all workflow IDs
72
+ */
73
+ getAllWorkflowIds(): Promise<string[]>;
74
+ /**
75
+ * Get workflow statistics
76
+ */
77
+ getWorkflowStats(workflowId: string): Promise<WorkflowStats>;
78
+ /**
79
+ * Get workflow history with all related data (steps and events)
80
+ */
81
+ getWorkflowHistoryWithStepsAndEvents(id: string): Promise<WorkflowHistoryEntry | null>;
82
+ /**
83
+ * Delete workflow history and all related data
84
+ */
85
+ deleteWorkflowHistoryWithRelated(id: string): Promise<void>;
86
+ /**
87
+ * Clean up old workflow histories
88
+ */
89
+ cleanupOldWorkflowHistories(workflowId: string, maxEntries: number): Promise<number>;
90
+ /**
91
+ * Parse workflow history row from database
92
+ */
93
+ private parseWorkflowHistoryRow;
94
+ /**
95
+ * Parse workflow step row from database
96
+ */
97
+ private parseWorkflowStepRow;
98
+ /**
99
+ * Parse workflow timeline event row from database
100
+ */
101
+ private parseWorkflowTimelineEventRow;
102
+ }
103
+
104
+ /**
105
+ * Options for configuring the LibSQLStorage
106
+ */
107
+ interface LibSQLStorageOptions extends MemoryOptions {
108
+ /**
109
+ * LibSQL connection URL
110
+ * Can be either a remote Turso URL or a local file path
111
+ * @default "file:./.voltagent/memory.db"
112
+ * @example "libsql://your-database.turso.io" for remote Turso
113
+ * @example "file:memory.db" for local SQLite in current directory
114
+ * @example "file:.voltagent/memory.db" for local SQLite in .voltagent folder
115
+ */
116
+ url?: string;
117
+ /**
118
+ * Auth token for LibSQL/Turso
119
+ * Not needed for local SQLite
120
+ */
121
+ authToken?: string;
122
+ /**
123
+ * Prefix for table names
124
+ * @default "voltagent_memory"
125
+ */
126
+ tablePrefix?: string;
127
+ /**
128
+ * Whether to enable debug logging
129
+ * @default false
130
+ */
131
+ debug?: boolean;
132
+ /**
133
+ * Storage limit for the LibSQLStorage
134
+ * @default 100
135
+ */
136
+ storageLimit?: number;
137
+ /**
138
+ * Number of retry attempts for database operations when encountering busy/locked errors
139
+ * @default 3
140
+ */
141
+ retryAttempts?: number;
142
+ /**
143
+ * Base delay in milliseconds before retrying a failed operation
144
+ * Uses a jittered exponential backoff strategy for better load distribution
145
+ * @default 50
146
+ */
147
+ baseDelayMs?: number;
148
+ /**
149
+ * Optional logger instance
150
+ */
151
+ logger?: Logger;
152
+ }
153
+ declare class LibSQLStorage implements Memory {
154
+ private client;
155
+ private options;
156
+ private initialized;
157
+ private workflowExtension;
158
+ private logger;
159
+ private retryAttempts;
160
+ private baseDelayMs;
161
+ /**
162
+ * Create a new LibSQL storage
163
+ * @param options Configuration options
164
+ */
165
+ constructor(options: LibSQLStorageOptions);
166
+ /**
167
+ * Log a debug message if debug is enabled
168
+ * @param message Message to log
169
+ * @param data Additional data to log
170
+ */
171
+ private debug;
172
+ /**
173
+ * Calculate delay with jitter for better load distribution
174
+ * @param attempt Current retry attempt number
175
+ * @returns Delay in milliseconds
176
+ */
177
+ private calculateRetryDelay;
178
+ /**
179
+ * Execute a database operation with retry strategy
180
+ * Implements jittered exponential backoff
181
+ * @param operationFn The operation function to execute
182
+ * @param operationName Operation name for logging
183
+ * @returns The result of the operation
184
+ */
185
+ private executeWithRetryStrategy;
186
+ /**
187
+ * Initialize workflow tables
188
+ */
189
+ private initializeWorkflowTables;
190
+ /**
191
+ * Initialize the database tables
192
+ * @returns Promise that resolves when initialization is complete
193
+ */
194
+ private initializeDatabase;
195
+ /**
196
+ * Generate a unique ID for a message
197
+ * @returns Unique ID
198
+ */
199
+ private generateId;
200
+ /**
201
+ * Get messages with filtering options
202
+ * @param options Filtering options
203
+ * @returns Filtered messages
204
+ */
205
+ getMessages(options?: MessageFilterOptions): Promise<MemoryMessage[]>;
206
+ /**
207
+ * Add a message to the conversation history
208
+ * @param message Message to add
209
+ * @param userId User identifier (optional, defaults to "default")
210
+ * @param conversationId Conversation identifier (optional, defaults to "default")
211
+ */
212
+ addMessage(message: MemoryMessage, conversationId?: string): Promise<void>;
213
+ /**
214
+ * Prune old messages to respect storage limit
215
+ * @param conversationId Conversation ID to prune messages for
216
+ */
217
+ private pruneOldMessages;
218
+ /**
219
+ * Clear messages from memory
220
+ */
221
+ clearMessages(options: {
222
+ userId: string;
223
+ conversationId?: string;
224
+ }): Promise<void>;
225
+ /**
226
+ * Close the database connection
227
+ */
228
+ close(): Promise<void>;
229
+ /**
230
+ * Add or update a history entry
231
+ * @param key Entry ID
232
+ * @param value Entry data
233
+ * @param agentId Agent ID for filtering
234
+ */
235
+ addHistoryEntry(key: string, value: any, agentId: string): Promise<void>;
236
+ /**
237
+ * Update an existing history entry
238
+ * @param key Entry ID
239
+ * @param value Updated entry data
240
+ * @param agentId Agent ID for filtering
241
+ */
242
+ updateHistoryEntry(key: string, value: any, agentId: string): Promise<void>;
243
+ /**
244
+ * Add a history step
245
+ * @param key Step ID
246
+ * @param value Step data
247
+ * @param historyId Related history entry ID
248
+ * @param agentId Agent ID for filtering
249
+ */
250
+ addHistoryStep(key: string, value: any, historyId: string, agentId: string): Promise<void>;
251
+ /**
252
+ * Update a history step
253
+ * @param key Step ID
254
+ * @param value Updated step data
255
+ * @param historyId Related history entry ID
256
+ * @param agentId Agent ID for filtering
257
+ */
258
+ updateHistoryStep(key: string, value: any, historyId: string, agentId: string): Promise<void>;
259
+ /**
260
+ * Add a timeline event
261
+ * @param key Event ID (UUID)
262
+ * @param value Timeline event data
263
+ * @param historyId Related history entry ID
264
+ * @param agentId Agent ID for filtering
265
+ */
266
+ addTimelineEvent(key: string, value: NewTimelineEvent, historyId: string, agentId: string): Promise<void>;
267
+ /**
268
+ * Get a history entry by ID
269
+ * @param key Entry ID
270
+ * @returns The history entry or undefined if not found
271
+ */
272
+ getHistoryEntry(key: string): Promise<any | undefined>;
273
+ /**
274
+ * Get a history step by ID
275
+ * @param key Step ID
276
+ * @returns The history step or undefined if not found
277
+ */
278
+ getHistoryStep(key: string): Promise<any | undefined>;
279
+ createConversation(conversation: CreateConversationInput): Promise<Conversation>;
280
+ getConversation(id: string): Promise<Conversation | null>;
281
+ getConversations(resourceId: string): Promise<Conversation[]>;
282
+ getConversationsByUserId(userId: string, options?: Omit<ConversationQueryOptions, "userId">): Promise<Conversation[]>;
283
+ /**
284
+ * Query conversations with filtering and pagination options
285
+ *
286
+ * @param options Query options for filtering and pagination
287
+ * @returns Promise that resolves to an array of conversations matching the criteria
288
+ * @see {@link https://voltagent.dev/docs/agents/memory/libsql#querying-conversations | Querying Conversations}
289
+ */
290
+ queryConversations(options: ConversationQueryOptions): Promise<Conversation[]>;
291
+ /**
292
+ * Get messages for a specific conversation with pagination support
293
+ *
294
+ * @param conversationId The unique identifier of the conversation to retrieve messages from
295
+ * @param options Optional pagination and filtering options
296
+ * @returns Promise that resolves to an array of messages in chronological order (oldest first)
297
+ * @see {@link https://voltagent.dev/docs/agents/memory/libsql#conversation-messages | Getting Conversation Messages}
298
+ */
299
+ getConversationMessages(conversationId: string, options?: {
300
+ limit?: number;
301
+ offset?: number;
302
+ }): Promise<MemoryMessage[]>;
303
+ updateConversation(id: string, updates: Partial<Omit<Conversation, "id" | "createdAt" | "updatedAt">>): Promise<Conversation>;
304
+ deleteConversation(id: string): Promise<void>;
305
+ /**
306
+ * Get all history entries for an agent with pagination
307
+ * @param agentId Agent ID
308
+ * @param page Page number (0-based)
309
+ * @param limit Number of entries per page
310
+ * @returns Object with entries array and total count
311
+ */
312
+ getAllHistoryEntriesByAgent(agentId: string, page: number, limit: number): Promise<{
313
+ entries: any[];
314
+ total: number;
315
+ }>;
316
+ /**
317
+ * Migrates agent history data from old structure to new structure.
318
+ * If migration fails, it can be rolled back using the backup mechanism.
319
+ *
320
+ * Old database structure:
321
+ * CREATE TABLE voltagent_memory_agent_history (
322
+ * key TEXT PRIMARY KEY,
323
+ * value TEXT NOT NULL,
324
+ * agent_id TEXT
325
+ * );
326
+ */
327
+ migrateAgentHistoryData(options?: {
328
+ createBackup?: boolean;
329
+ restoreFromBackup?: boolean;
330
+ deleteBackupAfterSuccess?: boolean;
331
+ }): Promise<{
332
+ success: boolean;
333
+ migratedCount?: number;
334
+ error?: Error;
335
+ backupCreated?: boolean;
336
+ }>;
337
+ /**
338
+ * Migrate conversation schema to add user_id and update messages table
339
+ *
340
+ * ⚠️ **CRITICAL WARNING: DESTRUCTIVE OPERATION** ⚠️
341
+ *
342
+ * This method performs a DESTRUCTIVE schema migration that:
343
+ * - DROPS and recreates existing tables
344
+ * - Creates temporary tables during migration
345
+ * - Modifies the primary key structure of the messages table
346
+ * - Can cause DATA LOSS if interrupted or if errors occur
347
+ *
348
+ * **IMPORTANT SAFETY REQUIREMENTS:**
349
+ * - 🛑 STOP all application instances before running this migration
350
+ * - 🛑 Ensure NO concurrent database operations are running
351
+ * - 🛑 Take a full database backup before running (independent of built-in backup)
352
+ * - 🛑 Test the migration on a copy of production data first
353
+ * - 🛑 Plan for downtime during migration execution
354
+ *
355
+ * **What this migration does:**
356
+ * 1. Creates backup tables (if createBackup=true)
357
+ * 2. Creates temporary tables with new schema
358
+ * 3. Migrates data from old tables to new schema
359
+ * 4. DROPS original tables
360
+ * 5. Renames temporary tables to original names
361
+ * 6. All operations are wrapped in a transaction for atomicity
362
+ *
363
+ * @param options Migration configuration options
364
+ * @param options.createBackup Whether to create backup tables before migration (default: true, HIGHLY RECOMMENDED)
365
+ * @param options.restoreFromBackup Whether to restore from existing backup instead of migrating (default: false)
366
+ * @param options.deleteBackupAfterSuccess Whether to delete backup tables after successful migration (default: false)
367
+ *
368
+ * @returns Promise resolving to migration result with success status, migrated count, and backup info
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * // RECOMMENDED: Run with backup creation (default)
373
+ * const result = await storage.migrateConversationSchema({
374
+ * createBackup: true,
375
+ * deleteBackupAfterSuccess: false // Keep backup for safety
376
+ * });
377
+ *
378
+ * if (result.success) {
379
+ * console.log(`Migrated ${result.migratedCount} conversations successfully`);
380
+ * } else {
381
+ * console.error('Migration failed:', result.error);
382
+ * // Consider restoring from backup
383
+ * }
384
+ *
385
+ * // If migration fails, restore from backup:
386
+ * const restoreResult = await storage.migrateConversationSchema({
387
+ * restoreFromBackup: true
388
+ * });
389
+ * ```
390
+ *
391
+ * @throws {Error} If migration fails and transaction is rolled back
392
+ *
393
+ * @since This migration is typically only needed when upgrading from older schema versions
394
+ */
395
+ private migrateConversationSchema;
396
+ /**
397
+ * Get conversations for a user with a fluent query builder interface
398
+ * @param userId User ID to filter by
399
+ * @returns Query builder object
400
+ */
401
+ getUserConversations(userId: string): {
402
+ /**
403
+ * Limit the number of results
404
+ * @param count Number of conversations to return
405
+ * @returns Query builder
406
+ */
407
+ limit: (count: number) => {
408
+ /**
409
+ * Order results by a specific field
410
+ * @param field Field to order by
411
+ * @param direction Sort direction
412
+ * @returns Query builder
413
+ */
414
+ orderBy: (field?: "created_at" | "updated_at" | "title", direction?: "ASC" | "DESC") => {
415
+ /**
416
+ * Execute the query and return results
417
+ * @returns Promise of conversations
418
+ */
419
+ execute: () => Promise<Conversation[]>;
420
+ };
421
+ /**
422
+ * Execute the query with default ordering
423
+ * @returns Promise of conversations
424
+ */
425
+ execute: () => Promise<Conversation[]>;
426
+ };
427
+ /**
428
+ * Order results by a specific field
429
+ * @param field Field to order by
430
+ * @param direction Sort direction
431
+ * @returns Query builder
432
+ */
433
+ orderBy: (field?: "created_at" | "updated_at" | "title", direction?: "ASC" | "DESC") => {
434
+ /**
435
+ * Limit the number of results
436
+ * @param count Number of conversations to return
437
+ * @returns Query builder
438
+ */
439
+ limit: (count: number) => {
440
+ /**
441
+ * Execute the query and return results
442
+ * @returns Promise of conversations
443
+ */
444
+ execute: () => Promise<Conversation[]>;
445
+ };
446
+ /**
447
+ * Execute the query without limit
448
+ * @returns Promise of conversations
449
+ */
450
+ execute: () => Promise<Conversation[]>;
451
+ };
452
+ /**
453
+ * Execute the query with default options
454
+ * @returns Promise of conversations
455
+ */
456
+ execute: () => Promise<Conversation[]>;
457
+ };
458
+ /**
459
+ * Get conversation by ID and ensure it belongs to the specified user
460
+ * @param conversationId Conversation ID
461
+ * @param userId User ID to validate ownership
462
+ * @returns Conversation or null
463
+ */
464
+ getUserConversation(conversationId: string, userId: string): Promise<Conversation | null>;
465
+ /**
466
+ * Get paginated conversations for a user
467
+ * @param userId User ID
468
+ * @param page Page number (1-based)
469
+ * @param pageSize Number of items per page
470
+ * @returns Object with conversations and pagination info
471
+ */
472
+ getPaginatedUserConversations(userId: string, page?: number, pageSize?: number): Promise<{
473
+ conversations: Conversation[];
474
+ page: number;
475
+ pageSize: number;
476
+ hasMore: boolean;
477
+ }>;
478
+ /**
479
+ * Check and create migration flag table, return if migration already completed
480
+ * @param migrationType Type of migration to check
481
+ * @returns Object with completion status and details
482
+ */
483
+ private checkMigrationFlag;
484
+ /**
485
+ * Set migration flag after successful completion
486
+ * @param migrationType Type of migration completed
487
+ * @param migratedCount Number of records migrated
488
+ */
489
+ private setMigrationFlag;
490
+ /**
491
+ * Migrate agent history schema to add userId and conversationId columns
492
+ */
493
+ private migrateAgentHistorySchema;
494
+ storeWorkflowHistory(entry: any): Promise<void>;
495
+ getWorkflowHistory(id: string): Promise<any>;
496
+ getWorkflowHistoryByWorkflowId(workflowId: string): Promise<any[]>;
497
+ updateWorkflowHistory(id: string, updates: any): Promise<void>;
498
+ deleteWorkflowHistory(id: string): Promise<void>;
499
+ storeWorkflowStep(step: any): Promise<void>;
500
+ getWorkflowStep(id: string): Promise<any>;
501
+ getWorkflowSteps(workflowHistoryId: string): Promise<any[]>;
502
+ updateWorkflowStep(id: string, updates: any): Promise<void>;
503
+ deleteWorkflowStep(id: string): Promise<void>;
504
+ storeWorkflowTimelineEvent(event: any): Promise<void>;
505
+ getWorkflowTimelineEvent(id: string): Promise<any>;
506
+ getWorkflowTimelineEvents(workflowHistoryId: string): Promise<any[]>;
507
+ deleteWorkflowTimelineEvent(id: string): Promise<void>;
508
+ getAllWorkflowIds(): Promise<string[]>;
509
+ getWorkflowStats(workflowId: string): Promise<any>;
510
+ getWorkflowHistoryWithStepsAndEvents(id: string): Promise<any>;
511
+ deleteWorkflowHistoryWithRelated(id: string): Promise<void>;
512
+ cleanupOldWorkflowHistories(workflowId: string, maxEntries: number): Promise<number>;
513
+ /**
514
+ * Get the workflow extension for advanced workflow operations
515
+ */
516
+ getWorkflowExtension(): LibSQLWorkflowExtension;
517
+ }
518
+
519
+ export { LibSQLStorage, type LibSQLStorageOptions };