@mastra/lance 0.0.0-message-list-update-20250715150321 → 0.0.0-model-router-unknown-provider-20251017212006
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.
- package/CHANGELOG.md +501 -18
- package/README.md +3 -3
- package/dist/index.cjs +1995 -849
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1996 -850
- package/dist/index.js.map +1 -0
- package/dist/storage/domains/legacy-evals/index.d.ts +25 -0
- package/dist/storage/domains/legacy-evals/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +103 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +40 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +50 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/traces/index.d.ts +34 -0
- package/dist/storage/domains/traces/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +10 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +57 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +272 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/vector/filter.d.ts +41 -0
- package/dist/vector/filter.d.ts.map +1 -0
- package/dist/vector/index.d.ts +85 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/types.d.ts +15 -0
- package/dist/vector/types.d.ts.map +1 -0
- package/package.json +24 -10
- package/dist/_tsup-dts-rollup.d.cts +0 -409
- package/dist/_tsup-dts-rollup.d.ts +0 -409
- package/dist/index.d.cts +0 -2
- package/eslint.config.js +0 -6
- package/src/index.ts +0 -2
- package/src/storage/index.test.ts +0 -1336
- package/src/storage/index.ts +0 -1447
- package/src/vector/filter.test.ts +0 -295
- package/src/vector/filter.ts +0 -443
- package/src/vector/index.test.ts +0 -1493
- package/src/vector/index.ts +0 -941
- package/src/vector/types.ts +0 -16
- package/tsconfig.json +0 -5
- package/vitest.config.ts +0 -11
package/src/storage/index.ts
DELETED
|
@@ -1,1447 +0,0 @@
|
|
|
1
|
-
import { connect } from '@lancedb/lancedb';
|
|
2
|
-
import type { Connection, ConnectionOptions, SchemaLike, FieldLike } from '@lancedb/lancedb';
|
|
3
|
-
import type { MastraMessageContentV2 } from '@mastra/core/agent';
|
|
4
|
-
import { MessageList } from '@mastra/core/agent';
|
|
5
|
-
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
6
|
-
import type { MastraMessageV1, MastraMessageV2, StorageThreadType, TraceType } from '@mastra/core/memory';
|
|
7
|
-
import {
|
|
8
|
-
MastraStorage,
|
|
9
|
-
TABLE_EVALS,
|
|
10
|
-
TABLE_MESSAGES,
|
|
11
|
-
TABLE_THREADS,
|
|
12
|
-
TABLE_TRACES,
|
|
13
|
-
TABLE_WORKFLOW_SNAPSHOT,
|
|
14
|
-
} from '@mastra/core/storage';
|
|
15
|
-
import type {
|
|
16
|
-
TABLE_NAMES,
|
|
17
|
-
PaginationInfo,
|
|
18
|
-
StorageGetMessagesArg,
|
|
19
|
-
StorageGetTracesArg,
|
|
20
|
-
StorageColumn,
|
|
21
|
-
EvalRow,
|
|
22
|
-
WorkflowRun,
|
|
23
|
-
WorkflowRuns,
|
|
24
|
-
} from '@mastra/core/storage';
|
|
25
|
-
import type { Trace } from '@mastra/core/telemetry';
|
|
26
|
-
import type { WorkflowRunState } from '@mastra/core/workflows';
|
|
27
|
-
import type { DataType } from 'apache-arrow';
|
|
28
|
-
import { Utf8, Int32, Float32, Binary, Schema, Field, Float64 } from 'apache-arrow';
|
|
29
|
-
|
|
30
|
-
export class LanceStorage extends MastraStorage {
|
|
31
|
-
private lanceClient!: Connection;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Creates a new instance of LanceStorage
|
|
35
|
-
* @param uri The URI to connect to LanceDB
|
|
36
|
-
* @param options connection options
|
|
37
|
-
*
|
|
38
|
-
* Usage:
|
|
39
|
-
*
|
|
40
|
-
* Connect to a local database
|
|
41
|
-
* ```ts
|
|
42
|
-
* const store = await LanceStorage.create('/path/to/db');
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* Connect to a LanceDB cloud database
|
|
46
|
-
* ```ts
|
|
47
|
-
* const store = await LanceStorage.create('db://host:port');
|
|
48
|
-
* ```
|
|
49
|
-
*
|
|
50
|
-
* Connect to a cloud database
|
|
51
|
-
* ```ts
|
|
52
|
-
* const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
public static async create(name: string, uri: string, options?: ConnectionOptions): Promise<LanceStorage> {
|
|
56
|
-
const instance = new LanceStorage(name);
|
|
57
|
-
try {
|
|
58
|
-
instance.lanceClient = await connect(uri, options);
|
|
59
|
-
return instance;
|
|
60
|
-
} catch (e: any) {
|
|
61
|
-
throw new MastraError(
|
|
62
|
-
{
|
|
63
|
-
id: 'STORAGE_LANCE_STORAGE_CONNECT_FAILED',
|
|
64
|
-
domain: ErrorDomain.STORAGE,
|
|
65
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
66
|
-
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
67
|
-
details: { uri, optionsProvided: !!options },
|
|
68
|
-
},
|
|
69
|
-
e,
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
private getPrimaryKeys(tableName: TABLE_NAMES): string[] {
|
|
75
|
-
let primaryId: string[] = ['id'];
|
|
76
|
-
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
77
|
-
primaryId = ['workflow_name', 'run_id'];
|
|
78
|
-
} else if (tableName === TABLE_EVALS) {
|
|
79
|
-
primaryId = ['agent_name', 'metric_name', 'run_id'];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return primaryId;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* @internal
|
|
87
|
-
* Private constructor to enforce using the create factory method
|
|
88
|
-
*/
|
|
89
|
-
private constructor(name: string) {
|
|
90
|
-
super({ name });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async createTable({
|
|
94
|
-
tableName,
|
|
95
|
-
schema,
|
|
96
|
-
}: {
|
|
97
|
-
tableName: TABLE_NAMES;
|
|
98
|
-
schema: Record<string, StorageColumn>;
|
|
99
|
-
}): Promise<void> {
|
|
100
|
-
try {
|
|
101
|
-
if (!this.lanceClient) {
|
|
102
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
103
|
-
}
|
|
104
|
-
if (!tableName) {
|
|
105
|
-
throw new Error('tableName is required for createTable.');
|
|
106
|
-
}
|
|
107
|
-
if (!schema) {
|
|
108
|
-
throw new Error('schema is required for createTable.');
|
|
109
|
-
}
|
|
110
|
-
} catch (error) {
|
|
111
|
-
throw new MastraError(
|
|
112
|
-
{
|
|
113
|
-
id: 'STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS',
|
|
114
|
-
domain: ErrorDomain.STORAGE,
|
|
115
|
-
category: ErrorCategory.USER,
|
|
116
|
-
details: { tableName },
|
|
117
|
-
},
|
|
118
|
-
error,
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
const arrowSchema = this.translateSchema(schema);
|
|
124
|
-
await this.lanceClient.createEmptyTable(tableName, arrowSchema);
|
|
125
|
-
} catch (error: any) {
|
|
126
|
-
throw new MastraError(
|
|
127
|
-
{
|
|
128
|
-
id: 'STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED',
|
|
129
|
-
domain: ErrorDomain.STORAGE,
|
|
130
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
131
|
-
details: { tableName },
|
|
132
|
-
},
|
|
133
|
-
error,
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private translateSchema(schema: Record<string, StorageColumn>): Schema {
|
|
139
|
-
const fields = Object.entries(schema).map(([name, column]) => {
|
|
140
|
-
// Convert string type to Arrow DataType
|
|
141
|
-
let arrowType: DataType;
|
|
142
|
-
switch (column.type.toLowerCase()) {
|
|
143
|
-
case 'text':
|
|
144
|
-
case 'uuid':
|
|
145
|
-
arrowType = new Utf8();
|
|
146
|
-
break;
|
|
147
|
-
case 'int':
|
|
148
|
-
case 'integer':
|
|
149
|
-
arrowType = new Int32();
|
|
150
|
-
break;
|
|
151
|
-
case 'bigint':
|
|
152
|
-
arrowType = new Float64();
|
|
153
|
-
break;
|
|
154
|
-
case 'float':
|
|
155
|
-
arrowType = new Float32();
|
|
156
|
-
break;
|
|
157
|
-
case 'jsonb':
|
|
158
|
-
case 'json':
|
|
159
|
-
arrowType = new Utf8();
|
|
160
|
-
break;
|
|
161
|
-
case 'binary':
|
|
162
|
-
arrowType = new Binary();
|
|
163
|
-
break;
|
|
164
|
-
case 'timestamp':
|
|
165
|
-
arrowType = new Float64();
|
|
166
|
-
break;
|
|
167
|
-
default:
|
|
168
|
-
// Default to string for unknown types
|
|
169
|
-
arrowType = new Utf8();
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Create a field with the appropriate arrow type
|
|
173
|
-
return new Field(name, arrowType, column.nullable ?? true);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
return new Schema(fields);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Drop a table if it exists
|
|
181
|
-
* @param tableName Name of the table to drop
|
|
182
|
-
*/
|
|
183
|
-
async dropTable(tableName: TABLE_NAMES): Promise<void> {
|
|
184
|
-
try {
|
|
185
|
-
if (!this.lanceClient) {
|
|
186
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
187
|
-
}
|
|
188
|
-
if (!tableName) {
|
|
189
|
-
throw new Error('tableName is required for dropTable.');
|
|
190
|
-
}
|
|
191
|
-
} catch (validationError: any) {
|
|
192
|
-
throw new MastraError(
|
|
193
|
-
{
|
|
194
|
-
id: 'STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS',
|
|
195
|
-
domain: ErrorDomain.STORAGE,
|
|
196
|
-
category: ErrorCategory.USER,
|
|
197
|
-
text: validationError.message,
|
|
198
|
-
details: { tableName },
|
|
199
|
-
},
|
|
200
|
-
validationError,
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
await this.lanceClient.dropTable(tableName);
|
|
206
|
-
} catch (error: any) {
|
|
207
|
-
if (error.toString().includes('was not found') || error.message?.includes('Table not found')) {
|
|
208
|
-
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
throw new MastraError(
|
|
212
|
-
{
|
|
213
|
-
id: 'STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED',
|
|
214
|
-
domain: ErrorDomain.STORAGE,
|
|
215
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
216
|
-
details: { tableName },
|
|
217
|
-
},
|
|
218
|
-
error,
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Get table schema
|
|
225
|
-
* @param tableName Name of the table
|
|
226
|
-
* @returns Table schema
|
|
227
|
-
*/
|
|
228
|
-
async getTableSchema(tableName: TABLE_NAMES): Promise<SchemaLike> {
|
|
229
|
-
try {
|
|
230
|
-
if (!this.lanceClient) {
|
|
231
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
232
|
-
}
|
|
233
|
-
if (!tableName) {
|
|
234
|
-
throw new Error('tableName is required for getTableSchema.');
|
|
235
|
-
}
|
|
236
|
-
} catch (validationError: any) {
|
|
237
|
-
throw new MastraError(
|
|
238
|
-
{
|
|
239
|
-
id: 'STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS',
|
|
240
|
-
domain: ErrorDomain.STORAGE,
|
|
241
|
-
category: ErrorCategory.USER,
|
|
242
|
-
text: validationError.message,
|
|
243
|
-
details: { tableName },
|
|
244
|
-
},
|
|
245
|
-
validationError,
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
251
|
-
const rawSchema = await table.schema();
|
|
252
|
-
const fields = rawSchema.fields as FieldLike[];
|
|
253
|
-
|
|
254
|
-
// Convert schema to SchemaLike format
|
|
255
|
-
return {
|
|
256
|
-
fields,
|
|
257
|
-
metadata: new Map<string, string>(),
|
|
258
|
-
get names() {
|
|
259
|
-
return fields.map((field: FieldLike) => field.name);
|
|
260
|
-
},
|
|
261
|
-
};
|
|
262
|
-
} catch (error: any) {
|
|
263
|
-
throw new MastraError(
|
|
264
|
-
{
|
|
265
|
-
id: 'STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED',
|
|
266
|
-
domain: ErrorDomain.STORAGE,
|
|
267
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
268
|
-
details: { tableName },
|
|
269
|
-
},
|
|
270
|
-
error,
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
protected getDefaultValue(type: StorageColumn['type']): string {
|
|
276
|
-
switch (type) {
|
|
277
|
-
case 'text':
|
|
278
|
-
return "''";
|
|
279
|
-
case 'timestamp':
|
|
280
|
-
return 'CURRENT_TIMESTAMP';
|
|
281
|
-
case 'integer':
|
|
282
|
-
case 'bigint':
|
|
283
|
-
return '0';
|
|
284
|
-
case 'jsonb':
|
|
285
|
-
return "'{}'";
|
|
286
|
-
case 'uuid':
|
|
287
|
-
return "''";
|
|
288
|
-
default:
|
|
289
|
-
return super.getDefaultValue(type);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Alters table schema to add columns if they don't exist
|
|
295
|
-
* @param tableName Name of the table
|
|
296
|
-
* @param schema Schema of the table
|
|
297
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
298
|
-
*/
|
|
299
|
-
async alterTable({
|
|
300
|
-
tableName,
|
|
301
|
-
schema,
|
|
302
|
-
ifNotExists,
|
|
303
|
-
}: {
|
|
304
|
-
tableName: string;
|
|
305
|
-
schema: Record<string, StorageColumn>;
|
|
306
|
-
ifNotExists: string[];
|
|
307
|
-
}): Promise<void> {
|
|
308
|
-
try {
|
|
309
|
-
if (!this.lanceClient) {
|
|
310
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
311
|
-
}
|
|
312
|
-
if (!tableName) {
|
|
313
|
-
throw new Error('tableName is required for alterTable.');
|
|
314
|
-
}
|
|
315
|
-
if (!schema) {
|
|
316
|
-
throw new Error('schema is required for alterTable.');
|
|
317
|
-
}
|
|
318
|
-
if (!ifNotExists || ifNotExists.length === 0) {
|
|
319
|
-
this.logger.debug('No columns specified to add in alterTable, skipping.');
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
} catch (validationError: any) {
|
|
323
|
-
throw new MastraError(
|
|
324
|
-
{
|
|
325
|
-
id: 'STORAGE_LANCE_STORAGE_ALTER_TABLE_INVALID_ARGS',
|
|
326
|
-
domain: ErrorDomain.STORAGE,
|
|
327
|
-
category: ErrorCategory.USER,
|
|
328
|
-
text: validationError.message,
|
|
329
|
-
details: { tableName },
|
|
330
|
-
},
|
|
331
|
-
validationError,
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
try {
|
|
336
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
337
|
-
const currentSchema = await table.schema();
|
|
338
|
-
const existingFields = new Set(currentSchema.fields.map((f: any) => f.name));
|
|
339
|
-
|
|
340
|
-
const typeMap: Record<string, string> = {
|
|
341
|
-
text: 'string',
|
|
342
|
-
integer: 'int',
|
|
343
|
-
bigint: 'bigint',
|
|
344
|
-
timestamp: 'timestamp',
|
|
345
|
-
jsonb: 'string',
|
|
346
|
-
uuid: 'string',
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
// Find columns to add
|
|
350
|
-
const columnsToAdd = ifNotExists
|
|
351
|
-
.filter(col => schema[col] && !existingFields.has(col))
|
|
352
|
-
.map(col => {
|
|
353
|
-
const colDef = schema[col];
|
|
354
|
-
return {
|
|
355
|
-
name: col,
|
|
356
|
-
valueSql: colDef?.nullable
|
|
357
|
-
? `cast(NULL as ${typeMap[colDef.type ?? 'text']})`
|
|
358
|
-
: `cast(${this.getDefaultValue(colDef?.type ?? 'text')} as ${typeMap[colDef?.type ?? 'text']})`,
|
|
359
|
-
};
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
if (columnsToAdd.length > 0) {
|
|
363
|
-
await table.addColumns(columnsToAdd);
|
|
364
|
-
this.logger?.info?.(`Added columns [${columnsToAdd.map(c => c.name).join(', ')}] to table ${tableName}`);
|
|
365
|
-
}
|
|
366
|
-
} catch (error: any) {
|
|
367
|
-
throw new MastraError(
|
|
368
|
-
{
|
|
369
|
-
id: 'STORAGE_LANCE_STORAGE_ALTER_TABLE_FAILED',
|
|
370
|
-
domain: ErrorDomain.STORAGE,
|
|
371
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
372
|
-
details: { tableName },
|
|
373
|
-
},
|
|
374
|
-
error,
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
async clearTable({ tableName }: { tableName: TABLE_NAMES }): Promise<void> {
|
|
380
|
-
try {
|
|
381
|
-
if (!this.lanceClient) {
|
|
382
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
383
|
-
}
|
|
384
|
-
if (!tableName) {
|
|
385
|
-
throw new Error('tableName is required for clearTable.');
|
|
386
|
-
}
|
|
387
|
-
} catch (validationError: any) {
|
|
388
|
-
throw new MastraError(
|
|
389
|
-
{
|
|
390
|
-
id: 'STORAGE_LANCE_STORAGE_CLEAR_TABLE_INVALID_ARGS',
|
|
391
|
-
domain: ErrorDomain.STORAGE,
|
|
392
|
-
category: ErrorCategory.USER,
|
|
393
|
-
text: validationError.message,
|
|
394
|
-
details: { tableName },
|
|
395
|
-
},
|
|
396
|
-
validationError,
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
try {
|
|
401
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
402
|
-
|
|
403
|
-
// delete function always takes a predicate as an argument, so we use '1=1' to delete all records because it is always true.
|
|
404
|
-
await table.delete('1=1');
|
|
405
|
-
} catch (error: any) {
|
|
406
|
-
throw new MastraError(
|
|
407
|
-
{
|
|
408
|
-
id: 'STORAGE_LANCE_STORAGE_CLEAR_TABLE_FAILED',
|
|
409
|
-
domain: ErrorDomain.STORAGE,
|
|
410
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
411
|
-
details: { tableName },
|
|
412
|
-
},
|
|
413
|
-
error,
|
|
414
|
-
);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Insert a single record into a table. This function overwrites the existing record if it exists. Use this function for inserting records into tables with custom schemas.
|
|
420
|
-
* @param tableName The name of the table to insert into.
|
|
421
|
-
* @param record The record to insert.
|
|
422
|
-
*/
|
|
423
|
-
async insert({ tableName, record }: { tableName: string; record: Record<string, any> }): Promise<void> {
|
|
424
|
-
try {
|
|
425
|
-
if (!this.lanceClient) {
|
|
426
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
427
|
-
}
|
|
428
|
-
if (!tableName) {
|
|
429
|
-
throw new Error('tableName is required for insert.');
|
|
430
|
-
}
|
|
431
|
-
if (!record || Object.keys(record).length === 0) {
|
|
432
|
-
throw new Error('record is required and cannot be empty for insert.');
|
|
433
|
-
}
|
|
434
|
-
} catch (validationError: any) {
|
|
435
|
-
throw new MastraError(
|
|
436
|
-
{
|
|
437
|
-
id: 'STORAGE_LANCE_STORAGE_INSERT_INVALID_ARGS',
|
|
438
|
-
domain: ErrorDomain.STORAGE,
|
|
439
|
-
category: ErrorCategory.USER,
|
|
440
|
-
text: validationError.message,
|
|
441
|
-
details: { tableName },
|
|
442
|
-
},
|
|
443
|
-
validationError,
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
try {
|
|
448
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
449
|
-
|
|
450
|
-
const primaryId = this.getPrimaryKeys(tableName as TABLE_NAMES);
|
|
451
|
-
|
|
452
|
-
const processedRecord = { ...record };
|
|
453
|
-
|
|
454
|
-
for (const key in processedRecord) {
|
|
455
|
-
if (
|
|
456
|
-
processedRecord[key] !== null &&
|
|
457
|
-
typeof processedRecord[key] === 'object' &&
|
|
458
|
-
!(processedRecord[key] instanceof Date)
|
|
459
|
-
) {
|
|
460
|
-
this.logger.debug('Converting object to JSON string: ', processedRecord[key]);
|
|
461
|
-
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
466
|
-
} catch (error: any) {
|
|
467
|
-
throw new MastraError(
|
|
468
|
-
{
|
|
469
|
-
id: 'STORAGE_LANCE_STORAGE_INSERT_FAILED',
|
|
470
|
-
domain: ErrorDomain.STORAGE,
|
|
471
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
472
|
-
details: { tableName },
|
|
473
|
-
},
|
|
474
|
-
error,
|
|
475
|
-
);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
/**
|
|
480
|
-
* Insert multiple records into a table. This function overwrites the existing records if they exist. Use this function for inserting records into tables with custom schemas.
|
|
481
|
-
* @param tableName The name of the table to insert into.
|
|
482
|
-
* @param records The records to insert.
|
|
483
|
-
*/
|
|
484
|
-
async batchInsert({ tableName, records }: { tableName: string; records: Record<string, any>[] }): Promise<void> {
|
|
485
|
-
try {
|
|
486
|
-
if (!this.lanceClient) {
|
|
487
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
488
|
-
}
|
|
489
|
-
if (!tableName) {
|
|
490
|
-
throw new Error('tableName is required for batchInsert.');
|
|
491
|
-
}
|
|
492
|
-
if (!records || records.length === 0) {
|
|
493
|
-
throw new Error('records array is required and cannot be empty for batchInsert.');
|
|
494
|
-
}
|
|
495
|
-
} catch (validationError: any) {
|
|
496
|
-
throw new MastraError(
|
|
497
|
-
{
|
|
498
|
-
id: 'STORAGE_LANCE_STORAGE_BATCH_INSERT_INVALID_ARGS',
|
|
499
|
-
domain: ErrorDomain.STORAGE,
|
|
500
|
-
category: ErrorCategory.USER,
|
|
501
|
-
text: validationError.message,
|
|
502
|
-
details: { tableName },
|
|
503
|
-
},
|
|
504
|
-
validationError,
|
|
505
|
-
);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
try {
|
|
509
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
510
|
-
|
|
511
|
-
const primaryId = this.getPrimaryKeys(tableName as TABLE_NAMES);
|
|
512
|
-
|
|
513
|
-
const processedRecords = records.map(record => {
|
|
514
|
-
const processedRecord = { ...record };
|
|
515
|
-
|
|
516
|
-
// Convert values based on schema type
|
|
517
|
-
for (const key in processedRecord) {
|
|
518
|
-
// Skip null/undefined values
|
|
519
|
-
if (processedRecord[key] == null) continue;
|
|
520
|
-
|
|
521
|
-
if (
|
|
522
|
-
processedRecord[key] !== null &&
|
|
523
|
-
typeof processedRecord[key] === 'object' &&
|
|
524
|
-
!(processedRecord[key] instanceof Date)
|
|
525
|
-
) {
|
|
526
|
-
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
return processedRecord;
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
|
|
534
|
-
} catch (error: any) {
|
|
535
|
-
throw new MastraError(
|
|
536
|
-
{
|
|
537
|
-
id: 'STORAGE_LANCE_STORAGE_BATCH_INSERT_FAILED',
|
|
538
|
-
domain: ErrorDomain.STORAGE,
|
|
539
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
540
|
-
details: { tableName },
|
|
541
|
-
},
|
|
542
|
-
error,
|
|
543
|
-
);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Load a record from the database by its key(s)
|
|
549
|
-
* @param tableName The name of the table to query
|
|
550
|
-
* @param keys Record of key-value pairs to use for lookup
|
|
551
|
-
* @throws Error if invalid types are provided for keys
|
|
552
|
-
* @returns The loaded record with proper type conversions, or null if not found
|
|
553
|
-
*/
|
|
554
|
-
async load({ tableName, keys }: { tableName: TABLE_NAMES; keys: Record<string, any> }): Promise<any> {
|
|
555
|
-
try {
|
|
556
|
-
if (!this.lanceClient) {
|
|
557
|
-
throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
|
|
558
|
-
}
|
|
559
|
-
if (!tableName) {
|
|
560
|
-
throw new Error('tableName is required for load.');
|
|
561
|
-
}
|
|
562
|
-
if (!keys || Object.keys(keys).length === 0) {
|
|
563
|
-
throw new Error('keys are required and cannot be empty for load.');
|
|
564
|
-
}
|
|
565
|
-
} catch (validationError: any) {
|
|
566
|
-
throw new MastraError(
|
|
567
|
-
{
|
|
568
|
-
id: 'STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS',
|
|
569
|
-
domain: ErrorDomain.STORAGE,
|
|
570
|
-
category: ErrorCategory.USER,
|
|
571
|
-
text: validationError.message,
|
|
572
|
-
details: { tableName },
|
|
573
|
-
},
|
|
574
|
-
validationError,
|
|
575
|
-
);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
try {
|
|
579
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
580
|
-
const tableSchema = await this.getTableSchema(tableName);
|
|
581
|
-
const query = table.query();
|
|
582
|
-
|
|
583
|
-
// Build filter condition with 'and' between all conditions
|
|
584
|
-
if (Object.keys(keys).length > 0) {
|
|
585
|
-
// Validate key types against schema
|
|
586
|
-
this.validateKeyTypes(keys, tableSchema);
|
|
587
|
-
|
|
588
|
-
const filterConditions = Object.entries(keys)
|
|
589
|
-
.map(([key, value]) => {
|
|
590
|
-
// Check if key is in camelCase and wrap it in backticks if it is
|
|
591
|
-
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
592
|
-
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
593
|
-
|
|
594
|
-
// Handle different types appropriately
|
|
595
|
-
if (typeof value === 'string') {
|
|
596
|
-
return `${quotedKey} = '${value}'`;
|
|
597
|
-
} else if (value === null) {
|
|
598
|
-
return `${quotedKey} IS NULL`;
|
|
599
|
-
} else {
|
|
600
|
-
// For numbers, booleans, etc.
|
|
601
|
-
return `${quotedKey} = ${value}`;
|
|
602
|
-
}
|
|
603
|
-
})
|
|
604
|
-
.join(' AND ');
|
|
605
|
-
|
|
606
|
-
this.logger.debug('where clause generated: ' + filterConditions);
|
|
607
|
-
query.where(filterConditions);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
const result = await query.limit(1).toArray();
|
|
611
|
-
|
|
612
|
-
if (result.length === 0) {
|
|
613
|
-
this.logger.debug('No record found');
|
|
614
|
-
return null;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// Process the result with type conversions
|
|
618
|
-
return this.processResultWithTypeConversion(result[0], tableSchema);
|
|
619
|
-
} catch (error: any) {
|
|
620
|
-
// If it's already a MastraError (e.g. from validateKeyTypes if we change it later), rethrow
|
|
621
|
-
if (error instanceof MastraError) throw error;
|
|
622
|
-
throw new MastraError(
|
|
623
|
-
{
|
|
624
|
-
id: 'STORAGE_LANCE_STORAGE_LOAD_FAILED',
|
|
625
|
-
domain: ErrorDomain.STORAGE,
|
|
626
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
627
|
-
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? '' },
|
|
628
|
-
},
|
|
629
|
-
error,
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Validates that key types match the schema definition
|
|
636
|
-
* @param keys The keys to validate
|
|
637
|
-
* @param tableSchema The table schema to validate against
|
|
638
|
-
* @throws Error if a key has an incompatible type
|
|
639
|
-
*/
|
|
640
|
-
private validateKeyTypes(keys: Record<string, any>, tableSchema: SchemaLike): void {
|
|
641
|
-
// Create a map of field names to their expected types
|
|
642
|
-
const fieldTypes = new Map(
|
|
643
|
-
tableSchema.fields.map((field: any) => [field.name, field.type?.toString().toLowerCase()]),
|
|
644
|
-
);
|
|
645
|
-
|
|
646
|
-
for (const [key, value] of Object.entries(keys)) {
|
|
647
|
-
const fieldType = fieldTypes.get(key);
|
|
648
|
-
|
|
649
|
-
if (!fieldType) {
|
|
650
|
-
throw new Error(`Field '${key}' does not exist in table schema`);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// Type validation
|
|
654
|
-
if (value !== null) {
|
|
655
|
-
if ((fieldType.includes('int') || fieldType.includes('bigint')) && typeof value !== 'number') {
|
|
656
|
-
throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
if (fieldType.includes('utf8') && typeof value !== 'string') {
|
|
660
|
-
throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
if (fieldType.includes('timestamp') && !(value instanceof Date) && typeof value !== 'string') {
|
|
664
|
-
throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
* Process a database result with appropriate type conversions based on the table schema
|
|
672
|
-
* @param rawResult The raw result object from the database
|
|
673
|
-
* @param tableSchema The schema of the table containing type information
|
|
674
|
-
* @returns Processed result with correct data types
|
|
675
|
-
*/
|
|
676
|
-
private processResultWithTypeConversion(
|
|
677
|
-
rawResult: Record<string, any> | Record<string, any>[],
|
|
678
|
-
tableSchema: SchemaLike,
|
|
679
|
-
): Record<string, any> | Record<string, any>[] {
|
|
680
|
-
// Build a map of field names to their schema types
|
|
681
|
-
const fieldTypeMap = new Map();
|
|
682
|
-
tableSchema.fields.forEach((field: any) => {
|
|
683
|
-
const fieldName = field.name;
|
|
684
|
-
const fieldTypeStr = field.type.toString().toLowerCase();
|
|
685
|
-
fieldTypeMap.set(fieldName, fieldTypeStr);
|
|
686
|
-
});
|
|
687
|
-
|
|
688
|
-
// Handle array case
|
|
689
|
-
if (Array.isArray(rawResult)) {
|
|
690
|
-
return rawResult.map(item => this.processResultWithTypeConversion(item, tableSchema));
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// Handle single record case
|
|
694
|
-
const processedResult = { ...rawResult };
|
|
695
|
-
|
|
696
|
-
// Convert each field according to its schema type
|
|
697
|
-
for (const key in processedResult) {
|
|
698
|
-
const fieldTypeStr = fieldTypeMap.get(key);
|
|
699
|
-
if (!fieldTypeStr) continue;
|
|
700
|
-
|
|
701
|
-
// Skip conversion for ID fields - preserve their original format
|
|
702
|
-
// if (key === 'id') {
|
|
703
|
-
// continue;
|
|
704
|
-
// }
|
|
705
|
-
|
|
706
|
-
// Only try to convert string values
|
|
707
|
-
if (typeof processedResult[key] === 'string') {
|
|
708
|
-
// Numeric types
|
|
709
|
-
if (fieldTypeStr.includes('int32') || fieldTypeStr.includes('float32')) {
|
|
710
|
-
if (!isNaN(Number(processedResult[key]))) {
|
|
711
|
-
processedResult[key] = Number(processedResult[key]);
|
|
712
|
-
}
|
|
713
|
-
} else if (fieldTypeStr.includes('int64')) {
|
|
714
|
-
processedResult[key] = Number(processedResult[key]);
|
|
715
|
-
} else if (fieldTypeStr.includes('utf8')) {
|
|
716
|
-
try {
|
|
717
|
-
processedResult[key] = JSON.parse(processedResult[key]);
|
|
718
|
-
} catch (e) {
|
|
719
|
-
// If JSON parsing fails, keep the original string
|
|
720
|
-
this.logger.debug(`Failed to parse JSON for key ${key}: ${e}`);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
} else if (typeof processedResult[key] === 'bigint') {
|
|
724
|
-
// Convert BigInt values to regular numbers for application layer
|
|
725
|
-
processedResult[key] = Number(processedResult[key]);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
return processedResult;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
getThreadById({ threadId }: { threadId: string }): Promise<StorageThreadType | null> {
|
|
733
|
-
try {
|
|
734
|
-
return this.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
|
|
735
|
-
} catch (error: any) {
|
|
736
|
-
throw new MastraError(
|
|
737
|
-
{
|
|
738
|
-
id: 'LANCE_STORE_GET_THREAD_BY_ID_FAILED',
|
|
739
|
-
domain: ErrorDomain.STORAGE,
|
|
740
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
741
|
-
},
|
|
742
|
-
error,
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
async getThreadsByResourceId({ resourceId }: { resourceId: string }): Promise<StorageThreadType[]> {
|
|
748
|
-
try {
|
|
749
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
750
|
-
// fetches all threads with the given resourceId
|
|
751
|
-
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
752
|
-
|
|
753
|
-
const records = await query.toArray();
|
|
754
|
-
return this.processResultWithTypeConversion(
|
|
755
|
-
records,
|
|
756
|
-
await this.getTableSchema(TABLE_THREADS),
|
|
757
|
-
) as StorageThreadType[];
|
|
758
|
-
} catch (error: any) {
|
|
759
|
-
throw new MastraError(
|
|
760
|
-
{
|
|
761
|
-
id: 'LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED',
|
|
762
|
-
domain: ErrorDomain.STORAGE,
|
|
763
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
764
|
-
},
|
|
765
|
-
error,
|
|
766
|
-
);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
772
|
-
* @param thread - The thread to save
|
|
773
|
-
* @returns The saved thread
|
|
774
|
-
*/
|
|
775
|
-
async saveThread({ thread }: { thread: StorageThreadType }): Promise<StorageThreadType> {
|
|
776
|
-
try {
|
|
777
|
-
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
778
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
779
|
-
await table.add([record], { mode: 'append' });
|
|
780
|
-
|
|
781
|
-
return thread;
|
|
782
|
-
} catch (error: any) {
|
|
783
|
-
throw new MastraError(
|
|
784
|
-
{
|
|
785
|
-
id: 'LANCE_STORE_SAVE_THREAD_FAILED',
|
|
786
|
-
domain: ErrorDomain.STORAGE,
|
|
787
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
788
|
-
},
|
|
789
|
-
error,
|
|
790
|
-
);
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
async updateThread({
|
|
795
|
-
id,
|
|
796
|
-
title,
|
|
797
|
-
metadata,
|
|
798
|
-
}: {
|
|
799
|
-
id: string;
|
|
800
|
-
title: string;
|
|
801
|
-
metadata: Record<string, unknown>;
|
|
802
|
-
}): Promise<StorageThreadType> {
|
|
803
|
-
try {
|
|
804
|
-
const record = { id, title, metadata: JSON.stringify(metadata) };
|
|
805
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
806
|
-
await table.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
807
|
-
|
|
808
|
-
const query = table.query().where(`id = '${id}'`);
|
|
809
|
-
|
|
810
|
-
const records = await query.toArray();
|
|
811
|
-
return this.processResultWithTypeConversion(
|
|
812
|
-
records[0],
|
|
813
|
-
await this.getTableSchema(TABLE_THREADS),
|
|
814
|
-
) as StorageThreadType;
|
|
815
|
-
} catch (error: any) {
|
|
816
|
-
throw new MastraError(
|
|
817
|
-
{
|
|
818
|
-
id: 'LANCE_STORE_UPDATE_THREAD_FAILED',
|
|
819
|
-
domain: ErrorDomain.STORAGE,
|
|
820
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
821
|
-
},
|
|
822
|
-
error,
|
|
823
|
-
);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
async deleteThread({ threadId }: { threadId: string }): Promise<void> {
|
|
828
|
-
try {
|
|
829
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
830
|
-
await table.delete(`id = '${threadId}'`);
|
|
831
|
-
} catch (error: any) {
|
|
832
|
-
throw new MastraError(
|
|
833
|
-
{
|
|
834
|
-
id: 'LANCE_STORE_DELETE_THREAD_FAILED',
|
|
835
|
-
domain: ErrorDomain.STORAGE,
|
|
836
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
837
|
-
},
|
|
838
|
-
error,
|
|
839
|
-
);
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
/**
|
|
844
|
-
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
845
|
-
* @param records - The sorted array of records to process
|
|
846
|
-
* @param include - The array of include specifications with context parameters
|
|
847
|
-
* @returns The processed array with context messages included
|
|
848
|
-
*/
|
|
849
|
-
private processMessagesWithContext(
|
|
850
|
-
records: any[],
|
|
851
|
-
include: { id: string; withPreviousMessages?: number; withNextMessages?: number }[],
|
|
852
|
-
): any[] {
|
|
853
|
-
const messagesWithContext = include.filter(item => item.withPreviousMessages || item.withNextMessages);
|
|
854
|
-
|
|
855
|
-
if (messagesWithContext.length === 0) {
|
|
856
|
-
return records;
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// Create a map of message id to index in the sorted array for quick lookup
|
|
860
|
-
const messageIndexMap = new Map<string, number>();
|
|
861
|
-
records.forEach((message, index) => {
|
|
862
|
-
messageIndexMap.set(message.id, index);
|
|
863
|
-
});
|
|
864
|
-
|
|
865
|
-
// Keep track of additional indices to include
|
|
866
|
-
const additionalIndices = new Set<number>();
|
|
867
|
-
|
|
868
|
-
for (const item of messagesWithContext) {
|
|
869
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
870
|
-
if (messageIndex !== undefined) {
|
|
871
|
-
// Add previous messages if requested
|
|
872
|
-
if (item.withPreviousMessages) {
|
|
873
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
874
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
875
|
-
additionalIndices.add(i);
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// Add next messages if requested
|
|
880
|
-
if (item.withNextMessages) {
|
|
881
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
882
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
883
|
-
additionalIndices.add(i);
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
// If we need to include additional messages, create a new set of records
|
|
890
|
-
if (additionalIndices.size === 0) {
|
|
891
|
-
return records;
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
// Get IDs of the records that matched the original query
|
|
895
|
-
const originalMatchIds = new Set(include.map(item => item.id));
|
|
896
|
-
|
|
897
|
-
// Create a set of all indices we need to include
|
|
898
|
-
const allIndices = new Set<number>();
|
|
899
|
-
|
|
900
|
-
// Add indices of originally matched messages
|
|
901
|
-
records.forEach((record, index) => {
|
|
902
|
-
if (originalMatchIds.has(record.id)) {
|
|
903
|
-
allIndices.add(index);
|
|
904
|
-
}
|
|
905
|
-
});
|
|
906
|
-
|
|
907
|
-
// Add the additional context message indices
|
|
908
|
-
additionalIndices.forEach(index => {
|
|
909
|
-
allIndices.add(index);
|
|
910
|
-
});
|
|
911
|
-
|
|
912
|
-
// Create a new filtered array with only the required messages
|
|
913
|
-
// while maintaining chronological order
|
|
914
|
-
return Array.from(allIndices)
|
|
915
|
-
.sort((a, b) => a - b)
|
|
916
|
-
.map(index => records[index]);
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
|
|
920
|
-
public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
|
|
921
|
-
public async getMessages({
|
|
922
|
-
threadId,
|
|
923
|
-
resourceId,
|
|
924
|
-
selectBy,
|
|
925
|
-
format,
|
|
926
|
-
threadConfig,
|
|
927
|
-
}: StorageGetMessagesArg & { format?: 'v1' | 'v2' }): Promise<MastraMessageV1[] | MastraMessageV2[]> {
|
|
928
|
-
try {
|
|
929
|
-
if (threadConfig) {
|
|
930
|
-
throw new Error('ThreadConfig is not supported by LanceDB storage');
|
|
931
|
-
}
|
|
932
|
-
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
|
|
933
|
-
const table = await this.lanceClient.openTable(TABLE_MESSAGES);
|
|
934
|
-
let query = table.query().where(`\`threadId\` = '${threadId}'`);
|
|
935
|
-
|
|
936
|
-
// Apply selectBy filters if provided
|
|
937
|
-
if (selectBy) {
|
|
938
|
-
// Handle 'include' to fetch specific messages
|
|
939
|
-
if (selectBy.include && selectBy.include.length > 0) {
|
|
940
|
-
const includeIds = selectBy.include.map(item => item.id);
|
|
941
|
-
// Add additional query to include specific message IDs
|
|
942
|
-
// This will be combined with the threadId filter
|
|
943
|
-
const includeClause = includeIds.map(id => `\`id\` = '${id}'`).join(' OR ');
|
|
944
|
-
query = query.where(`(\`threadId\` = '${threadId}' OR (${includeClause}))`);
|
|
945
|
-
|
|
946
|
-
// Note: The surrounding messages (withPreviousMessages/withNextMessages) will be
|
|
947
|
-
// handled after we retrieve the results
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// Fetch all records matching the query
|
|
952
|
-
let records = await query.toArray();
|
|
953
|
-
|
|
954
|
-
// Sort the records chronologically
|
|
955
|
-
records.sort((a, b) => {
|
|
956
|
-
const dateA = new Date(a.createdAt).getTime();
|
|
957
|
-
const dateB = new Date(b.createdAt).getTime();
|
|
958
|
-
return dateA - dateB; // Ascending order
|
|
959
|
-
});
|
|
960
|
-
|
|
961
|
-
// Process the include.withPreviousMessages and include.withNextMessages if specified
|
|
962
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
963
|
-
records = this.processMessagesWithContext(records, selectBy.include);
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
// If we're fetching the last N messages, take only the last N after sorting
|
|
967
|
-
if (limit !== Number.MAX_SAFE_INTEGER) {
|
|
968
|
-
records = records.slice(-limit);
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
const messages = this.processResultWithTypeConversion(records, await this.getTableSchema(TABLE_MESSAGES));
|
|
972
|
-
const normalized = messages.map((msg: MastraMessageV2 | MastraMessageV1) => ({
|
|
973
|
-
...msg,
|
|
974
|
-
content:
|
|
975
|
-
typeof msg.content === 'string'
|
|
976
|
-
? (() => {
|
|
977
|
-
try {
|
|
978
|
-
return JSON.parse(msg.content);
|
|
979
|
-
} catch {
|
|
980
|
-
return msg.content;
|
|
981
|
-
}
|
|
982
|
-
})()
|
|
983
|
-
: msg.content,
|
|
984
|
-
}));
|
|
985
|
-
const list = new MessageList({ threadId, resourceId }).add(normalized, 'memory');
|
|
986
|
-
if (format === 'v2') return list.get.all.v2();
|
|
987
|
-
return list.get.all.v1();
|
|
988
|
-
} catch (error: any) {
|
|
989
|
-
throw new MastraError(
|
|
990
|
-
{
|
|
991
|
-
id: 'LANCE_STORE_GET_MESSAGES_FAILED',
|
|
992
|
-
domain: ErrorDomain.STORAGE,
|
|
993
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
994
|
-
},
|
|
995
|
-
error,
|
|
996
|
-
);
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
async saveMessages(args: { messages: MastraMessageV1[]; format?: undefined | 'v1' }): Promise<MastraMessageV1[]>;
|
|
1001
|
-
async saveMessages(args: { messages: MastraMessageV2[]; format: 'v2' }): Promise<MastraMessageV2[]>;
|
|
1002
|
-
async saveMessages(
|
|
1003
|
-
args: { messages: MastraMessageV1[]; format?: undefined | 'v1' } | { messages: MastraMessageV2[]; format: 'v2' },
|
|
1004
|
-
): Promise<MastraMessageV2[] | MastraMessageV1[]> {
|
|
1005
|
-
try {
|
|
1006
|
-
const { messages, format = 'v1' } = args;
|
|
1007
|
-
if (messages.length === 0) {
|
|
1008
|
-
return [];
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
const threadId = messages[0]?.threadId;
|
|
1012
|
-
|
|
1013
|
-
if (!threadId) {
|
|
1014
|
-
throw new Error('Thread ID is required');
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
const transformedMessages = messages.map((message: MastraMessageV2 | MastraMessageV1) => ({
|
|
1018
|
-
...message,
|
|
1019
|
-
content: JSON.stringify(message.content),
|
|
1020
|
-
}));
|
|
1021
|
-
|
|
1022
|
-
const table = await this.lanceClient.openTable(TABLE_MESSAGES);
|
|
1023
|
-
await table.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
1024
|
-
|
|
1025
|
-
const list = new MessageList().add(messages, 'memory');
|
|
1026
|
-
if (format === `v2`) return list.get.all.v2();
|
|
1027
|
-
return list.get.all.v1();
|
|
1028
|
-
} catch (error: any) {
|
|
1029
|
-
throw new MastraError(
|
|
1030
|
-
{
|
|
1031
|
-
id: 'LANCE_STORE_SAVE_MESSAGES_FAILED',
|
|
1032
|
-
domain: ErrorDomain.STORAGE,
|
|
1033
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1034
|
-
},
|
|
1035
|
-
error,
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
async saveTrace({ trace }: { trace: TraceType }): Promise<TraceType> {
|
|
1041
|
-
try {
|
|
1042
|
-
const table = await this.lanceClient.openTable(TABLE_TRACES);
|
|
1043
|
-
const record = {
|
|
1044
|
-
...trace,
|
|
1045
|
-
attributes: JSON.stringify(trace.attributes),
|
|
1046
|
-
status: JSON.stringify(trace.status),
|
|
1047
|
-
events: JSON.stringify(trace.events),
|
|
1048
|
-
links: JSON.stringify(trace.links),
|
|
1049
|
-
other: JSON.stringify(trace.other),
|
|
1050
|
-
};
|
|
1051
|
-
await table.add([record], { mode: 'append' });
|
|
1052
|
-
|
|
1053
|
-
return trace;
|
|
1054
|
-
} catch (error: any) {
|
|
1055
|
-
throw new MastraError(
|
|
1056
|
-
{
|
|
1057
|
-
id: 'LANCE_STORE_SAVE_TRACE_FAILED',
|
|
1058
|
-
domain: ErrorDomain.STORAGE,
|
|
1059
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1060
|
-
},
|
|
1061
|
-
error,
|
|
1062
|
-
);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
async getTraceById({ traceId }: { traceId: string }): Promise<TraceType> {
|
|
1067
|
-
try {
|
|
1068
|
-
const table = await this.lanceClient.openTable(TABLE_TRACES);
|
|
1069
|
-
const query = table.query().where(`id = '${traceId}'`);
|
|
1070
|
-
const records = await query.toArray();
|
|
1071
|
-
return this.processResultWithTypeConversion(records[0], await this.getTableSchema(TABLE_TRACES)) as TraceType;
|
|
1072
|
-
} catch (error: any) {
|
|
1073
|
-
throw new MastraError(
|
|
1074
|
-
{
|
|
1075
|
-
id: 'LANCE_STORE_GET_TRACE_BY_ID_FAILED',
|
|
1076
|
-
domain: ErrorDomain.STORAGE,
|
|
1077
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1078
|
-
},
|
|
1079
|
-
error,
|
|
1080
|
-
);
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
async getTraces({
|
|
1085
|
-
name,
|
|
1086
|
-
scope,
|
|
1087
|
-
page = 1,
|
|
1088
|
-
perPage = 10,
|
|
1089
|
-
attributes,
|
|
1090
|
-
}: {
|
|
1091
|
-
name?: string;
|
|
1092
|
-
scope?: string;
|
|
1093
|
-
page: number;
|
|
1094
|
-
perPage: number;
|
|
1095
|
-
attributes?: Record<string, string>;
|
|
1096
|
-
}): Promise<TraceType[]> {
|
|
1097
|
-
try {
|
|
1098
|
-
const table = await this.lanceClient.openTable(TABLE_TRACES);
|
|
1099
|
-
const query = table.query();
|
|
1100
|
-
|
|
1101
|
-
if (name) {
|
|
1102
|
-
query.where(`name = '${name}'`);
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
if (scope) {
|
|
1106
|
-
query.where(`scope = '${scope}'`);
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
if (attributes) {
|
|
1110
|
-
query.where(`attributes = '${JSON.stringify(attributes)}'`);
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
// Calculate offset based on page and perPage
|
|
1114
|
-
const offset = (page - 1) * perPage;
|
|
1115
|
-
|
|
1116
|
-
// Apply limit for pagination
|
|
1117
|
-
query.limit(perPage);
|
|
1118
|
-
|
|
1119
|
-
// Apply offset if greater than 0
|
|
1120
|
-
if (offset > 0) {
|
|
1121
|
-
query.offset(offset);
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
const records = await query.toArray();
|
|
1125
|
-
return records.map(record => {
|
|
1126
|
-
return {
|
|
1127
|
-
...record,
|
|
1128
|
-
attributes: JSON.parse(record.attributes),
|
|
1129
|
-
status: JSON.parse(record.status),
|
|
1130
|
-
events: JSON.parse(record.events),
|
|
1131
|
-
links: JSON.parse(record.links),
|
|
1132
|
-
other: JSON.parse(record.other),
|
|
1133
|
-
startTime: new Date(record.startTime),
|
|
1134
|
-
endTime: new Date(record.endTime),
|
|
1135
|
-
createdAt: new Date(record.createdAt),
|
|
1136
|
-
};
|
|
1137
|
-
}) as TraceType[];
|
|
1138
|
-
} catch (error: any) {
|
|
1139
|
-
throw new MastraError(
|
|
1140
|
-
{
|
|
1141
|
-
id: 'LANCE_STORE_GET_TRACES_FAILED',
|
|
1142
|
-
domain: ErrorDomain.STORAGE,
|
|
1143
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1144
|
-
details: { name: name ?? '', scope: scope ?? '' },
|
|
1145
|
-
},
|
|
1146
|
-
error,
|
|
1147
|
-
);
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
async saveEvals({ evals }: { evals: EvalRow[] }): Promise<EvalRow[]> {
|
|
1152
|
-
try {
|
|
1153
|
-
const table = await this.lanceClient.openTable(TABLE_EVALS);
|
|
1154
|
-
const transformedEvals = evals.map(evalRecord => ({
|
|
1155
|
-
input: evalRecord.input,
|
|
1156
|
-
output: evalRecord.output,
|
|
1157
|
-
agent_name: evalRecord.agentName,
|
|
1158
|
-
metric_name: evalRecord.metricName,
|
|
1159
|
-
result: JSON.stringify(evalRecord.result),
|
|
1160
|
-
instructions: evalRecord.instructions,
|
|
1161
|
-
test_info: JSON.stringify(evalRecord.testInfo),
|
|
1162
|
-
global_run_id: evalRecord.globalRunId,
|
|
1163
|
-
run_id: evalRecord.runId,
|
|
1164
|
-
created_at: new Date(evalRecord.createdAt).getTime(),
|
|
1165
|
-
}));
|
|
1166
|
-
|
|
1167
|
-
await table.add(transformedEvals, { mode: 'append' });
|
|
1168
|
-
return evals;
|
|
1169
|
-
} catch (error: any) {
|
|
1170
|
-
throw new MastraError(
|
|
1171
|
-
{
|
|
1172
|
-
id: 'LANCE_STORE_SAVE_EVALS_FAILED',
|
|
1173
|
-
domain: ErrorDomain.STORAGE,
|
|
1174
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1175
|
-
},
|
|
1176
|
-
error,
|
|
1177
|
-
);
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
async getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]> {
|
|
1182
|
-
try {
|
|
1183
|
-
if (type) {
|
|
1184
|
-
this.logger.warn('Type is not implemented yet in LanceDB storage');
|
|
1185
|
-
}
|
|
1186
|
-
const table = await this.lanceClient.openTable(TABLE_EVALS);
|
|
1187
|
-
const query = table.query().where(`agent_name = '${agentName}'`);
|
|
1188
|
-
const records = await query.toArray();
|
|
1189
|
-
return records.map(record => {
|
|
1190
|
-
return {
|
|
1191
|
-
id: record.id,
|
|
1192
|
-
input: record.input,
|
|
1193
|
-
output: record.output,
|
|
1194
|
-
agentName: record.agent_name,
|
|
1195
|
-
metricName: record.metric_name,
|
|
1196
|
-
result: JSON.parse(record.result),
|
|
1197
|
-
instructions: record.instructions,
|
|
1198
|
-
testInfo: JSON.parse(record.test_info),
|
|
1199
|
-
globalRunId: record.global_run_id,
|
|
1200
|
-
runId: record.run_id,
|
|
1201
|
-
createdAt: new Date(record.created_at).toString(),
|
|
1202
|
-
};
|
|
1203
|
-
}) as EvalRow[];
|
|
1204
|
-
} catch (error: any) {
|
|
1205
|
-
throw new MastraError(
|
|
1206
|
-
{
|
|
1207
|
-
id: 'LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED',
|
|
1208
|
-
domain: ErrorDomain.STORAGE,
|
|
1209
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1210
|
-
details: { agentName },
|
|
1211
|
-
},
|
|
1212
|
-
error,
|
|
1213
|
-
);
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
private parseWorkflowRun(row: any): WorkflowRun {
|
|
1218
|
-
let parsedSnapshot: WorkflowRunState | string = row.snapshot as string;
|
|
1219
|
-
if (typeof parsedSnapshot === 'string') {
|
|
1220
|
-
try {
|
|
1221
|
-
parsedSnapshot = JSON.parse(row.snapshot as string) as WorkflowRunState;
|
|
1222
|
-
} catch (e) {
|
|
1223
|
-
// If parsing fails, return the raw snapshot string
|
|
1224
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
return {
|
|
1229
|
-
workflowName: row.workflow_name,
|
|
1230
|
-
runId: row.run_id,
|
|
1231
|
-
snapshot: parsedSnapshot,
|
|
1232
|
-
createdAt: this.ensureDate(row.createdAt)!,
|
|
1233
|
-
updatedAt: this.ensureDate(row.updatedAt)!,
|
|
1234
|
-
resourceId: row.resourceId,
|
|
1235
|
-
};
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
async getWorkflowRuns(args?: {
|
|
1239
|
-
namespace?: string;
|
|
1240
|
-
workflowName?: string;
|
|
1241
|
-
fromDate?: Date;
|
|
1242
|
-
toDate?: Date;
|
|
1243
|
-
limit?: number;
|
|
1244
|
-
offset?: number;
|
|
1245
|
-
}): Promise<WorkflowRuns> {
|
|
1246
|
-
try {
|
|
1247
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1248
|
-
const query = table.query();
|
|
1249
|
-
|
|
1250
|
-
if (args?.workflowName) {
|
|
1251
|
-
query.where(`workflow_name = '${args.workflowName}'`);
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
if (args?.fromDate) {
|
|
1255
|
-
query.where(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
if (args?.toDate) {
|
|
1259
|
-
query.where(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
if (args?.limit) {
|
|
1263
|
-
query.limit(args.limit);
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
if (args?.offset) {
|
|
1267
|
-
query.offset(args.offset);
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
const records = await query.toArray();
|
|
1271
|
-
return {
|
|
1272
|
-
runs: records.map(record => this.parseWorkflowRun(record)),
|
|
1273
|
-
total: records.length,
|
|
1274
|
-
};
|
|
1275
|
-
} catch (error: any) {
|
|
1276
|
-
throw new MastraError(
|
|
1277
|
-
{
|
|
1278
|
-
id: 'LANCE_STORE_GET_WORKFLOW_RUNS_FAILED',
|
|
1279
|
-
domain: ErrorDomain.STORAGE,
|
|
1280
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1281
|
-
details: { namespace: args?.namespace ?? '', workflowName: args?.workflowName ?? '' },
|
|
1282
|
-
},
|
|
1283
|
-
error,
|
|
1284
|
-
);
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
/**
|
|
1289
|
-
* Retrieve a single workflow run by its runId.
|
|
1290
|
-
* @param args The ID of the workflow run to retrieve
|
|
1291
|
-
* @returns The workflow run object or null if not found
|
|
1292
|
-
*/
|
|
1293
|
-
async getWorkflowRunById(args: { runId: string; workflowName?: string }): Promise<{
|
|
1294
|
-
workflowName: string;
|
|
1295
|
-
runId: string;
|
|
1296
|
-
snapshot: any;
|
|
1297
|
-
createdAt: Date;
|
|
1298
|
-
updatedAt: Date;
|
|
1299
|
-
} | null> {
|
|
1300
|
-
try {
|
|
1301
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1302
|
-
let whereClause = `run_id = '${args.runId}'`;
|
|
1303
|
-
if (args.workflowName) {
|
|
1304
|
-
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
1305
|
-
}
|
|
1306
|
-
const query = table.query().where(whereClause);
|
|
1307
|
-
const records = await query.toArray();
|
|
1308
|
-
if (records.length === 0) return null;
|
|
1309
|
-
const record = records[0];
|
|
1310
|
-
return this.parseWorkflowRun(record);
|
|
1311
|
-
} catch (error: any) {
|
|
1312
|
-
throw new MastraError(
|
|
1313
|
-
{
|
|
1314
|
-
id: 'LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED',
|
|
1315
|
-
domain: ErrorDomain.STORAGE,
|
|
1316
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1317
|
-
details: { runId: args.runId, workflowName: args.workflowName ?? '' },
|
|
1318
|
-
},
|
|
1319
|
-
error,
|
|
1320
|
-
);
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
async persistWorkflowSnapshot({
|
|
1325
|
-
workflowName,
|
|
1326
|
-
runId,
|
|
1327
|
-
snapshot,
|
|
1328
|
-
}: {
|
|
1329
|
-
workflowName: string;
|
|
1330
|
-
runId: string;
|
|
1331
|
-
snapshot: WorkflowRunState;
|
|
1332
|
-
}): Promise<void> {
|
|
1333
|
-
try {
|
|
1334
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1335
|
-
|
|
1336
|
-
// Try to find the existing record
|
|
1337
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1338
|
-
const records = await query.toArray();
|
|
1339
|
-
let createdAt: number;
|
|
1340
|
-
const now = Date.now();
|
|
1341
|
-
|
|
1342
|
-
if (records.length > 0) {
|
|
1343
|
-
createdAt = records[0].createdAt ?? now;
|
|
1344
|
-
} else {
|
|
1345
|
-
createdAt = now;
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
const record = {
|
|
1349
|
-
workflow_name: workflowName,
|
|
1350
|
-
run_id: runId,
|
|
1351
|
-
snapshot: JSON.stringify(snapshot),
|
|
1352
|
-
createdAt,
|
|
1353
|
-
updatedAt: now,
|
|
1354
|
-
};
|
|
1355
|
-
|
|
1356
|
-
await table
|
|
1357
|
-
.mergeInsert(['workflow_name', 'run_id'])
|
|
1358
|
-
.whenMatchedUpdateAll()
|
|
1359
|
-
.whenNotMatchedInsertAll()
|
|
1360
|
-
.execute([record]);
|
|
1361
|
-
} catch (error: any) {
|
|
1362
|
-
throw new MastraError(
|
|
1363
|
-
{
|
|
1364
|
-
id: 'LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED',
|
|
1365
|
-
domain: ErrorDomain.STORAGE,
|
|
1366
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1367
|
-
details: { workflowName, runId },
|
|
1368
|
-
},
|
|
1369
|
-
error,
|
|
1370
|
-
);
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
async loadWorkflowSnapshot({
|
|
1374
|
-
workflowName,
|
|
1375
|
-
runId,
|
|
1376
|
-
}: {
|
|
1377
|
-
workflowName: string;
|
|
1378
|
-
runId: string;
|
|
1379
|
-
}): Promise<WorkflowRunState | null> {
|
|
1380
|
-
try {
|
|
1381
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1382
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1383
|
-
const records = await query.toArray();
|
|
1384
|
-
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1385
|
-
} catch (error: any) {
|
|
1386
|
-
throw new MastraError(
|
|
1387
|
-
{
|
|
1388
|
-
id: 'LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED',
|
|
1389
|
-
domain: ErrorDomain.STORAGE,
|
|
1390
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1391
|
-
details: { workflowName, runId },
|
|
1392
|
-
},
|
|
1393
|
-
error,
|
|
1394
|
-
);
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
async getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & { traces: Trace[] }> {
|
|
1399
|
-
throw new MastraError(
|
|
1400
|
-
{
|
|
1401
|
-
id: 'LANCE_STORE_GET_TRACES_PAGINATED_FAILED',
|
|
1402
|
-
domain: ErrorDomain.STORAGE,
|
|
1403
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1404
|
-
},
|
|
1405
|
-
'Method not implemented.',
|
|
1406
|
-
);
|
|
1407
|
-
}
|
|
1408
|
-
|
|
1409
|
-
async getThreadsByResourceIdPaginated(_args: {
|
|
1410
|
-
resourceId: string;
|
|
1411
|
-
page?: number;
|
|
1412
|
-
perPage?: number;
|
|
1413
|
-
}): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
|
|
1414
|
-
throw new MastraError(
|
|
1415
|
-
{
|
|
1416
|
-
id: 'LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED',
|
|
1417
|
-
domain: ErrorDomain.STORAGE,
|
|
1418
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1419
|
-
},
|
|
1420
|
-
'Method not implemented.',
|
|
1421
|
-
);
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
async getMessagesPaginated(
|
|
1425
|
-
_args: StorageGetMessagesArg,
|
|
1426
|
-
): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
|
|
1427
|
-
throw new MastraError(
|
|
1428
|
-
{
|
|
1429
|
-
id: 'LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED',
|
|
1430
|
-
domain: ErrorDomain.STORAGE,
|
|
1431
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1432
|
-
},
|
|
1433
|
-
'Method not implemented.',
|
|
1434
|
-
);
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
async updateMessages(_args: {
|
|
1438
|
-
messages: Partial<Omit<MastraMessageV2, 'createdAt'>> &
|
|
1439
|
-
{
|
|
1440
|
-
id: string;
|
|
1441
|
-
content?: { metadata?: MastraMessageContentV2['metadata']; content?: MastraMessageContentV2['content'] };
|
|
1442
|
-
}[];
|
|
1443
|
-
}): Promise<MastraMessageV2[]> {
|
|
1444
|
-
this.logger.error('updateMessages is not yet implemented in LanceStore');
|
|
1445
|
-
throw new Error('Method not implemented');
|
|
1446
|
-
}
|
|
1447
|
-
}
|