@mastra/lance 0.0.0-remove-unused-model-providers-api-20251030210744 → 0.0.0-remove-ai-peer-dep-from-evals-20260105220639
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 +1114 -3
- package/README.md +61 -4
- package/dist/docs/README.md +33 -0
- package/dist/docs/SKILL.md +34 -0
- package/dist/docs/SOURCE_MAP.json +6 -0
- package/dist/docs/rag/01-vector-databases.md +638 -0
- package/dist/docs/storage/01-reference.md +113 -0
- package/dist/docs/vectors/01-reference.md +149 -0
- package/dist/index.cjs +1438 -1415
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1436 -1416
- package/dist/index.js.map +1 -1
- package/dist/storage/{domains/operations → db}/index.d.ts +21 -2
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/db/utils.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +19 -45
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +24 -27
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +17 -15
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +101 -200
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/filter.d.ts +5 -5
- package/dist/vector/index.d.ts +6 -3
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +17 -12
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
- package/dist/storage/domains/utils.d.ts.map +0 -1
- /package/dist/storage/{domains → db}/utils.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -4,8 +4,9 @@ var lancedb = require('@lancedb/lancedb');
|
|
|
4
4
|
var error = require('@mastra/core/error');
|
|
5
5
|
var storage = require('@mastra/core/storage');
|
|
6
6
|
var agent = require('@mastra/core/agent');
|
|
7
|
+
var base = require('@mastra/core/base');
|
|
7
8
|
var apacheArrow = require('apache-arrow');
|
|
8
|
-
var
|
|
9
|
+
var evals = require('@mastra/core/evals');
|
|
9
10
|
var vector = require('@mastra/core/vector');
|
|
10
11
|
var filter = require('@mastra/core/vector/filter');
|
|
11
12
|
|
|
@@ -91,7 +92,7 @@ async function getTableSchema({
|
|
|
91
92
|
} catch (validationError) {
|
|
92
93
|
throw new error.MastraError(
|
|
93
94
|
{
|
|
94
|
-
id: "
|
|
95
|
+
id: storage.createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
|
|
95
96
|
domain: error.ErrorDomain.STORAGE,
|
|
96
97
|
category: error.ErrorCategory.USER,
|
|
97
98
|
text: validationError.message,
|
|
@@ -114,7 +115,7 @@ async function getTableSchema({
|
|
|
114
115
|
} catch (error$1) {
|
|
115
116
|
throw new error.MastraError(
|
|
116
117
|
{
|
|
117
|
-
id: "
|
|
118
|
+
id: storage.createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
|
|
118
119
|
domain: error.ErrorDomain.STORAGE,
|
|
119
120
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
120
121
|
details: { tableName }
|
|
@@ -124,793 +125,503 @@ async function getTableSchema({
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
// src/storage/
|
|
128
|
-
|
|
128
|
+
// src/storage/db/index.ts
|
|
129
|
+
function resolveLanceConfig(config) {
|
|
130
|
+
return config.client;
|
|
131
|
+
}
|
|
132
|
+
var LanceDB = class extends base.MastraBase {
|
|
129
133
|
client;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
super();
|
|
134
|
+
constructor({ client }) {
|
|
135
|
+
super({ name: "lance-db" });
|
|
133
136
|
this.client = client;
|
|
134
|
-
this.operations = operations;
|
|
135
137
|
}
|
|
136
|
-
|
|
138
|
+
getDefaultValue(type) {
|
|
139
|
+
switch (type) {
|
|
140
|
+
case "text":
|
|
141
|
+
return "''";
|
|
142
|
+
case "timestamp":
|
|
143
|
+
return "CURRENT_TIMESTAMP";
|
|
144
|
+
case "integer":
|
|
145
|
+
case "bigint":
|
|
146
|
+
return "0";
|
|
147
|
+
case "jsonb":
|
|
148
|
+
return "'{}'";
|
|
149
|
+
case "uuid":
|
|
150
|
+
return "''";
|
|
151
|
+
default:
|
|
152
|
+
return storage.getDefaultValue(type);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async hasColumn(tableName, columnName) {
|
|
156
|
+
const table = await this.client.openTable(tableName);
|
|
157
|
+
const schema = await table.schema();
|
|
158
|
+
return schema.fields.some((field) => field.name === columnName);
|
|
159
|
+
}
|
|
160
|
+
translateSchema(schema) {
|
|
161
|
+
const fields = Object.entries(schema).map(([name, column]) => {
|
|
162
|
+
let arrowType;
|
|
163
|
+
switch (column.type.toLowerCase()) {
|
|
164
|
+
case "text":
|
|
165
|
+
case "uuid":
|
|
166
|
+
arrowType = new apacheArrow.Utf8();
|
|
167
|
+
break;
|
|
168
|
+
case "int":
|
|
169
|
+
case "integer":
|
|
170
|
+
arrowType = new apacheArrow.Int32();
|
|
171
|
+
break;
|
|
172
|
+
case "bigint":
|
|
173
|
+
arrowType = new apacheArrow.Float64();
|
|
174
|
+
break;
|
|
175
|
+
case "float":
|
|
176
|
+
arrowType = new apacheArrow.Float32();
|
|
177
|
+
break;
|
|
178
|
+
case "jsonb":
|
|
179
|
+
case "json":
|
|
180
|
+
arrowType = new apacheArrow.Utf8();
|
|
181
|
+
break;
|
|
182
|
+
case "binary":
|
|
183
|
+
arrowType = new apacheArrow.Binary();
|
|
184
|
+
break;
|
|
185
|
+
case "timestamp":
|
|
186
|
+
arrowType = new apacheArrow.Float64();
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
arrowType = new apacheArrow.Utf8();
|
|
190
|
+
}
|
|
191
|
+
return new apacheArrow.Field(name, arrowType, column.nullable ?? true);
|
|
192
|
+
});
|
|
193
|
+
return new apacheArrow.Schema(fields);
|
|
194
|
+
}
|
|
195
|
+
async createTable({
|
|
196
|
+
tableName,
|
|
197
|
+
schema
|
|
198
|
+
}) {
|
|
137
199
|
try {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
200
|
+
if (!this.client) {
|
|
201
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
202
|
+
}
|
|
203
|
+
if (!tableName) {
|
|
204
|
+
throw new Error("tableName is required for createTable.");
|
|
205
|
+
}
|
|
206
|
+
if (!schema) {
|
|
207
|
+
throw new Error("schema is required for createTable.");
|
|
141
208
|
}
|
|
142
|
-
return {
|
|
143
|
-
...thread,
|
|
144
|
-
createdAt: new Date(thread.createdAt),
|
|
145
|
-
updatedAt: new Date(thread.updatedAt)
|
|
146
|
-
};
|
|
147
209
|
} catch (error$1) {
|
|
148
210
|
throw new error.MastraError(
|
|
149
211
|
{
|
|
150
|
-
id: "
|
|
212
|
+
id: storage.createStorageErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
|
|
151
213
|
domain: error.ErrorDomain.STORAGE,
|
|
152
|
-
category: error.ErrorCategory.
|
|
214
|
+
category: error.ErrorCategory.USER,
|
|
215
|
+
details: { tableName }
|
|
153
216
|
},
|
|
154
217
|
error$1
|
|
155
218
|
);
|
|
156
219
|
}
|
|
157
|
-
}
|
|
158
|
-
async getThreadsByResourceId({ resourceId }) {
|
|
159
220
|
try {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
const records = await query.toArray();
|
|
163
|
-
return processResultWithTypeConversion(
|
|
164
|
-
records,
|
|
165
|
-
await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client })
|
|
166
|
-
);
|
|
221
|
+
const arrowSchema = this.translateSchema(schema);
|
|
222
|
+
await this.client.createEmptyTable(tableName, arrowSchema);
|
|
167
223
|
} catch (error$1) {
|
|
224
|
+
if (error$1.message?.includes("already exists")) {
|
|
225
|
+
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
168
228
|
throw new error.MastraError(
|
|
169
229
|
{
|
|
170
|
-
id: "
|
|
230
|
+
id: storage.createStorageErrorId("LANCE", "CREATE_TABLE", "FAILED"),
|
|
171
231
|
domain: error.ErrorDomain.STORAGE,
|
|
172
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
232
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
233
|
+
details: { tableName }
|
|
173
234
|
},
|
|
174
235
|
error$1
|
|
175
236
|
);
|
|
176
237
|
}
|
|
177
238
|
}
|
|
178
|
-
|
|
179
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
180
|
-
* @param thread - The thread to save
|
|
181
|
-
* @returns The saved thread
|
|
182
|
-
*/
|
|
183
|
-
async saveThread({ thread }) {
|
|
239
|
+
async dropTable({ tableName }) {
|
|
184
240
|
try {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
241
|
+
if (!this.client) {
|
|
242
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
243
|
+
}
|
|
244
|
+
if (!tableName) {
|
|
245
|
+
throw new Error("tableName is required for dropTable.");
|
|
246
|
+
}
|
|
247
|
+
} catch (validationError) {
|
|
190
248
|
throw new error.MastraError(
|
|
191
249
|
{
|
|
192
|
-
id: "
|
|
250
|
+
id: storage.createStorageErrorId("LANCE", "DROP_TABLE", "INVALID_ARGS"),
|
|
193
251
|
domain: error.ErrorDomain.STORAGE,
|
|
194
|
-
category: error.ErrorCategory.
|
|
252
|
+
category: error.ErrorCategory.USER,
|
|
253
|
+
text: validationError.message,
|
|
254
|
+
details: { tableName }
|
|
195
255
|
},
|
|
196
|
-
|
|
256
|
+
validationError
|
|
197
257
|
);
|
|
198
258
|
}
|
|
199
|
-
}
|
|
200
|
-
async updateThread({
|
|
201
|
-
id,
|
|
202
|
-
title,
|
|
203
|
-
metadata
|
|
204
|
-
}) {
|
|
205
|
-
const maxRetries = 5;
|
|
206
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
207
|
-
try {
|
|
208
|
-
const current = await this.getThreadById({ threadId: id });
|
|
209
|
-
if (!current) {
|
|
210
|
-
throw new Error(`Thread with id ${id} not found`);
|
|
211
|
-
}
|
|
212
|
-
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
213
|
-
const record = {
|
|
214
|
-
id,
|
|
215
|
-
title,
|
|
216
|
-
metadata: JSON.stringify(mergedMetadata),
|
|
217
|
-
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
218
|
-
};
|
|
219
|
-
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
220
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
221
|
-
const updatedThread = await this.getThreadById({ threadId: id });
|
|
222
|
-
if (!updatedThread) {
|
|
223
|
-
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
224
|
-
}
|
|
225
|
-
return updatedThread;
|
|
226
|
-
} catch (error$1) {
|
|
227
|
-
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
228
|
-
const delay = Math.pow(2, attempt) * 10;
|
|
229
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
throw new error.MastraError(
|
|
233
|
-
{
|
|
234
|
-
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
235
|
-
domain: error.ErrorDomain.STORAGE,
|
|
236
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
237
|
-
},
|
|
238
|
-
error$1
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
throw new error.MastraError(
|
|
243
|
-
{
|
|
244
|
-
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
245
|
-
domain: error.ErrorDomain.STORAGE,
|
|
246
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
247
|
-
},
|
|
248
|
-
new Error("All retries exhausted")
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
async deleteThread({ threadId }) {
|
|
252
259
|
try {
|
|
253
|
-
|
|
254
|
-
await table.delete(`id = '${threadId}'`);
|
|
255
|
-
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
256
|
-
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
260
|
+
await this.client.dropTable(tableName);
|
|
257
261
|
} catch (error$1) {
|
|
262
|
+
if (error$1.toString().includes("was not found") || error$1.message?.includes("Table not found")) {
|
|
263
|
+
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
258
266
|
throw new error.MastraError(
|
|
259
267
|
{
|
|
260
|
-
id: "
|
|
268
|
+
id: storage.createStorageErrorId("LANCE", "DROP_TABLE", "FAILED"),
|
|
261
269
|
domain: error.ErrorDomain.STORAGE,
|
|
262
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
270
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
271
|
+
details: { tableName }
|
|
263
272
|
},
|
|
264
273
|
error$1
|
|
265
274
|
);
|
|
266
275
|
}
|
|
267
276
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
threadId: thread_id,
|
|
273
|
-
content: typeof message.content === "string" ? (() => {
|
|
274
|
-
try {
|
|
275
|
-
return JSON.parse(message.content);
|
|
276
|
-
} catch {
|
|
277
|
-
return message.content;
|
|
278
|
-
}
|
|
279
|
-
})() : message.content
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
async getMessages({
|
|
283
|
-
threadId,
|
|
284
|
-
resourceId,
|
|
285
|
-
selectBy,
|
|
286
|
-
format,
|
|
287
|
-
threadConfig
|
|
277
|
+
async alterTable({
|
|
278
|
+
tableName,
|
|
279
|
+
schema,
|
|
280
|
+
ifNotExists
|
|
288
281
|
}) {
|
|
289
282
|
try {
|
|
290
|
-
if (!
|
|
291
|
-
|
|
292
|
-
throw new Error("ThreadConfig is not supported by LanceDB storage");
|
|
283
|
+
if (!this.client) {
|
|
284
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
293
285
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
let allRecords = [];
|
|
297
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
298
|
-
const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
|
|
299
|
-
for (const threadId2 of threadIds) {
|
|
300
|
-
const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
|
|
301
|
-
let threadRecords = await threadQuery.toArray();
|
|
302
|
-
allRecords.push(...threadRecords);
|
|
303
|
-
}
|
|
304
|
-
} else {
|
|
305
|
-
let query = table.query().where(`\`thread_id\` = '${threadId}'`);
|
|
306
|
-
allRecords = await query.toArray();
|
|
286
|
+
if (!tableName) {
|
|
287
|
+
throw new Error("tableName is required for alterTable.");
|
|
307
288
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const dateB = new Date(b.createdAt).getTime();
|
|
311
|
-
return dateA - dateB;
|
|
312
|
-
});
|
|
313
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
314
|
-
allRecords = this.processMessagesWithContext(allRecords, selectBy.include);
|
|
289
|
+
if (!schema) {
|
|
290
|
+
throw new Error("schema is required for alterTable.");
|
|
315
291
|
}
|
|
316
|
-
if (
|
|
317
|
-
|
|
292
|
+
if (!ifNotExists || ifNotExists.length === 0) {
|
|
293
|
+
this.logger.debug("No columns specified to add in alterTable, skipping.");
|
|
294
|
+
return;
|
|
318
295
|
}
|
|
319
|
-
|
|
320
|
-
allRecords,
|
|
321
|
-
await getTableSchema({ tableName: storage.TABLE_MESSAGES, client: this.client })
|
|
322
|
-
);
|
|
323
|
-
const list = new agent.MessageList({ threadId, resourceId }).add(messages.map(this.normalizeMessage), "memory");
|
|
324
|
-
if (format === "v2") return list.get.all.v2();
|
|
325
|
-
return list.get.all.v1();
|
|
326
|
-
} catch (error$1) {
|
|
296
|
+
} catch (validationError) {
|
|
327
297
|
throw new error.MastraError(
|
|
328
298
|
{
|
|
329
|
-
id: "
|
|
299
|
+
id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "INVALID_ARGS"),
|
|
330
300
|
domain: error.ErrorDomain.STORAGE,
|
|
331
|
-
category: error.ErrorCategory.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
resourceId: resourceId ?? ""
|
|
335
|
-
}
|
|
301
|
+
category: error.ErrorCategory.USER,
|
|
302
|
+
text: validationError.message,
|
|
303
|
+
details: { tableName }
|
|
336
304
|
},
|
|
337
|
-
|
|
305
|
+
validationError
|
|
338
306
|
);
|
|
339
307
|
}
|
|
340
|
-
}
|
|
341
|
-
async listMessagesById({ messageIds }) {
|
|
342
|
-
if (messageIds.length === 0) return [];
|
|
343
308
|
try {
|
|
344
|
-
const table = await this.client.openTable(
|
|
345
|
-
const
|
|
346
|
-
const
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
async listMessages(args) {
|
|
368
|
-
const { threadId, resourceId, include, filter, limit, offset = 0, orderBy } = args;
|
|
369
|
-
if (!threadId.trim()) {
|
|
309
|
+
const table = await this.client.openTable(tableName);
|
|
310
|
+
const currentSchema = await table.schema();
|
|
311
|
+
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
312
|
+
const typeMap = {
|
|
313
|
+
text: "string",
|
|
314
|
+
integer: "int",
|
|
315
|
+
bigint: "bigint",
|
|
316
|
+
timestamp: "timestamp",
|
|
317
|
+
jsonb: "string",
|
|
318
|
+
uuid: "string"
|
|
319
|
+
};
|
|
320
|
+
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
321
|
+
const colDef = schema[col];
|
|
322
|
+
return {
|
|
323
|
+
name: col,
|
|
324
|
+
valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
if (columnsToAdd.length > 0) {
|
|
328
|
+
await table.addColumns(columnsToAdd);
|
|
329
|
+
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
330
|
+
}
|
|
331
|
+
} catch (error$1) {
|
|
370
332
|
throw new error.MastraError(
|
|
371
333
|
{
|
|
372
|
-
id: "
|
|
334
|
+
id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "FAILED"),
|
|
373
335
|
domain: error.ErrorDomain.STORAGE,
|
|
374
336
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
375
|
-
details: {
|
|
337
|
+
details: { tableName }
|
|
376
338
|
},
|
|
377
|
-
|
|
339
|
+
error$1
|
|
378
340
|
);
|
|
379
341
|
}
|
|
342
|
+
}
|
|
343
|
+
async clearTable({ tableName }) {
|
|
380
344
|
try {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (limit === false) {
|
|
384
|
-
perPage = Number.MAX_SAFE_INTEGER;
|
|
385
|
-
} else if (limit === 0) {
|
|
386
|
-
perPage = 0;
|
|
387
|
-
} else if (typeof limit === "number" && limit > 0) {
|
|
388
|
-
perPage = limit;
|
|
389
|
-
}
|
|
345
|
+
if (!this.client) {
|
|
346
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
390
347
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const sortDirection = orderBy?.direction || "DESC";
|
|
394
|
-
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
395
|
-
const escapeSql = (str) => str.replace(/'/g, "''");
|
|
396
|
-
const conditions = [`thread_id = '${escapeSql(threadId)}'`];
|
|
397
|
-
if (resourceId) {
|
|
398
|
-
conditions.push(`\`resourceId\` = '${escapeSql(resourceId)}'`);
|
|
348
|
+
if (!tableName) {
|
|
349
|
+
throw new Error("tableName is required for clearTable.");
|
|
399
350
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
351
|
+
} catch (validationError) {
|
|
352
|
+
throw new error.MastraError(
|
|
353
|
+
{
|
|
354
|
+
id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "INVALID_ARGS"),
|
|
355
|
+
domain: error.ErrorDomain.STORAGE,
|
|
356
|
+
category: error.ErrorCategory.USER,
|
|
357
|
+
text: validationError.message,
|
|
358
|
+
details: { tableName }
|
|
359
|
+
},
|
|
360
|
+
validationError
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
const table = await this.client.openTable(tableName);
|
|
365
|
+
await table.delete("1=1");
|
|
366
|
+
} catch (error$1) {
|
|
367
|
+
throw new error.MastraError(
|
|
368
|
+
{
|
|
369
|
+
id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "FAILED"),
|
|
370
|
+
domain: error.ErrorDomain.STORAGE,
|
|
371
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
372
|
+
details: { tableName }
|
|
373
|
+
},
|
|
374
|
+
error$1
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async insert({ tableName, record }) {
|
|
379
|
+
try {
|
|
380
|
+
if (!this.client) {
|
|
381
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
403
382
|
}
|
|
404
|
-
if (
|
|
405
|
-
|
|
406
|
-
conditions.push(`\`createdAt\` <= ${endTime}`);
|
|
383
|
+
if (!tableName) {
|
|
384
|
+
throw new Error("tableName is required for insert.");
|
|
407
385
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
const query = table.query().where(whereClause);
|
|
411
|
-
let allRecords = await query.toArray();
|
|
412
|
-
allRecords.sort((a, b) => {
|
|
413
|
-
const aValue = sortField === "createdAt" ? a.createdAt : a[sortField];
|
|
414
|
-
const bValue = sortField === "createdAt" ? b.createdAt : b[sortField];
|
|
415
|
-
return sortDirection === "ASC" ? aValue - bValue : bValue - aValue;
|
|
416
|
-
});
|
|
417
|
-
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
418
|
-
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
419
|
-
if (total === 0 && messages.length === 0) {
|
|
420
|
-
return {
|
|
421
|
-
messages: [],
|
|
422
|
-
total: 0,
|
|
423
|
-
page,
|
|
424
|
-
perPage,
|
|
425
|
-
hasMore: false
|
|
426
|
-
};
|
|
386
|
+
if (!record || Object.keys(record).length === 0) {
|
|
387
|
+
throw new Error("record is required and cannot be empty for insert.");
|
|
427
388
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
389
|
+
} catch (validationError) {
|
|
390
|
+
throw new error.MastraError(
|
|
391
|
+
{
|
|
392
|
+
id: storage.createStorageErrorId("LANCE", "INSERT", "INVALID_ARGS"),
|
|
393
|
+
domain: error.ErrorDomain.STORAGE,
|
|
394
|
+
category: error.ErrorCategory.USER,
|
|
395
|
+
text: validationError.message,
|
|
396
|
+
details: { tableName }
|
|
397
|
+
},
|
|
398
|
+
validationError
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const table = await this.client.openTable(tableName);
|
|
403
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
404
|
+
const processedRecord = { ...record };
|
|
405
|
+
for (const key in processedRecord) {
|
|
406
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
407
|
+
this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
|
|
408
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
445
409
|
}
|
|
446
410
|
}
|
|
447
|
-
|
|
448
|
-
let finalMessages = list.get.all.v2();
|
|
449
|
-
finalMessages = finalMessages.sort((a, b) => {
|
|
450
|
-
const aValue = sortField === "createdAt" ? new Date(a.createdAt).getTime() : a[sortField];
|
|
451
|
-
const bValue = sortField === "createdAt" ? new Date(b.createdAt).getTime() : b[sortField];
|
|
452
|
-
return sortDirection === "ASC" ? aValue - bValue : bValue - aValue;
|
|
453
|
-
});
|
|
454
|
-
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
455
|
-
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
456
|
-
const hasMore = limit === false ? false : allThreadMessagesReturned ? false : offset + paginatedRecords.length < total;
|
|
457
|
-
return {
|
|
458
|
-
messages: finalMessages,
|
|
459
|
-
total,
|
|
460
|
-
page,
|
|
461
|
-
perPage,
|
|
462
|
-
hasMore
|
|
463
|
-
};
|
|
411
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
464
412
|
} catch (error$1) {
|
|
465
|
-
|
|
466
|
-
const mastraError = new error.MastraError(
|
|
413
|
+
throw new error.MastraError(
|
|
467
414
|
{
|
|
468
|
-
id: "
|
|
415
|
+
id: storage.createStorageErrorId("LANCE", "INSERT", "FAILED"),
|
|
469
416
|
domain: error.ErrorDomain.STORAGE,
|
|
470
417
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
471
|
-
details: {
|
|
472
|
-
threadId,
|
|
473
|
-
resourceId: resourceId ?? ""
|
|
474
|
-
}
|
|
418
|
+
details: { tableName }
|
|
475
419
|
},
|
|
476
420
|
error$1
|
|
477
421
|
);
|
|
478
|
-
this.logger?.error?.(mastraError.toString());
|
|
479
|
-
this.logger?.trackException?.(mastraError);
|
|
480
|
-
return {
|
|
481
|
-
messages: [],
|
|
482
|
-
total: 0,
|
|
483
|
-
page: errorPerPage === 0 ? 0 : Math.floor(offset / errorPerPage),
|
|
484
|
-
perPage: errorPerPage,
|
|
485
|
-
hasMore: false
|
|
486
|
-
};
|
|
487
422
|
}
|
|
488
423
|
}
|
|
489
|
-
|
|
490
|
-
* @todo When migrating from getThreadsByResourceIdPaginated to this method,
|
|
491
|
-
* implement orderBy and sortDirection support for full sorting capabilities
|
|
492
|
-
*/
|
|
493
|
-
async listThreadsByResourceId(args) {
|
|
494
|
-
const { resourceId, limit, offset } = args;
|
|
495
|
-
const page = Math.floor(offset / limit);
|
|
496
|
-
const perPage = limit;
|
|
497
|
-
return this.getThreadsByResourceIdPaginated({ resourceId, page, perPage });
|
|
498
|
-
}
|
|
499
|
-
async saveMessages(args) {
|
|
424
|
+
async batchInsert({ tableName, records }) {
|
|
500
425
|
try {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
return [];
|
|
426
|
+
if (!this.client) {
|
|
427
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
504
428
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
throw new Error("Thread ID is required");
|
|
429
|
+
if (!tableName) {
|
|
430
|
+
throw new Error("tableName is required for batchInsert.");
|
|
508
431
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
throw new Error("Message ID is required");
|
|
512
|
-
}
|
|
513
|
-
if (!message.threadId) {
|
|
514
|
-
throw new Error("Thread ID is required for all messages");
|
|
515
|
-
}
|
|
516
|
-
if (message.resourceId === null || message.resourceId === void 0) {
|
|
517
|
-
throw new Error("Resource ID cannot be null or undefined");
|
|
518
|
-
}
|
|
519
|
-
if (!message.content) {
|
|
520
|
-
throw new Error("Message content is required");
|
|
521
|
-
}
|
|
432
|
+
if (!records || records.length === 0) {
|
|
433
|
+
throw new Error("records array is required and cannot be empty for batchInsert.");
|
|
522
434
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
435
|
+
} catch (validationError) {
|
|
436
|
+
throw new error.MastraError(
|
|
437
|
+
{
|
|
438
|
+
id: storage.createStorageErrorId("LANCE", "BATCH_INSERT", "INVALID_ARGS"),
|
|
439
|
+
domain: error.ErrorDomain.STORAGE,
|
|
440
|
+
category: error.ErrorCategory.USER,
|
|
441
|
+
text: validationError.message,
|
|
442
|
+
details: { tableName }
|
|
443
|
+
},
|
|
444
|
+
validationError
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
const table = await this.client.openTable(tableName);
|
|
449
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
450
|
+
const processedRecords = records.map((record) => {
|
|
451
|
+
const processedRecord = { ...record };
|
|
452
|
+
for (const key in processedRecord) {
|
|
453
|
+
if (processedRecord[key] == null) continue;
|
|
454
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
455
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return processedRecord;
|
|
531
459
|
});
|
|
532
|
-
|
|
533
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
534
|
-
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
535
|
-
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
536
|
-
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
537
|
-
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
538
|
-
const list = new agent.MessageList().add(messages, "memory");
|
|
539
|
-
if (format === `v2`) return list.get.all.v2();
|
|
540
|
-
return list.get.all.v1();
|
|
460
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
|
|
541
461
|
} catch (error$1) {
|
|
542
462
|
throw new error.MastraError(
|
|
543
463
|
{
|
|
544
|
-
id: "
|
|
464
|
+
id: storage.createStorageErrorId("LANCE", "BATCH_INSERT", "FAILED"),
|
|
545
465
|
domain: error.ErrorDomain.STORAGE,
|
|
546
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
466
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
467
|
+
details: { tableName }
|
|
547
468
|
},
|
|
548
469
|
error$1
|
|
549
470
|
);
|
|
550
471
|
}
|
|
551
472
|
}
|
|
552
|
-
async
|
|
473
|
+
async load({ tableName, keys }) {
|
|
553
474
|
try {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const total = await table.countRows(`\`resourceId\` = '${resourceId}'`);
|
|
557
|
-
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
558
|
-
const offset = page * perPage;
|
|
559
|
-
query.limit(perPage);
|
|
560
|
-
if (offset > 0) {
|
|
561
|
-
query.offset(offset);
|
|
475
|
+
if (!this.client) {
|
|
476
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
562
477
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
page,
|
|
571
|
-
perPage,
|
|
572
|
-
hasMore: total > (page + 1) * perPage
|
|
573
|
-
};
|
|
574
|
-
} catch (error$1) {
|
|
478
|
+
if (!tableName) {
|
|
479
|
+
throw new Error("tableName is required for load.");
|
|
480
|
+
}
|
|
481
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
482
|
+
throw new Error("keys are required and cannot be empty for load.");
|
|
483
|
+
}
|
|
484
|
+
} catch (validationError) {
|
|
575
485
|
throw new error.MastraError(
|
|
576
486
|
{
|
|
577
|
-
id: "
|
|
487
|
+
id: storage.createStorageErrorId("LANCE", "LOAD", "INVALID_ARGS"),
|
|
578
488
|
domain: error.ErrorDomain.STORAGE,
|
|
579
|
-
category: error.ErrorCategory.
|
|
489
|
+
category: error.ErrorCategory.USER,
|
|
490
|
+
text: validationError.message,
|
|
491
|
+
details: { tableName }
|
|
580
492
|
},
|
|
581
|
-
|
|
493
|
+
validationError
|
|
582
494
|
);
|
|
583
495
|
}
|
|
584
|
-
}
|
|
585
|
-
/**
|
|
586
|
-
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
587
|
-
* @param records - The sorted array of records to process
|
|
588
|
-
* @param include - The array of include specifications with context parameters
|
|
589
|
-
* @returns The processed array with context messages included
|
|
590
|
-
*/
|
|
591
|
-
processMessagesWithContext(records, include) {
|
|
592
|
-
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
593
|
-
if (messagesWithContext.length === 0) {
|
|
594
|
-
return records;
|
|
595
|
-
}
|
|
596
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
597
|
-
records.forEach((message, index) => {
|
|
598
|
-
messageIndexMap.set(message.id, index);
|
|
599
|
-
});
|
|
600
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
601
|
-
for (const item of messagesWithContext) {
|
|
602
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
603
|
-
if (messageIndex !== void 0) {
|
|
604
|
-
if (item.withPreviousMessages) {
|
|
605
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
606
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
607
|
-
additionalIndices.add(i);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
if (item.withNextMessages) {
|
|
611
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
612
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
613
|
-
additionalIndices.add(i);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
if (additionalIndices.size === 0) {
|
|
619
|
-
return records;
|
|
620
|
-
}
|
|
621
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
622
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
623
|
-
records.forEach((record, index) => {
|
|
624
|
-
if (originalMatchIds.has(record.id)) {
|
|
625
|
-
allIndices.add(index);
|
|
626
|
-
}
|
|
627
|
-
});
|
|
628
|
-
additionalIndices.forEach((index) => {
|
|
629
|
-
allIndices.add(index);
|
|
630
|
-
});
|
|
631
|
-
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
632
|
-
}
|
|
633
|
-
async getMessagesPaginated(args) {
|
|
634
|
-
const { threadId, resourceId, selectBy, format = "v1" } = args;
|
|
635
|
-
const page = selectBy?.pagination?.page ?? 0;
|
|
636
|
-
const perPage = selectBy?.pagination?.perPage ?? 10;
|
|
637
496
|
try {
|
|
638
|
-
|
|
639
|
-
const
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
messages.push(...contextMessages);
|
|
657
|
-
}
|
|
658
|
-
const conditions = [`thread_id = '${threadId}'`];
|
|
659
|
-
if (resourceId) {
|
|
660
|
-
conditions.push(`\`resourceId\` = '${resourceId}'`);
|
|
661
|
-
}
|
|
662
|
-
if (fromDate) {
|
|
663
|
-
conditions.push(`\`createdAt\` >= ${fromDate.getTime()}`);
|
|
664
|
-
}
|
|
665
|
-
if (toDate) {
|
|
666
|
-
conditions.push(`\`createdAt\` <= ${toDate.getTime()}`);
|
|
667
|
-
}
|
|
668
|
-
let total = 0;
|
|
669
|
-
if (conditions.length > 0) {
|
|
670
|
-
total = await table.countRows(conditions.join(" AND "));
|
|
671
|
-
} else {
|
|
672
|
-
total = await table.countRows();
|
|
497
|
+
const table = await this.client.openTable(tableName);
|
|
498
|
+
const tableSchema = await getTableSchema({ tableName, client: this.client });
|
|
499
|
+
const query = table.query();
|
|
500
|
+
if (Object.keys(keys).length > 0) {
|
|
501
|
+
validateKeyTypes(keys, tableSchema);
|
|
502
|
+
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
503
|
+
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
504
|
+
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
505
|
+
if (typeof value === "string") {
|
|
506
|
+
return `${quotedKey} = '${value}'`;
|
|
507
|
+
} else if (value === null) {
|
|
508
|
+
return `${quotedKey} IS NULL`;
|
|
509
|
+
} else {
|
|
510
|
+
return `${quotedKey} = ${value}`;
|
|
511
|
+
}
|
|
512
|
+
}).join(" AND ");
|
|
513
|
+
this.logger.debug("where clause generated: " + filterConditions);
|
|
514
|
+
query.where(filterConditions);
|
|
673
515
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
page,
|
|
679
|
-
perPage,
|
|
680
|
-
hasMore: false
|
|
681
|
-
};
|
|
516
|
+
const result = await query.limit(1).toArray();
|
|
517
|
+
if (result.length === 0) {
|
|
518
|
+
this.logger.debug("No record found");
|
|
519
|
+
return null;
|
|
682
520
|
}
|
|
683
|
-
|
|
684
|
-
let selectedMessages = [];
|
|
685
|
-
if (selectBy?.last && selectBy.last > 0) {
|
|
686
|
-
const query = table.query();
|
|
687
|
-
if (conditions.length > 0) {
|
|
688
|
-
query.where(conditions.join(" AND "));
|
|
689
|
-
}
|
|
690
|
-
let records = await query.toArray();
|
|
691
|
-
records = records.sort((a, b) => a.createdAt - b.createdAt);
|
|
692
|
-
if (excludeIds.length > 0) {
|
|
693
|
-
records = records.filter((m) => !excludeIds.includes(m.id));
|
|
694
|
-
}
|
|
695
|
-
selectedMessages = records.slice(-selectBy.last);
|
|
696
|
-
} else {
|
|
697
|
-
const query = table.query();
|
|
698
|
-
if (conditions.length > 0) {
|
|
699
|
-
query.where(conditions.join(" AND "));
|
|
700
|
-
}
|
|
701
|
-
let records = await query.toArray();
|
|
702
|
-
records = records.sort((a, b) => a.createdAt - b.createdAt);
|
|
703
|
-
if (excludeIds.length > 0) {
|
|
704
|
-
records = records.filter((m) => !excludeIds.includes(m.id));
|
|
705
|
-
}
|
|
706
|
-
selectedMessages = records.slice(page * perPage, (page + 1) * perPage);
|
|
707
|
-
}
|
|
708
|
-
const allMessages = [...messages, ...selectedMessages];
|
|
709
|
-
const seen = /* @__PURE__ */ new Set();
|
|
710
|
-
const dedupedMessages = allMessages.filter((m) => {
|
|
711
|
-
const key = `${m.id}:${m.thread_id}`;
|
|
712
|
-
if (seen.has(key)) return false;
|
|
713
|
-
seen.add(key);
|
|
714
|
-
return true;
|
|
715
|
-
});
|
|
716
|
-
const formattedMessages = dedupedMessages.map((msg) => {
|
|
717
|
-
const { thread_id, ...rest } = msg;
|
|
718
|
-
return {
|
|
719
|
-
...rest,
|
|
720
|
-
threadId: thread_id,
|
|
721
|
-
content: typeof msg.content === "string" ? (() => {
|
|
722
|
-
try {
|
|
723
|
-
return JSON.parse(msg.content);
|
|
724
|
-
} catch {
|
|
725
|
-
return msg.content;
|
|
726
|
-
}
|
|
727
|
-
})() : msg.content
|
|
728
|
-
};
|
|
729
|
-
});
|
|
730
|
-
const list = new agent.MessageList().add(formattedMessages, "memory");
|
|
731
|
-
return {
|
|
732
|
-
messages: format === "v2" ? list.get.all.v2() : list.get.all.v1(),
|
|
733
|
-
total,
|
|
734
|
-
// Total should be the count of messages matching the filters
|
|
735
|
-
page,
|
|
736
|
-
perPage,
|
|
737
|
-
hasMore: total > (page + 1) * perPage
|
|
738
|
-
};
|
|
521
|
+
return processResultWithTypeConversion(result[0], tableSchema);
|
|
739
522
|
} catch (error$1) {
|
|
740
|
-
|
|
523
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
524
|
+
throw new error.MastraError(
|
|
741
525
|
{
|
|
742
|
-
id: "
|
|
526
|
+
id: storage.createStorageErrorId("LANCE", "LOAD", "FAILED"),
|
|
743
527
|
domain: error.ErrorDomain.STORAGE,
|
|
744
528
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
745
|
-
details: {
|
|
746
|
-
threadId,
|
|
747
|
-
resourceId: resourceId ?? ""
|
|
748
|
-
}
|
|
529
|
+
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
749
530
|
},
|
|
750
531
|
error$1
|
|
751
532
|
);
|
|
752
|
-
this.logger?.trackException?.(mastraError);
|
|
753
|
-
this.logger?.error?.(mastraError.toString());
|
|
754
|
-
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
755
533
|
}
|
|
756
534
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
// src/storage/domains/memory/index.ts
|
|
538
|
+
var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
539
|
+
client;
|
|
540
|
+
#db;
|
|
541
|
+
constructor(config) {
|
|
542
|
+
super();
|
|
543
|
+
const client = resolveLanceConfig(config);
|
|
544
|
+
this.client = client;
|
|
545
|
+
this.#db = new LanceDB({ client });
|
|
546
|
+
}
|
|
547
|
+
async init() {
|
|
548
|
+
await this.#db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
|
|
549
|
+
await this.#db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
|
|
550
|
+
await this.#db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
|
|
551
|
+
await this.#db.alterTable({
|
|
552
|
+
tableName: storage.TABLE_MESSAGES,
|
|
553
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES],
|
|
554
|
+
ifNotExists: ["resourceId"]
|
|
555
|
+
});
|
|
775
556
|
}
|
|
776
|
-
async
|
|
777
|
-
|
|
778
|
-
this.
|
|
779
|
-
|
|
780
|
-
|
|
557
|
+
async dangerouslyClearAll() {
|
|
558
|
+
await this.#db.clearTable({ tableName: storage.TABLE_THREADS });
|
|
559
|
+
await this.#db.clearTable({ tableName: storage.TABLE_MESSAGES });
|
|
560
|
+
await this.#db.clearTable({ tableName: storage.TABLE_RESOURCES });
|
|
561
|
+
}
|
|
562
|
+
async deleteMessages(messageIds) {
|
|
563
|
+
if (!messageIds || messageIds.length === 0) {
|
|
564
|
+
return;
|
|
781
565
|
}
|
|
782
|
-
|
|
783
|
-
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
566
|
+
this.logger.debug("Deleting messages", { count: messageIds.length });
|
|
784
567
|
try {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const
|
|
788
|
-
if (
|
|
789
|
-
|
|
790
|
-
continue;
|
|
791
|
-
}
|
|
792
|
-
const existingMsg = this.parseMessageData(existingMessage);
|
|
793
|
-
const originalThreadId = existingMsg.threadId;
|
|
794
|
-
affectedThreadIds.add(originalThreadId);
|
|
795
|
-
const updatePayload = {};
|
|
796
|
-
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
797
|
-
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
798
|
-
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
799
|
-
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
800
|
-
updatePayload.thread_id = updates.threadId;
|
|
801
|
-
affectedThreadIds.add(updates.threadId);
|
|
802
|
-
}
|
|
803
|
-
if (updates.content) {
|
|
804
|
-
const existingContent = existingMsg.content;
|
|
805
|
-
let newContent = { ...existingContent };
|
|
806
|
-
if (updates.content.metadata !== void 0) {
|
|
807
|
-
newContent.metadata = {
|
|
808
|
-
...existingContent.metadata || {},
|
|
809
|
-
...updates.content.metadata || {}
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
if (updates.content.content !== void 0) {
|
|
813
|
-
newContent.content = updates.content.content;
|
|
814
|
-
}
|
|
815
|
-
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
816
|
-
newContent.parts = updates.content.parts;
|
|
817
|
-
}
|
|
818
|
-
updatePayload.content = JSON.stringify(newContent);
|
|
819
|
-
}
|
|
820
|
-
await this.operations.insert({ tableName: storage.TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
821
|
-
const updatedMessage = await this.operations.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
822
|
-
if (updatedMessage) {
|
|
823
|
-
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
568
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
569
|
+
for (const messageId of messageIds) {
|
|
570
|
+
const message = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id: messageId } });
|
|
571
|
+
if (message?.thread_id) {
|
|
572
|
+
threadIds.add(message.thread_id);
|
|
824
573
|
}
|
|
825
574
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
575
|
+
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
576
|
+
const idConditions = messageIds.map((id) => `id = '${this.escapeSql(id)}'`).join(" OR ");
|
|
577
|
+
await messagesTable.delete(idConditions);
|
|
578
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
579
|
+
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
580
|
+
for (const threadId of threadIds) {
|
|
581
|
+
const thread = await this.getThreadById({ threadId });
|
|
582
|
+
if (thread) {
|
|
583
|
+
const record = {
|
|
584
|
+
id: threadId,
|
|
585
|
+
resourceId: thread.resourceId,
|
|
586
|
+
title: thread.title,
|
|
587
|
+
metadata: JSON.stringify(thread.metadata),
|
|
588
|
+
createdAt: new Date(thread.createdAt).getTime(),
|
|
589
|
+
updatedAt: now
|
|
590
|
+
};
|
|
591
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
592
|
+
}
|
|
831
593
|
}
|
|
832
|
-
return updatedMessages;
|
|
833
594
|
} catch (error$1) {
|
|
834
595
|
throw new error.MastraError(
|
|
835
596
|
{
|
|
836
|
-
id: "
|
|
597
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_MESSAGES", "FAILED"),
|
|
837
598
|
domain: error.ErrorDomain.STORAGE,
|
|
838
599
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
839
|
-
details: { count:
|
|
600
|
+
details: { count: messageIds.length }
|
|
840
601
|
},
|
|
841
602
|
error$1
|
|
842
603
|
);
|
|
843
604
|
}
|
|
844
605
|
}
|
|
845
|
-
|
|
606
|
+
// Utility to escape single quotes in SQL strings
|
|
607
|
+
escapeSql(str) {
|
|
608
|
+
return str.replace(/'/g, "''");
|
|
609
|
+
}
|
|
610
|
+
async getThreadById({ threadId }) {
|
|
846
611
|
try {
|
|
847
|
-
const
|
|
848
|
-
if (!
|
|
612
|
+
const thread = await this.#db.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
|
|
613
|
+
if (!thread) {
|
|
849
614
|
return null;
|
|
850
615
|
}
|
|
851
|
-
let createdAt;
|
|
852
|
-
let updatedAt;
|
|
853
|
-
try {
|
|
854
|
-
if (resource.createdAt instanceof Date) {
|
|
855
|
-
createdAt = resource.createdAt;
|
|
856
|
-
} else if (typeof resource.createdAt === "string") {
|
|
857
|
-
createdAt = new Date(resource.createdAt);
|
|
858
|
-
} else if (typeof resource.createdAt === "number") {
|
|
859
|
-
createdAt = new Date(resource.createdAt);
|
|
860
|
-
} else {
|
|
861
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
862
|
-
}
|
|
863
|
-
if (isNaN(createdAt.getTime())) {
|
|
864
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
865
|
-
}
|
|
866
|
-
} catch {
|
|
867
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
868
|
-
}
|
|
869
|
-
try {
|
|
870
|
-
if (resource.updatedAt instanceof Date) {
|
|
871
|
-
updatedAt = resource.updatedAt;
|
|
872
|
-
} else if (typeof resource.updatedAt === "string") {
|
|
873
|
-
updatedAt = new Date(resource.updatedAt);
|
|
874
|
-
} else if (typeof resource.updatedAt === "number") {
|
|
875
|
-
updatedAt = new Date(resource.updatedAt);
|
|
876
|
-
} else {
|
|
877
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
878
|
-
}
|
|
879
|
-
if (isNaN(updatedAt.getTime())) {
|
|
880
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
881
|
-
}
|
|
882
|
-
} catch {
|
|
883
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
884
|
-
}
|
|
885
|
-
let workingMemory = resource.workingMemory;
|
|
886
|
-
if (workingMemory === null || workingMemory === void 0) {
|
|
887
|
-
workingMemory = void 0;
|
|
888
|
-
} else if (workingMemory === "") {
|
|
889
|
-
workingMemory = "";
|
|
890
|
-
} else if (typeof workingMemory === "object") {
|
|
891
|
-
workingMemory = JSON.stringify(workingMemory);
|
|
892
|
-
}
|
|
893
|
-
let metadata = resource.metadata;
|
|
894
|
-
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
895
|
-
metadata = void 0;
|
|
896
|
-
} else if (typeof metadata === "string") {
|
|
897
|
-
try {
|
|
898
|
-
metadata = JSON.parse(metadata);
|
|
899
|
-
} catch {
|
|
900
|
-
metadata = metadata;
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
616
|
return {
|
|
904
|
-
...
|
|
905
|
-
createdAt,
|
|
906
|
-
updatedAt
|
|
907
|
-
workingMemory,
|
|
908
|
-
metadata
|
|
617
|
+
...thread,
|
|
618
|
+
createdAt: new Date(thread.createdAt),
|
|
619
|
+
updatedAt: new Date(thread.updatedAt)
|
|
909
620
|
};
|
|
910
621
|
} catch (error$1) {
|
|
911
622
|
throw new error.MastraError(
|
|
912
623
|
{
|
|
913
|
-
id: "
|
|
624
|
+
id: storage.createStorageErrorId("LANCE", "GET_THREAD_BY_ID", "FAILED"),
|
|
914
625
|
domain: error.ErrorDomain.STORAGE,
|
|
915
626
|
category: error.ErrorCategory.THIRD_PARTY
|
|
916
627
|
},
|
|
@@ -918,23 +629,21 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
918
629
|
);
|
|
919
630
|
}
|
|
920
631
|
}
|
|
921
|
-
|
|
632
|
+
/**
|
|
633
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
634
|
+
* @param thread - The thread to save
|
|
635
|
+
* @returns The saved thread
|
|
636
|
+
*/
|
|
637
|
+
async saveThread({ thread }) {
|
|
922
638
|
try {
|
|
923
|
-
const record = {
|
|
924
|
-
|
|
925
|
-
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
926
|
-
createdAt: resource.createdAt.getTime(),
|
|
927
|
-
// Store as timestamp (milliseconds)
|
|
928
|
-
updatedAt: resource.updatedAt.getTime()
|
|
929
|
-
// Store as timestamp (milliseconds)
|
|
930
|
-
};
|
|
931
|
-
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
639
|
+
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
640
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
932
641
|
await table.add([record], { mode: "append" });
|
|
933
|
-
return
|
|
642
|
+
return thread;
|
|
934
643
|
} catch (error$1) {
|
|
935
644
|
throw new error.MastraError(
|
|
936
645
|
{
|
|
937
|
-
id: "
|
|
646
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_THREAD", "FAILED"),
|
|
938
647
|
domain: error.ErrorDomain.STORAGE,
|
|
939
648
|
category: error.ErrorCategory.THIRD_PARTY
|
|
940
649
|
},
|
|
@@ -942,44 +651,32 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
942
651
|
);
|
|
943
652
|
}
|
|
944
653
|
}
|
|
945
|
-
async
|
|
946
|
-
|
|
947
|
-
|
|
654
|
+
async updateThread({
|
|
655
|
+
id,
|
|
656
|
+
title,
|
|
948
657
|
metadata
|
|
949
658
|
}) {
|
|
950
|
-
const maxRetries =
|
|
659
|
+
const maxRetries = 5;
|
|
951
660
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
952
661
|
try {
|
|
953
|
-
const
|
|
954
|
-
if (!
|
|
955
|
-
|
|
956
|
-
id: resourceId,
|
|
957
|
-
workingMemory,
|
|
958
|
-
metadata: metadata || {},
|
|
959
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
960
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
961
|
-
};
|
|
962
|
-
return this.saveResource({ resource: newResource });
|
|
662
|
+
const current = await this.getThreadById({ threadId: id });
|
|
663
|
+
if (!current) {
|
|
664
|
+
throw new Error(`Thread with id ${id} not found`);
|
|
963
665
|
}
|
|
964
|
-
const
|
|
965
|
-
...existingResource,
|
|
966
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
967
|
-
metadata: {
|
|
968
|
-
...existingResource.metadata,
|
|
969
|
-
...metadata
|
|
970
|
-
},
|
|
971
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
972
|
-
};
|
|
666
|
+
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
973
667
|
const record = {
|
|
974
|
-
id
|
|
975
|
-
|
|
976
|
-
metadata:
|
|
977
|
-
updatedAt:
|
|
978
|
-
// Store as timestamp (milliseconds)
|
|
668
|
+
id,
|
|
669
|
+
title,
|
|
670
|
+
metadata: JSON.stringify(mergedMetadata),
|
|
671
|
+
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
979
672
|
};
|
|
980
|
-
const table = await this.client.openTable(storage.
|
|
673
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
981
674
|
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
982
|
-
|
|
675
|
+
const updatedThread = await this.getThreadById({ threadId: id });
|
|
676
|
+
if (!updatedThread) {
|
|
677
|
+
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
678
|
+
}
|
|
679
|
+
return updatedThread;
|
|
983
680
|
} catch (error$1) {
|
|
984
681
|
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
985
682
|
const delay = Math.pow(2, attempt) * 10;
|
|
@@ -988,7 +685,7 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
988
685
|
}
|
|
989
686
|
throw new error.MastraError(
|
|
990
687
|
{
|
|
991
|
-
id: "
|
|
688
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
992
689
|
domain: error.ErrorDomain.STORAGE,
|
|
993
690
|
category: error.ErrorCategory.THIRD_PARTY
|
|
994
691
|
},
|
|
@@ -996,458 +693,681 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
996
693
|
);
|
|
997
694
|
}
|
|
998
695
|
}
|
|
999
|
-
throw new
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
}
|
|
1008
|
-
getDefaultValue(type) {
|
|
1009
|
-
switch (type) {
|
|
1010
|
-
case "text":
|
|
1011
|
-
return "''";
|
|
1012
|
-
case "timestamp":
|
|
1013
|
-
return "CURRENT_TIMESTAMP";
|
|
1014
|
-
case "integer":
|
|
1015
|
-
case "bigint":
|
|
1016
|
-
return "0";
|
|
1017
|
-
case "jsonb":
|
|
1018
|
-
return "'{}'";
|
|
1019
|
-
case "uuid":
|
|
1020
|
-
return "''";
|
|
1021
|
-
default:
|
|
1022
|
-
return super.getDefaultValue(type);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
async hasColumn(tableName, columnName) {
|
|
1026
|
-
const table = await this.client.openTable(tableName);
|
|
1027
|
-
const schema = await table.schema();
|
|
1028
|
-
return schema.fields.some((field) => field.name === columnName);
|
|
1029
|
-
}
|
|
1030
|
-
translateSchema(schema) {
|
|
1031
|
-
const fields = Object.entries(schema).map(([name, column]) => {
|
|
1032
|
-
let arrowType;
|
|
1033
|
-
switch (column.type.toLowerCase()) {
|
|
1034
|
-
case "text":
|
|
1035
|
-
case "uuid":
|
|
1036
|
-
arrowType = new apacheArrow.Utf8();
|
|
1037
|
-
break;
|
|
1038
|
-
case "int":
|
|
1039
|
-
case "integer":
|
|
1040
|
-
arrowType = new apacheArrow.Int32();
|
|
1041
|
-
break;
|
|
1042
|
-
case "bigint":
|
|
1043
|
-
arrowType = new apacheArrow.Float64();
|
|
1044
|
-
break;
|
|
1045
|
-
case "float":
|
|
1046
|
-
arrowType = new apacheArrow.Float32();
|
|
1047
|
-
break;
|
|
1048
|
-
case "jsonb":
|
|
1049
|
-
case "json":
|
|
1050
|
-
arrowType = new apacheArrow.Utf8();
|
|
1051
|
-
break;
|
|
1052
|
-
case "binary":
|
|
1053
|
-
arrowType = new apacheArrow.Binary();
|
|
1054
|
-
break;
|
|
1055
|
-
case "timestamp":
|
|
1056
|
-
arrowType = new apacheArrow.Float64();
|
|
1057
|
-
break;
|
|
1058
|
-
default:
|
|
1059
|
-
arrowType = new apacheArrow.Utf8();
|
|
1060
|
-
}
|
|
1061
|
-
return new apacheArrow.Field(name, arrowType, column.nullable ?? true);
|
|
1062
|
-
});
|
|
1063
|
-
return new apacheArrow.Schema(fields);
|
|
696
|
+
throw new error.MastraError(
|
|
697
|
+
{
|
|
698
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
699
|
+
domain: error.ErrorDomain.STORAGE,
|
|
700
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
701
|
+
},
|
|
702
|
+
new Error("All retries exhausted")
|
|
703
|
+
);
|
|
1064
704
|
}
|
|
1065
|
-
async
|
|
1066
|
-
tableName,
|
|
1067
|
-
schema
|
|
1068
|
-
}) {
|
|
705
|
+
async deleteThread({ threadId }) {
|
|
1069
706
|
try {
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
throw new Error("tableName is required for createTable.");
|
|
1075
|
-
}
|
|
1076
|
-
if (!schema) {
|
|
1077
|
-
throw new Error("schema is required for createTable.");
|
|
1078
|
-
}
|
|
707
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
708
|
+
await table.delete(`id = '${threadId}'`);
|
|
709
|
+
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
710
|
+
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
1079
711
|
} catch (error$1) {
|
|
1080
712
|
throw new error.MastraError(
|
|
1081
713
|
{
|
|
1082
|
-
id: "
|
|
714
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_THREAD", "FAILED"),
|
|
1083
715
|
domain: error.ErrorDomain.STORAGE,
|
|
1084
|
-
category: error.ErrorCategory.
|
|
1085
|
-
details: { tableName }
|
|
716
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1086
717
|
},
|
|
1087
718
|
error$1
|
|
1088
719
|
);
|
|
1089
720
|
}
|
|
721
|
+
}
|
|
722
|
+
normalizeMessage(message) {
|
|
723
|
+
const { thread_id, ...rest } = message;
|
|
724
|
+
return {
|
|
725
|
+
...rest,
|
|
726
|
+
threadId: thread_id,
|
|
727
|
+
content: typeof message.content === "string" ? (() => {
|
|
728
|
+
try {
|
|
729
|
+
return JSON.parse(message.content);
|
|
730
|
+
} catch {
|
|
731
|
+
return message.content;
|
|
732
|
+
}
|
|
733
|
+
})() : message.content
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
async listMessagesById({ messageIds }) {
|
|
737
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1090
738
|
try {
|
|
1091
|
-
const
|
|
1092
|
-
|
|
739
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
740
|
+
const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
|
|
741
|
+
const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
|
|
742
|
+
const messages = processResultWithTypeConversion(
|
|
743
|
+
allRecords,
|
|
744
|
+
await getTableSchema({ tableName: storage.TABLE_MESSAGES, client: this.client })
|
|
745
|
+
);
|
|
746
|
+
const list = new agent.MessageList().add(
|
|
747
|
+
messages.map(this.normalizeMessage),
|
|
748
|
+
"memory"
|
|
749
|
+
);
|
|
750
|
+
return { messages: list.get.all.db() };
|
|
1093
751
|
} catch (error$1) {
|
|
1094
|
-
if (error$1.message?.includes("already exists")) {
|
|
1095
|
-
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
1096
|
-
return;
|
|
1097
|
-
}
|
|
1098
752
|
throw new error.MastraError(
|
|
1099
753
|
{
|
|
1100
|
-
id: "
|
|
754
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1101
755
|
domain: error.ErrorDomain.STORAGE,
|
|
1102
756
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1103
|
-
details: {
|
|
757
|
+
details: {
|
|
758
|
+
messageIds: JSON.stringify(messageIds)
|
|
759
|
+
}
|
|
1104
760
|
},
|
|
1105
761
|
error$1
|
|
1106
762
|
);
|
|
1107
763
|
}
|
|
1108
764
|
}
|
|
1109
|
-
async
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
}
|
|
1114
|
-
if (!tableName) {
|
|
1115
|
-
throw new Error("tableName is required for dropTable.");
|
|
1116
|
-
}
|
|
1117
|
-
} catch (validationError) {
|
|
1118
|
-
throw new error.MastraError(
|
|
1119
|
-
{
|
|
1120
|
-
id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
|
|
1121
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1122
|
-
category: error.ErrorCategory.USER,
|
|
1123
|
-
text: validationError.message,
|
|
1124
|
-
details: { tableName }
|
|
1125
|
-
},
|
|
1126
|
-
validationError
|
|
1127
|
-
);
|
|
1128
|
-
}
|
|
1129
|
-
try {
|
|
1130
|
-
await this.client.dropTable(tableName);
|
|
1131
|
-
} catch (error$1) {
|
|
1132
|
-
if (error$1.toString().includes("was not found") || error$1.message?.includes("Table not found")) {
|
|
1133
|
-
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
1134
|
-
return;
|
|
1135
|
-
}
|
|
765
|
+
async listMessages(args) {
|
|
766
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
767
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
768
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
1136
769
|
throw new error.MastraError(
|
|
1137
770
|
{
|
|
1138
|
-
id: "
|
|
771
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1139
772
|
domain: error.ErrorDomain.STORAGE,
|
|
1140
773
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1141
|
-
details: {
|
|
774
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1142
775
|
},
|
|
1143
|
-
|
|
776
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1144
777
|
);
|
|
1145
778
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
tableName,
|
|
1149
|
-
schema,
|
|
1150
|
-
ifNotExists
|
|
1151
|
-
}) {
|
|
779
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
780
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1152
781
|
try {
|
|
1153
|
-
if (
|
|
1154
|
-
throw new
|
|
782
|
+
if (page < 0) {
|
|
783
|
+
throw new error.MastraError(
|
|
784
|
+
{
|
|
785
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
786
|
+
domain: error.ErrorDomain.STORAGE,
|
|
787
|
+
category: error.ErrorCategory.USER,
|
|
788
|
+
details: { page }
|
|
789
|
+
},
|
|
790
|
+
new Error("page must be >= 0")
|
|
791
|
+
);
|
|
1155
792
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
793
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
794
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
795
|
+
const threadCondition = threadIds.length === 1 ? `thread_id = '${this.escapeSql(threadIds[0])}'` : `thread_id IN (${threadIds.map((t) => `'${this.escapeSql(t)}'`).join(", ")})`;
|
|
796
|
+
const conditions = [threadCondition];
|
|
797
|
+
if (resourceId) {
|
|
798
|
+
conditions.push(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
1158
799
|
}
|
|
1159
|
-
if (
|
|
1160
|
-
|
|
800
|
+
if (filter?.dateRange?.start) {
|
|
801
|
+
const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
|
|
802
|
+
const startOp = filter.dateRange.startExclusive ? ">" : ">=";
|
|
803
|
+
conditions.push(`\`createdAt\` ${startOp} ${startTime}`);
|
|
1161
804
|
}
|
|
1162
|
-
if (
|
|
1163
|
-
|
|
1164
|
-
|
|
805
|
+
if (filter?.dateRange?.end) {
|
|
806
|
+
const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
|
|
807
|
+
const endOp = filter.dateRange.endExclusive ? "<" : "<=";
|
|
808
|
+
conditions.push(`\`createdAt\` ${endOp} ${endTime}`);
|
|
1165
809
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
const
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1184
|
-
integer: "int",
|
|
1185
|
-
bigint: "bigint",
|
|
1186
|
-
timestamp: "timestamp",
|
|
1187
|
-
jsonb: "string",
|
|
1188
|
-
uuid: "string"
|
|
1189
|
-
};
|
|
1190
|
-
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
1191
|
-
const colDef = schema[col];
|
|
810
|
+
const whereClause = conditions.join(" AND ");
|
|
811
|
+
const total = await table.countRows(whereClause);
|
|
812
|
+
const query = table.query().where(whereClause);
|
|
813
|
+
let allRecords = await query.toArray();
|
|
814
|
+
allRecords.sort((a, b) => {
|
|
815
|
+
const aValue = field === "createdAt" ? a.createdAt : a[field];
|
|
816
|
+
const bValue = field === "createdAt" ? b.createdAt : b[field];
|
|
817
|
+
if (aValue == null && bValue == null) return 0;
|
|
818
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
819
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
820
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
821
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
822
|
+
}
|
|
823
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
824
|
+
});
|
|
825
|
+
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
826
|
+
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
827
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
1192
828
|
return {
|
|
1193
|
-
|
|
1194
|
-
|
|
829
|
+
messages: [],
|
|
830
|
+
total: 0,
|
|
831
|
+
page,
|
|
832
|
+
perPage: perPageForResponse,
|
|
833
|
+
hasMore: false
|
|
1195
834
|
};
|
|
1196
|
-
});
|
|
1197
|
-
if (columnsToAdd.length > 0) {
|
|
1198
|
-
await table.addColumns(columnsToAdd);
|
|
1199
|
-
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
1200
835
|
}
|
|
836
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
837
|
+
if (include && include.length > 0) {
|
|
838
|
+
const threadIds2 = [...new Set(include.map((item) => item.threadId || threadId))];
|
|
839
|
+
const allThreadMessages = [];
|
|
840
|
+
for (const tid of threadIds2) {
|
|
841
|
+
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
842
|
+
let threadRecords = await threadQuery.toArray();
|
|
843
|
+
allThreadMessages.push(...threadRecords);
|
|
844
|
+
}
|
|
845
|
+
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
846
|
+
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
847
|
+
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
848
|
+
for (const includeMsg of includedMessages) {
|
|
849
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
850
|
+
messages.push(includeMsg);
|
|
851
|
+
messageIds.add(includeMsg.id);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
856
|
+
let finalMessages = list.get.all.db();
|
|
857
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
858
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
859
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
860
|
+
if (aValue == null && bValue == null) return 0;
|
|
861
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
862
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
863
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
864
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
865
|
+
}
|
|
866
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
867
|
+
});
|
|
868
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
869
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
870
|
+
const fetchedAll = perPageInput === false || allThreadMessagesReturned;
|
|
871
|
+
const hasMore = !fetchedAll && offset + perPage < total;
|
|
872
|
+
return {
|
|
873
|
+
messages: finalMessages,
|
|
874
|
+
total,
|
|
875
|
+
page,
|
|
876
|
+
perPage: perPageForResponse,
|
|
877
|
+
hasMore
|
|
878
|
+
};
|
|
1201
879
|
} catch (error$1) {
|
|
1202
|
-
|
|
880
|
+
const mastraError = new error.MastraError(
|
|
1203
881
|
{
|
|
1204
|
-
id: "
|
|
882
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "FAILED"),
|
|
1205
883
|
domain: error.ErrorDomain.STORAGE,
|
|
1206
884
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1207
|
-
details: {
|
|
885
|
+
details: {
|
|
886
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
887
|
+
resourceId: resourceId ?? ""
|
|
888
|
+
}
|
|
1208
889
|
},
|
|
1209
890
|
error$1
|
|
1210
891
|
);
|
|
892
|
+
this.logger?.error?.(mastraError.toString());
|
|
893
|
+
this.logger?.trackException?.(mastraError);
|
|
894
|
+
return {
|
|
895
|
+
messages: [],
|
|
896
|
+
total: 0,
|
|
897
|
+
page,
|
|
898
|
+
perPage: perPageForResponse,
|
|
899
|
+
hasMore: false
|
|
900
|
+
};
|
|
1211
901
|
}
|
|
1212
902
|
}
|
|
1213
|
-
async
|
|
903
|
+
async saveMessages(args) {
|
|
1214
904
|
try {
|
|
1215
|
-
|
|
1216
|
-
|
|
905
|
+
const { messages } = args;
|
|
906
|
+
if (messages.length === 0) {
|
|
907
|
+
return { messages: [] };
|
|
1217
908
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
909
|
+
const threadId = messages[0]?.threadId;
|
|
910
|
+
if (!threadId) {
|
|
911
|
+
throw new Error("Thread ID is required");
|
|
1220
912
|
}
|
|
1221
|
-
|
|
913
|
+
for (const message of messages) {
|
|
914
|
+
if (!message.id) {
|
|
915
|
+
throw new Error("Message ID is required");
|
|
916
|
+
}
|
|
917
|
+
if (!message.threadId) {
|
|
918
|
+
throw new Error("Thread ID is required for all messages");
|
|
919
|
+
}
|
|
920
|
+
if (message.resourceId === null || message.resourceId === void 0) {
|
|
921
|
+
throw new Error("Resource ID cannot be null or undefined");
|
|
922
|
+
}
|
|
923
|
+
if (!message.content) {
|
|
924
|
+
throw new Error("Message content is required");
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
const transformedMessages = messages.map((message) => {
|
|
928
|
+
const { threadId: threadId2, type, ...rest } = message;
|
|
929
|
+
return {
|
|
930
|
+
...rest,
|
|
931
|
+
thread_id: threadId2,
|
|
932
|
+
type: type ?? "v2",
|
|
933
|
+
content: JSON.stringify(message.content)
|
|
934
|
+
};
|
|
935
|
+
});
|
|
936
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
937
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
938
|
+
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
939
|
+
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
940
|
+
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
941
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
942
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
943
|
+
return { messages: list.get.all.db() };
|
|
944
|
+
} catch (error$1) {
|
|
1222
945
|
throw new error.MastraError(
|
|
1223
946
|
{
|
|
1224
|
-
id: "
|
|
947
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_MESSAGES", "FAILED"),
|
|
1225
948
|
domain: error.ErrorDomain.STORAGE,
|
|
1226
|
-
category: error.ErrorCategory.
|
|
1227
|
-
text: validationError.message,
|
|
1228
|
-
details: { tableName }
|
|
949
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1229
950
|
},
|
|
1230
|
-
|
|
951
|
+
error$1
|
|
1231
952
|
);
|
|
1232
953
|
}
|
|
954
|
+
}
|
|
955
|
+
async listThreadsByResourceId(args) {
|
|
1233
956
|
try {
|
|
1234
|
-
const
|
|
1235
|
-
|
|
957
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
958
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
959
|
+
if (page < 0) {
|
|
960
|
+
throw new error.MastraError(
|
|
961
|
+
{
|
|
962
|
+
id: storage.createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
963
|
+
domain: error.ErrorDomain.STORAGE,
|
|
964
|
+
category: error.ErrorCategory.USER,
|
|
965
|
+
details: { page }
|
|
966
|
+
},
|
|
967
|
+
new Error("page must be >= 0")
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
971
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
972
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
973
|
+
const total = await table.countRows(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
974
|
+
const query = table.query().where(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
975
|
+
const records = await query.toArray();
|
|
976
|
+
records.sort((a, b) => {
|
|
977
|
+
const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
|
|
978
|
+
const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
|
|
979
|
+
if (aValue == null && bValue == null) return 0;
|
|
980
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
981
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
982
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
983
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
984
|
+
}
|
|
985
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
986
|
+
});
|
|
987
|
+
const paginatedRecords = records.slice(offset, offset + perPage);
|
|
988
|
+
const schema = await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client });
|
|
989
|
+
const threads = paginatedRecords.map(
|
|
990
|
+
(record) => processResultWithTypeConversion(record, schema)
|
|
991
|
+
);
|
|
992
|
+
return {
|
|
993
|
+
threads,
|
|
994
|
+
total,
|
|
995
|
+
page,
|
|
996
|
+
perPage: perPageForResponse,
|
|
997
|
+
hasMore: offset + perPage < total
|
|
998
|
+
};
|
|
1236
999
|
} catch (error$1) {
|
|
1237
1000
|
throw new error.MastraError(
|
|
1238
1001
|
{
|
|
1239
|
-
id: "
|
|
1002
|
+
id: storage.createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
1240
1003
|
domain: error.ErrorDomain.STORAGE,
|
|
1241
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1242
|
-
details: { tableName }
|
|
1004
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1243
1005
|
},
|
|
1244
1006
|
error$1
|
|
1245
1007
|
);
|
|
1246
1008
|
}
|
|
1247
1009
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1010
|
+
/**
|
|
1011
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
1012
|
+
* @param records - The sorted array of records to process
|
|
1013
|
+
* @param include - The array of include specifications with context parameters
|
|
1014
|
+
* @returns The processed array with context messages included
|
|
1015
|
+
*/
|
|
1016
|
+
processMessagesWithContext(records, include) {
|
|
1017
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
1018
|
+
if (messagesWithContext.length === 0) {
|
|
1019
|
+
return records;
|
|
1020
|
+
}
|
|
1021
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1022
|
+
records.forEach((message, index) => {
|
|
1023
|
+
messageIndexMap.set(message.id, index);
|
|
1024
|
+
});
|
|
1025
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
1026
|
+
for (const item of messagesWithContext) {
|
|
1027
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
1028
|
+
if (messageIndex !== void 0) {
|
|
1029
|
+
if (item.withPreviousMessages) {
|
|
1030
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
1031
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
1032
|
+
additionalIndices.add(i);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
if (item.withNextMessages) {
|
|
1036
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
1037
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
1038
|
+
additionalIndices.add(i);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1255
1041
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1042
|
+
}
|
|
1043
|
+
if (additionalIndices.size === 0) {
|
|
1044
|
+
return records;
|
|
1045
|
+
}
|
|
1046
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1047
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
1048
|
+
records.forEach((record, index) => {
|
|
1049
|
+
if (originalMatchIds.has(record.id)) {
|
|
1050
|
+
allIndices.add(index);
|
|
1258
1051
|
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1052
|
+
});
|
|
1053
|
+
additionalIndices.forEach((index) => {
|
|
1054
|
+
allIndices.add(index);
|
|
1055
|
+
});
|
|
1056
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Parse message data from LanceDB record format to MastraDBMessage format
|
|
1060
|
+
*/
|
|
1061
|
+
parseMessageData(data) {
|
|
1062
|
+
const { thread_id, ...rest } = data;
|
|
1063
|
+
return {
|
|
1064
|
+
...rest,
|
|
1065
|
+
threadId: thread_id,
|
|
1066
|
+
content: typeof data.content === "string" ? (() => {
|
|
1067
|
+
try {
|
|
1068
|
+
return JSON.parse(data.content);
|
|
1069
|
+
} catch {
|
|
1070
|
+
return data.content;
|
|
1071
|
+
}
|
|
1072
|
+
})() : data.content,
|
|
1073
|
+
createdAt: new Date(data.createdAt),
|
|
1074
|
+
updatedAt: new Date(data.updatedAt)
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
async updateMessages(args) {
|
|
1078
|
+
const { messages } = args;
|
|
1079
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1080
|
+
if (!messages.length) {
|
|
1081
|
+
return [];
|
|
1270
1082
|
}
|
|
1083
|
+
const updatedMessages = [];
|
|
1084
|
+
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
1271
1085
|
try {
|
|
1272
|
-
const
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1086
|
+
for (const updateData of messages) {
|
|
1087
|
+
const { id, ...updates } = updateData;
|
|
1088
|
+
const existingMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
1089
|
+
if (!existingMessage) {
|
|
1090
|
+
this.logger.warn("Message not found for update", { id });
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
const existingMsg = this.parseMessageData(existingMessage);
|
|
1094
|
+
const originalThreadId = existingMsg.threadId;
|
|
1095
|
+
affectedThreadIds.add(originalThreadId);
|
|
1096
|
+
const updatePayload = {};
|
|
1097
|
+
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
1098
|
+
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
1099
|
+
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
1100
|
+
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
1101
|
+
updatePayload.thread_id = updates.threadId;
|
|
1102
|
+
affectedThreadIds.add(updates.threadId);
|
|
1103
|
+
}
|
|
1104
|
+
if (updates.content) {
|
|
1105
|
+
const existingContent = existingMsg.content;
|
|
1106
|
+
let newContent = { ...existingContent };
|
|
1107
|
+
if (updates.content.metadata !== void 0) {
|
|
1108
|
+
newContent.metadata = {
|
|
1109
|
+
...existingContent.metadata || {},
|
|
1110
|
+
...updates.content.metadata || {}
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
if (updates.content.content !== void 0) {
|
|
1114
|
+
newContent.content = updates.content.content;
|
|
1115
|
+
}
|
|
1116
|
+
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
1117
|
+
newContent.parts = updates.content.parts;
|
|
1118
|
+
}
|
|
1119
|
+
updatePayload.content = JSON.stringify(newContent);
|
|
1120
|
+
}
|
|
1121
|
+
await this.#db.insert({ tableName: storage.TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
1122
|
+
const updatedMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
1123
|
+
if (updatedMessage) {
|
|
1124
|
+
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
1279
1125
|
}
|
|
1280
1126
|
}
|
|
1281
|
-
|
|
1282
|
-
|
|
1127
|
+
for (const threadId of affectedThreadIds) {
|
|
1128
|
+
await this.#db.insert({
|
|
1129
|
+
tableName: storage.TABLE_THREADS,
|
|
1130
|
+
record: { id: threadId, updatedAt: Date.now() }
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
return updatedMessages;
|
|
1283
1134
|
} catch (error$1) {
|
|
1284
1135
|
throw new error.MastraError(
|
|
1285
1136
|
{
|
|
1286
|
-
id: "
|
|
1137
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_MESSAGES", "FAILED"),
|
|
1287
1138
|
domain: error.ErrorDomain.STORAGE,
|
|
1288
1139
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1289
|
-
details: {
|
|
1140
|
+
details: { count: messages.length }
|
|
1290
1141
|
},
|
|
1291
1142
|
error$1
|
|
1292
1143
|
);
|
|
1293
1144
|
}
|
|
1294
1145
|
}
|
|
1295
|
-
async
|
|
1146
|
+
async getResourceById({ resourceId }) {
|
|
1296
1147
|
try {
|
|
1297
|
-
|
|
1298
|
-
|
|
1148
|
+
const resource = await this.#db.load({ tableName: storage.TABLE_RESOURCES, keys: { id: resourceId } });
|
|
1149
|
+
if (!resource) {
|
|
1150
|
+
return null;
|
|
1299
1151
|
}
|
|
1300
|
-
|
|
1301
|
-
|
|
1152
|
+
let createdAt;
|
|
1153
|
+
let updatedAt;
|
|
1154
|
+
try {
|
|
1155
|
+
if (resource.createdAt instanceof Date) {
|
|
1156
|
+
createdAt = resource.createdAt;
|
|
1157
|
+
} else if (typeof resource.createdAt === "string") {
|
|
1158
|
+
createdAt = new Date(resource.createdAt);
|
|
1159
|
+
} else if (typeof resource.createdAt === "number") {
|
|
1160
|
+
createdAt = new Date(resource.createdAt);
|
|
1161
|
+
} else {
|
|
1162
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1163
|
+
}
|
|
1164
|
+
if (isNaN(createdAt.getTime())) {
|
|
1165
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1166
|
+
}
|
|
1167
|
+
} catch {
|
|
1168
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1302
1169
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1170
|
+
try {
|
|
1171
|
+
if (resource.updatedAt instanceof Date) {
|
|
1172
|
+
updatedAt = resource.updatedAt;
|
|
1173
|
+
} else if (typeof resource.updatedAt === "string") {
|
|
1174
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1175
|
+
} else if (typeof resource.updatedAt === "number") {
|
|
1176
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1177
|
+
} else {
|
|
1178
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1179
|
+
}
|
|
1180
|
+
if (isNaN(updatedAt.getTime())) {
|
|
1181
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1182
|
+
}
|
|
1183
|
+
} catch {
|
|
1184
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1305
1185
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
const processedRecord = { ...record };
|
|
1323
|
-
for (const key in processedRecord) {
|
|
1324
|
-
if (processedRecord[key] == null) continue;
|
|
1325
|
-
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
1326
|
-
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
1327
|
-
}
|
|
1186
|
+
let workingMemory = resource.workingMemory;
|
|
1187
|
+
if (workingMemory === null || workingMemory === void 0) {
|
|
1188
|
+
workingMemory = void 0;
|
|
1189
|
+
} else if (workingMemory === "") {
|
|
1190
|
+
workingMemory = "";
|
|
1191
|
+
} else if (typeof workingMemory === "object") {
|
|
1192
|
+
workingMemory = JSON.stringify(workingMemory);
|
|
1193
|
+
}
|
|
1194
|
+
let metadata = resource.metadata;
|
|
1195
|
+
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
1196
|
+
metadata = void 0;
|
|
1197
|
+
} else if (typeof metadata === "string") {
|
|
1198
|
+
try {
|
|
1199
|
+
metadata = JSON.parse(metadata);
|
|
1200
|
+
} catch {
|
|
1201
|
+
metadata = metadata;
|
|
1328
1202
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
...resource,
|
|
1206
|
+
createdAt,
|
|
1207
|
+
updatedAt,
|
|
1208
|
+
workingMemory,
|
|
1209
|
+
metadata
|
|
1210
|
+
};
|
|
1332
1211
|
} catch (error$1) {
|
|
1333
1212
|
throw new error.MastraError(
|
|
1334
1213
|
{
|
|
1335
|
-
id: "
|
|
1214
|
+
id: storage.createStorageErrorId("LANCE", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
1336
1215
|
domain: error.ErrorDomain.STORAGE,
|
|
1337
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1338
|
-
details: { tableName }
|
|
1216
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1339
1217
|
},
|
|
1340
1218
|
error$1
|
|
1341
1219
|
);
|
|
1342
1220
|
}
|
|
1343
1221
|
}
|
|
1344
|
-
async
|
|
1345
|
-
try {
|
|
1346
|
-
if (!this.client) {
|
|
1347
|
-
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1348
|
-
}
|
|
1349
|
-
if (!tableName) {
|
|
1350
|
-
throw new Error("tableName is required for load.");
|
|
1351
|
-
}
|
|
1352
|
-
if (!keys || Object.keys(keys).length === 0) {
|
|
1353
|
-
throw new Error("keys are required and cannot be empty for load.");
|
|
1354
|
-
}
|
|
1355
|
-
} catch (validationError) {
|
|
1356
|
-
throw new error.MastraError(
|
|
1357
|
-
{
|
|
1358
|
-
id: "STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS",
|
|
1359
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1360
|
-
category: error.ErrorCategory.USER,
|
|
1361
|
-
text: validationError.message,
|
|
1362
|
-
details: { tableName }
|
|
1363
|
-
},
|
|
1364
|
-
validationError
|
|
1365
|
-
);
|
|
1366
|
-
}
|
|
1222
|
+
async saveResource({ resource }) {
|
|
1367
1223
|
try {
|
|
1368
|
-
const
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
return `${quotedKey} IS NULL`;
|
|
1380
|
-
} else {
|
|
1381
|
-
return `${quotedKey} = ${value}`;
|
|
1382
|
-
}
|
|
1383
|
-
}).join(" AND ");
|
|
1384
|
-
this.logger.debug("where clause generated: " + filterConditions);
|
|
1385
|
-
query.where(filterConditions);
|
|
1386
|
-
}
|
|
1387
|
-
const result = await query.limit(1).toArray();
|
|
1388
|
-
if (result.length === 0) {
|
|
1389
|
-
this.logger.debug("No record found");
|
|
1390
|
-
return null;
|
|
1391
|
-
}
|
|
1392
|
-
return processResultWithTypeConversion(result[0], tableSchema);
|
|
1224
|
+
const record = {
|
|
1225
|
+
...resource,
|
|
1226
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
1227
|
+
createdAt: resource.createdAt.getTime(),
|
|
1228
|
+
// Store as timestamp (milliseconds)
|
|
1229
|
+
updatedAt: resource.updatedAt.getTime()
|
|
1230
|
+
// Store as timestamp (milliseconds)
|
|
1231
|
+
};
|
|
1232
|
+
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
1233
|
+
await table.add([record], { mode: "append" });
|
|
1234
|
+
return resource;
|
|
1393
1235
|
} catch (error$1) {
|
|
1394
|
-
if (error$1 instanceof error.MastraError) throw error$1;
|
|
1395
1236
|
throw new error.MastraError(
|
|
1396
1237
|
{
|
|
1397
|
-
id: "
|
|
1238
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_RESOURCE", "FAILED"),
|
|
1398
1239
|
domain: error.ErrorDomain.STORAGE,
|
|
1399
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1400
|
-
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
1240
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1401
1241
|
},
|
|
1402
1242
|
error$1
|
|
1403
1243
|
);
|
|
1404
1244
|
}
|
|
1405
1245
|
}
|
|
1246
|
+
async updateResource({
|
|
1247
|
+
resourceId,
|
|
1248
|
+
workingMemory,
|
|
1249
|
+
metadata
|
|
1250
|
+
}) {
|
|
1251
|
+
const maxRetries = 3;
|
|
1252
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1253
|
+
try {
|
|
1254
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1255
|
+
if (!existingResource) {
|
|
1256
|
+
const newResource = {
|
|
1257
|
+
id: resourceId,
|
|
1258
|
+
workingMemory,
|
|
1259
|
+
metadata: metadata || {},
|
|
1260
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1261
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1262
|
+
};
|
|
1263
|
+
return this.saveResource({ resource: newResource });
|
|
1264
|
+
}
|
|
1265
|
+
const updatedResource = {
|
|
1266
|
+
...existingResource,
|
|
1267
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1268
|
+
metadata: {
|
|
1269
|
+
...existingResource.metadata,
|
|
1270
|
+
...metadata
|
|
1271
|
+
},
|
|
1272
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1273
|
+
};
|
|
1274
|
+
const record = {
|
|
1275
|
+
id: resourceId,
|
|
1276
|
+
workingMemory: updatedResource.workingMemory || "",
|
|
1277
|
+
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
1278
|
+
updatedAt: updatedResource.updatedAt.getTime()
|
|
1279
|
+
// Store as timestamp (milliseconds)
|
|
1280
|
+
};
|
|
1281
|
+
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
1282
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1283
|
+
return updatedResource;
|
|
1284
|
+
} catch (error$1) {
|
|
1285
|
+
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
1286
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
1287
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1288
|
+
continue;
|
|
1289
|
+
}
|
|
1290
|
+
throw new error.MastraError(
|
|
1291
|
+
{
|
|
1292
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_RESOURCE", "FAILED"),
|
|
1293
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1294
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1295
|
+
},
|
|
1296
|
+
error$1
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
throw new Error("Unexpected end of retry loop");
|
|
1301
|
+
}
|
|
1406
1302
|
};
|
|
1407
1303
|
var StoreScoresLance = class extends storage.ScoresStorage {
|
|
1408
1304
|
client;
|
|
1409
|
-
|
|
1305
|
+
#db;
|
|
1306
|
+
constructor(config) {
|
|
1410
1307
|
super();
|
|
1308
|
+
const client = resolveLanceConfig(config);
|
|
1411
1309
|
this.client = client;
|
|
1310
|
+
this.#db = new LanceDB({ client });
|
|
1311
|
+
}
|
|
1312
|
+
async init() {
|
|
1313
|
+
await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.SCORERS_SCHEMA });
|
|
1314
|
+
await this.#db.alterTable({
|
|
1315
|
+
tableName: storage.TABLE_SCORERS,
|
|
1316
|
+
schema: storage.SCORERS_SCHEMA,
|
|
1317
|
+
ifNotExists: ["spanId", "requestContext"]
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
async dangerouslyClearAll() {
|
|
1321
|
+
await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
|
|
1412
1322
|
}
|
|
1413
1323
|
async saveScore(score) {
|
|
1414
1324
|
let validatedScore;
|
|
1415
1325
|
try {
|
|
1416
|
-
validatedScore =
|
|
1326
|
+
validatedScore = evals.saveScorePayloadSchema.parse(score);
|
|
1417
1327
|
} catch (error$1) {
|
|
1418
1328
|
throw new error.MastraError(
|
|
1419
1329
|
{
|
|
1420
|
-
id: "
|
|
1330
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
1421
1331
|
text: "Failed to save score in LanceStorage",
|
|
1422
1332
|
domain: error.ErrorDomain.STORAGE,
|
|
1423
|
-
category: error.ErrorCategory.
|
|
1333
|
+
category: error.ErrorCategory.USER,
|
|
1334
|
+
details: {
|
|
1335
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
1336
|
+
entityId: score.entityId ?? "unknown",
|
|
1337
|
+
entityType: score.entityType ?? "unknown",
|
|
1338
|
+
traceId: score.traceId ?? "",
|
|
1339
|
+
spanId: score.spanId ?? ""
|
|
1340
|
+
}
|
|
1424
1341
|
},
|
|
1425
1342
|
error$1
|
|
1426
1343
|
);
|
|
1427
1344
|
}
|
|
1345
|
+
const id = crypto.randomUUID();
|
|
1346
|
+
const now = /* @__PURE__ */ new Date();
|
|
1428
1347
|
try {
|
|
1429
|
-
const id = crypto.randomUUID();
|
|
1430
1348
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1431
1349
|
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1432
1350
|
const allowedFields = new Set(schema.fields.map((f) => f.name));
|
|
1433
1351
|
const filteredScore = {};
|
|
1434
|
-
Object.keys(validatedScore)
|
|
1352
|
+
for (const key of Object.keys(validatedScore)) {
|
|
1435
1353
|
if (allowedFields.has(key)) {
|
|
1436
|
-
filteredScore[key] =
|
|
1354
|
+
filteredScore[key] = validatedScore[key];
|
|
1437
1355
|
}
|
|
1438
|
-
}
|
|
1356
|
+
}
|
|
1439
1357
|
for (const key in filteredScore) {
|
|
1440
1358
|
if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
|
|
1441
1359
|
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
1442
1360
|
}
|
|
1443
1361
|
}
|
|
1444
1362
|
filteredScore.id = id;
|
|
1363
|
+
filteredScore.createdAt = now;
|
|
1364
|
+
filteredScore.updatedAt = now;
|
|
1445
1365
|
await table.add([filteredScore], { mode: "append" });
|
|
1446
|
-
return { score };
|
|
1366
|
+
return { score: { ...validatedScore, id, createdAt: now, updatedAt: now } };
|
|
1447
1367
|
} catch (error$1) {
|
|
1448
1368
|
throw new error.MastraError(
|
|
1449
1369
|
{
|
|
1450
|
-
id: "
|
|
1370
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_SCORE", "FAILED"),
|
|
1451
1371
|
text: "Failed to save score in LanceStorage",
|
|
1452
1372
|
domain: error.ErrorDomain.STORAGE,
|
|
1453
1373
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1463,12 +1383,11 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1463
1383
|
const query = table.query().where(`id = '${id}'`).limit(1);
|
|
1464
1384
|
const records = await query.toArray();
|
|
1465
1385
|
if (records.length === 0) return null;
|
|
1466
|
-
|
|
1467
|
-
return processResultWithTypeConversion(records[0], schema);
|
|
1386
|
+
return await this.transformScoreRow(records[0]);
|
|
1468
1387
|
} catch (error$1) {
|
|
1469
1388
|
throw new error.MastraError(
|
|
1470
1389
|
{
|
|
1471
|
-
id: "
|
|
1390
|
+
id: storage.createStorageErrorId("LANCE", "GET_SCORE_BY_ID", "FAILED"),
|
|
1472
1391
|
text: "Failed to get score by id in LanceStorage",
|
|
1473
1392
|
domain: error.ErrorDomain.STORAGE,
|
|
1474
1393
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1478,7 +1397,23 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1478
1397
|
);
|
|
1479
1398
|
}
|
|
1480
1399
|
}
|
|
1481
|
-
|
|
1400
|
+
/**
|
|
1401
|
+
* LanceDB-specific score row transformation.
|
|
1402
|
+
*
|
|
1403
|
+
* Note: This implementation does NOT use coreTransformScoreRow because:
|
|
1404
|
+
* 1. LanceDB stores schema information in the table itself (requires async fetch)
|
|
1405
|
+
* 2. Uses processResultWithTypeConversion utility for LanceDB-specific type handling
|
|
1406
|
+
*/
|
|
1407
|
+
async transformScoreRow(row) {
|
|
1408
|
+
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1409
|
+
const transformed = processResultWithTypeConversion(row, schema);
|
|
1410
|
+
return {
|
|
1411
|
+
...transformed,
|
|
1412
|
+
createdAt: row.createdAt,
|
|
1413
|
+
updatedAt: row.updatedAt
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
async listScoresByScorerId({
|
|
1482
1417
|
scorerId,
|
|
1483
1418
|
pagination,
|
|
1484
1419
|
entityId,
|
|
@@ -1486,9 +1421,10 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1486
1421
|
source
|
|
1487
1422
|
}) {
|
|
1488
1423
|
try {
|
|
1424
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1425
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1426
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1489
1427
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1490
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
1491
|
-
const offset = page * perPage;
|
|
1492
1428
|
let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1493
1429
|
if (source) {
|
|
1494
1430
|
query = query.where(`\`source\` = '${source}'`);
|
|
@@ -1499,30 +1435,38 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1499
1435
|
if (entityType) {
|
|
1500
1436
|
query = query.where(`\`entityType\` = '${entityType}'`);
|
|
1501
1437
|
}
|
|
1502
|
-
query = query.limit(perPage);
|
|
1503
|
-
if (offset > 0) query.offset(offset);
|
|
1504
|
-
const records = await query.toArray();
|
|
1505
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1506
|
-
const scores = processResultWithTypeConversion(records, schema);
|
|
1507
1438
|
let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1508
1439
|
if (source) {
|
|
1509
1440
|
totalQuery = totalQuery.where(`\`source\` = '${source}'`);
|
|
1510
1441
|
}
|
|
1442
|
+
if (entityId) {
|
|
1443
|
+
totalQuery = totalQuery.where(`\`entityId\` = '${entityId}'`);
|
|
1444
|
+
}
|
|
1445
|
+
if (entityType) {
|
|
1446
|
+
totalQuery = totalQuery.where(`\`entityType\` = '${entityType}'`);
|
|
1447
|
+
}
|
|
1511
1448
|
const allRecords = await totalQuery.toArray();
|
|
1512
1449
|
const total = allRecords.length;
|
|
1450
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1451
|
+
if (perPageInput !== false) {
|
|
1452
|
+
query = query.limit(perPage);
|
|
1453
|
+
if (start > 0) query = query.offset(start);
|
|
1454
|
+
}
|
|
1455
|
+
const records = await query.toArray();
|
|
1456
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1513
1457
|
return {
|
|
1514
1458
|
pagination: {
|
|
1515
1459
|
page,
|
|
1516
|
-
perPage,
|
|
1460
|
+
perPage: perPageForResponse,
|
|
1517
1461
|
total,
|
|
1518
|
-
hasMore:
|
|
1462
|
+
hasMore: end < total
|
|
1519
1463
|
},
|
|
1520
1464
|
scores
|
|
1521
1465
|
};
|
|
1522
1466
|
} catch (error$1) {
|
|
1523
1467
|
throw new error.MastraError(
|
|
1524
1468
|
{
|
|
1525
|
-
id: "
|
|
1469
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
|
|
1526
1470
|
text: "Failed to get scores by scorerId in LanceStorage",
|
|
1527
1471
|
domain: error.ErrorDomain.STORAGE,
|
|
1528
1472
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1532,34 +1476,38 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1532
1476
|
);
|
|
1533
1477
|
}
|
|
1534
1478
|
}
|
|
1535
|
-
async
|
|
1479
|
+
async listScoresByRunId({
|
|
1536
1480
|
runId,
|
|
1537
1481
|
pagination
|
|
1538
1482
|
}) {
|
|
1539
1483
|
try {
|
|
1484
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1485
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1486
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1540
1487
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1541
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
1542
|
-
const offset = page * perPage;
|
|
1543
|
-
const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
|
|
1544
|
-
if (offset > 0) query.offset(offset);
|
|
1545
|
-
const records = await query.toArray();
|
|
1546
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1547
|
-
const scores = processResultWithTypeConversion(records, schema);
|
|
1548
1488
|
const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
|
|
1549
1489
|
const total = allRecords.length;
|
|
1490
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1491
|
+
let query = table.query().where(`\`runId\` = '${runId}'`);
|
|
1492
|
+
if (perPageInput !== false) {
|
|
1493
|
+
query = query.limit(perPage);
|
|
1494
|
+
if (start > 0) query = query.offset(start);
|
|
1495
|
+
}
|
|
1496
|
+
const records = await query.toArray();
|
|
1497
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1550
1498
|
return {
|
|
1551
1499
|
pagination: {
|
|
1552
1500
|
page,
|
|
1553
|
-
perPage,
|
|
1501
|
+
perPage: perPageForResponse,
|
|
1554
1502
|
total,
|
|
1555
|
-
hasMore:
|
|
1503
|
+
hasMore: end < total
|
|
1556
1504
|
},
|
|
1557
1505
|
scores
|
|
1558
1506
|
};
|
|
1559
1507
|
} catch (error$1) {
|
|
1560
1508
|
throw new error.MastraError(
|
|
1561
1509
|
{
|
|
1562
|
-
id: "
|
|
1510
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_RUN_ID", "FAILED"),
|
|
1563
1511
|
text: "Failed to get scores by runId in LanceStorage",
|
|
1564
1512
|
domain: error.ErrorDomain.STORAGE,
|
|
1565
1513
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1569,35 +1517,39 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1569
1517
|
);
|
|
1570
1518
|
}
|
|
1571
1519
|
}
|
|
1572
|
-
async
|
|
1520
|
+
async listScoresByEntityId({
|
|
1573
1521
|
entityId,
|
|
1574
1522
|
entityType,
|
|
1575
1523
|
pagination
|
|
1576
1524
|
}) {
|
|
1577
1525
|
try {
|
|
1526
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1527
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1528
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1578
1529
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1579
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
1580
|
-
const offset = page * perPage;
|
|
1581
|
-
const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
|
|
1582
|
-
if (offset > 0) query.offset(offset);
|
|
1583
|
-
const records = await query.toArray();
|
|
1584
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1585
|
-
const scores = processResultWithTypeConversion(records, schema);
|
|
1586
1530
|
const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
|
|
1587
1531
|
const total = allRecords.length;
|
|
1532
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1533
|
+
let query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`);
|
|
1534
|
+
if (perPageInput !== false) {
|
|
1535
|
+
query = query.limit(perPage);
|
|
1536
|
+
if (start > 0) query = query.offset(start);
|
|
1537
|
+
}
|
|
1538
|
+
const records = await query.toArray();
|
|
1539
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1588
1540
|
return {
|
|
1589
1541
|
pagination: {
|
|
1590
1542
|
page,
|
|
1591
|
-
perPage,
|
|
1543
|
+
perPage: perPageForResponse,
|
|
1592
1544
|
total,
|
|
1593
|
-
hasMore:
|
|
1545
|
+
hasMore: end < total
|
|
1594
1546
|
},
|
|
1595
1547
|
scores
|
|
1596
1548
|
};
|
|
1597
1549
|
} catch (error$1) {
|
|
1598
1550
|
throw new error.MastraError(
|
|
1599
1551
|
{
|
|
1600
|
-
id: "
|
|
1552
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
|
|
1601
1553
|
text: "Failed to get scores by entityId and entityType in LanceStorage",
|
|
1602
1554
|
domain: error.ErrorDomain.STORAGE,
|
|
1603
1555
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1607,35 +1559,39 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1607
1559
|
);
|
|
1608
1560
|
}
|
|
1609
1561
|
}
|
|
1610
|
-
async
|
|
1562
|
+
async listScoresBySpan({
|
|
1611
1563
|
traceId,
|
|
1612
1564
|
spanId,
|
|
1613
1565
|
pagination
|
|
1614
1566
|
}) {
|
|
1615
1567
|
try {
|
|
1568
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1569
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1570
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1616
1571
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1617
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
1618
|
-
const offset = page * perPage;
|
|
1619
|
-
const query = table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).limit(perPage);
|
|
1620
|
-
if (offset > 0) query.offset(offset);
|
|
1621
|
-
const records = await query.toArray();
|
|
1622
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1623
|
-
const scores = processResultWithTypeConversion(records, schema);
|
|
1624
1572
|
const allRecords = await table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).toArray();
|
|
1625
1573
|
const total = allRecords.length;
|
|
1574
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1575
|
+
let query = table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`);
|
|
1576
|
+
if (perPageInput !== false) {
|
|
1577
|
+
query = query.limit(perPage);
|
|
1578
|
+
if (start > 0) query = query.offset(start);
|
|
1579
|
+
}
|
|
1580
|
+
const records = await query.toArray();
|
|
1581
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1626
1582
|
return {
|
|
1627
1583
|
pagination: {
|
|
1628
1584
|
page,
|
|
1629
|
-
perPage,
|
|
1585
|
+
perPage: perPageForResponse,
|
|
1630
1586
|
total,
|
|
1631
|
-
hasMore:
|
|
1587
|
+
hasMore: end < total
|
|
1632
1588
|
},
|
|
1633
1589
|
scores
|
|
1634
1590
|
};
|
|
1635
1591
|
} catch (error$1) {
|
|
1636
1592
|
throw new error.MastraError(
|
|
1637
1593
|
{
|
|
1638
|
-
id: "
|
|
1594
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_SPAN", "FAILED"),
|
|
1639
1595
|
text: "Failed to get scores by traceId and spanId in LanceStorage",
|
|
1640
1596
|
domain: error.ErrorDomain.STORAGE,
|
|
1641
1597
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1646,6 +1602,9 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1646
1602
|
}
|
|
1647
1603
|
}
|
|
1648
1604
|
};
|
|
1605
|
+
function escapeSql(str) {
|
|
1606
|
+
return str.replace(/'/g, "''");
|
|
1607
|
+
}
|
|
1649
1608
|
function parseWorkflowRun(row) {
|
|
1650
1609
|
let parsedSnapshot = row.snapshot;
|
|
1651
1610
|
if (typeof parsedSnapshot === "string") {
|
|
@@ -1666,56 +1625,104 @@ function parseWorkflowRun(row) {
|
|
|
1666
1625
|
}
|
|
1667
1626
|
var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
1668
1627
|
client;
|
|
1669
|
-
|
|
1628
|
+
#db;
|
|
1629
|
+
constructor(config) {
|
|
1670
1630
|
super();
|
|
1631
|
+
const client = resolveLanceConfig(config);
|
|
1671
1632
|
this.client = client;
|
|
1633
|
+
this.#db = new LanceDB({ client });
|
|
1634
|
+
}
|
|
1635
|
+
async init() {
|
|
1636
|
+
const schema = storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
1637
|
+
await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema });
|
|
1638
|
+
await this.#db.alterTable({
|
|
1639
|
+
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1640
|
+
schema,
|
|
1641
|
+
ifNotExists: ["resourceId"]
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
async dangerouslyClearAll() {
|
|
1645
|
+
await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
1672
1646
|
}
|
|
1673
|
-
updateWorkflowResults({
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1647
|
+
async updateWorkflowResults({
|
|
1648
|
+
workflowName,
|
|
1649
|
+
runId,
|
|
1650
|
+
stepId,
|
|
1651
|
+
result,
|
|
1652
|
+
requestContext
|
|
1679
1653
|
}) {
|
|
1680
|
-
|
|
1654
|
+
let snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
1655
|
+
if (!snapshot) {
|
|
1656
|
+
snapshot = {
|
|
1657
|
+
context: {},
|
|
1658
|
+
activePaths: [],
|
|
1659
|
+
timestamp: Date.now(),
|
|
1660
|
+
suspendedPaths: {},
|
|
1661
|
+
activeStepsPath: {},
|
|
1662
|
+
resumeLabels: {},
|
|
1663
|
+
serializedStepGraph: [],
|
|
1664
|
+
status: "pending",
|
|
1665
|
+
value: {},
|
|
1666
|
+
waitingPaths: {},
|
|
1667
|
+
runId,
|
|
1668
|
+
requestContext: {}
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
snapshot.context[stepId] = result;
|
|
1672
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
1673
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
1674
|
+
return snapshot.context;
|
|
1681
1675
|
}
|
|
1682
|
-
updateWorkflowState({
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1676
|
+
async updateWorkflowState({
|
|
1677
|
+
workflowName,
|
|
1678
|
+
runId,
|
|
1679
|
+
opts
|
|
1686
1680
|
}) {
|
|
1687
|
-
|
|
1681
|
+
const snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
1682
|
+
if (!snapshot) {
|
|
1683
|
+
return void 0;
|
|
1684
|
+
}
|
|
1685
|
+
if (!snapshot.context) {
|
|
1686
|
+
throw new Error(`Snapshot not found for runId ${runId}`);
|
|
1687
|
+
}
|
|
1688
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
1689
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
|
|
1690
|
+
return updatedSnapshot;
|
|
1688
1691
|
}
|
|
1689
1692
|
async persistWorkflowSnapshot({
|
|
1690
1693
|
workflowName,
|
|
1691
1694
|
runId,
|
|
1692
1695
|
resourceId,
|
|
1693
|
-
snapshot
|
|
1696
|
+
snapshot,
|
|
1697
|
+
createdAt,
|
|
1698
|
+
updatedAt
|
|
1694
1699
|
}) {
|
|
1695
1700
|
try {
|
|
1696
1701
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1697
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1702
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1698
1703
|
const records = await query.toArray();
|
|
1699
|
-
let
|
|
1700
|
-
const now = Date.now();
|
|
1704
|
+
let createdAtValue;
|
|
1705
|
+
const now = createdAt?.getTime() ?? Date.now();
|
|
1701
1706
|
if (records.length > 0) {
|
|
1702
|
-
|
|
1707
|
+
createdAtValue = records[0].createdAt ?? now;
|
|
1703
1708
|
} else {
|
|
1704
|
-
|
|
1709
|
+
createdAtValue = now;
|
|
1705
1710
|
}
|
|
1711
|
+
const { status, value, ...rest } = snapshot;
|
|
1706
1712
|
const record = {
|
|
1707
1713
|
workflow_name: workflowName,
|
|
1708
1714
|
run_id: runId,
|
|
1709
1715
|
resourceId,
|
|
1710
|
-
snapshot: JSON.stringify(
|
|
1711
|
-
|
|
1712
|
-
|
|
1716
|
+
snapshot: JSON.stringify({ status, value, ...rest }),
|
|
1717
|
+
// this is to ensure status is always just before value, for when querying the db by status
|
|
1718
|
+
createdAt: createdAtValue,
|
|
1719
|
+
updatedAt: updatedAt ?? now
|
|
1713
1720
|
};
|
|
1714
1721
|
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1715
1722
|
} catch (error$1) {
|
|
1716
1723
|
throw new error.MastraError(
|
|
1717
1724
|
{
|
|
1718
|
-
id: "
|
|
1725
|
+
id: storage.createStorageErrorId("LANCE", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1719
1726
|
domain: error.ErrorDomain.STORAGE,
|
|
1720
1727
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1721
1728
|
details: { workflowName, runId }
|
|
@@ -1730,13 +1737,13 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1730
1737
|
}) {
|
|
1731
1738
|
try {
|
|
1732
1739
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1733
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1740
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1734
1741
|
const records = await query.toArray();
|
|
1735
1742
|
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1736
1743
|
} catch (error$1) {
|
|
1737
1744
|
throw new error.MastraError(
|
|
1738
1745
|
{
|
|
1739
|
-
id: "
|
|
1746
|
+
id: storage.createStorageErrorId("LANCE", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1740
1747
|
domain: error.ErrorDomain.STORAGE,
|
|
1741
1748
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1742
1749
|
details: { workflowName, runId }
|
|
@@ -1748,9 +1755,9 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1748
1755
|
async getWorkflowRunById(args) {
|
|
1749
1756
|
try {
|
|
1750
1757
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1751
|
-
let whereClause = `run_id = '${args.runId}'`;
|
|
1758
|
+
let whereClause = `run_id = '${escapeSql(args.runId)}'`;
|
|
1752
1759
|
if (args.workflowName) {
|
|
1753
|
-
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
1760
|
+
whereClause += ` AND workflow_name = '${escapeSql(args.workflowName)}'`;
|
|
1754
1761
|
}
|
|
1755
1762
|
const query = table.query().where(whereClause);
|
|
1756
1763
|
const records = await query.toArray();
|
|
@@ -1760,7 +1767,7 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1760
1767
|
} catch (error$1) {
|
|
1761
1768
|
throw new error.MastraError(
|
|
1762
1769
|
{
|
|
1763
|
-
id: "
|
|
1770
|
+
id: storage.createStorageErrorId("LANCE", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1764
1771
|
domain: error.ErrorDomain.STORAGE,
|
|
1765
1772
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1766
1773
|
details: { runId: args.runId, workflowName: args.workflowName ?? "" }
|
|
@@ -1769,16 +1776,37 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1769
1776
|
);
|
|
1770
1777
|
}
|
|
1771
1778
|
}
|
|
1779
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
1780
|
+
try {
|
|
1781
|
+
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1782
|
+
const whereClause = `run_id = '${escapeSql(runId)}' AND workflow_name = '${escapeSql(workflowName)}'`;
|
|
1783
|
+
await table.delete(whereClause);
|
|
1784
|
+
} catch (error$1) {
|
|
1785
|
+
throw new error.MastraError(
|
|
1786
|
+
{
|
|
1787
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1788
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1789
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1790
|
+
details: { runId, workflowName }
|
|
1791
|
+
},
|
|
1792
|
+
error$1
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1772
1796
|
async listWorkflowRuns(args) {
|
|
1773
1797
|
try {
|
|
1774
1798
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1775
1799
|
let query = table.query();
|
|
1776
1800
|
const conditions = [];
|
|
1777
1801
|
if (args?.workflowName) {
|
|
1778
|
-
conditions.push(`workflow_name = '${args.workflowName
|
|
1802
|
+
conditions.push(`workflow_name = '${escapeSql(args.workflowName)}'`);
|
|
1803
|
+
}
|
|
1804
|
+
if (args?.status) {
|
|
1805
|
+
const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
1806
|
+
conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
|
|
1779
1807
|
}
|
|
1780
1808
|
if (args?.resourceId) {
|
|
1781
|
-
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1809
|
+
conditions.push(`\`resourceId\` = '${escapeSql(args.resourceId)}'`);
|
|
1782
1810
|
}
|
|
1783
1811
|
if (args?.fromDate instanceof Date) {
|
|
1784
1812
|
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
@@ -1793,11 +1821,22 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1793
1821
|
} else {
|
|
1794
1822
|
total = await table.countRows();
|
|
1795
1823
|
}
|
|
1796
|
-
if (args?.
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1824
|
+
if (args?.perPage !== void 0 && args?.page !== void 0) {
|
|
1825
|
+
const normalizedPerPage = storage.normalizePerPage(args.perPage, Number.MAX_SAFE_INTEGER);
|
|
1826
|
+
if (args.page < 0 || !Number.isInteger(args.page)) {
|
|
1827
|
+
throw new error.MastraError(
|
|
1828
|
+
{
|
|
1829
|
+
id: storage.createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "INVALID_PAGINATION"),
|
|
1830
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1831
|
+
category: error.ErrorCategory.USER,
|
|
1832
|
+
details: { page: args.page, perPage: args.perPage }
|
|
1833
|
+
},
|
|
1834
|
+
new Error(`Invalid pagination parameters: page=${args.page}, perPage=${args.perPage}`)
|
|
1835
|
+
);
|
|
1836
|
+
}
|
|
1837
|
+
const offset = args.page * normalizedPerPage;
|
|
1838
|
+
query.limit(normalizedPerPage);
|
|
1839
|
+
query.offset(offset);
|
|
1801
1840
|
}
|
|
1802
1841
|
const records = await query.toArray();
|
|
1803
1842
|
return {
|
|
@@ -1807,7 +1846,7 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1807
1846
|
} catch (error$1) {
|
|
1808
1847
|
throw new error.MastraError(
|
|
1809
1848
|
{
|
|
1810
|
-
id: "
|
|
1849
|
+
id: storage.createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
1811
1850
|
domain: error.ErrorDomain.STORAGE,
|
|
1812
1851
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1813
1852
|
details: { resourceId: args?.resourceId ?? "", workflowName: args?.workflowName ?? "" }
|
|
@@ -1824,279 +1863,95 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
|
|
|
1824
1863
|
lanceClient;
|
|
1825
1864
|
/**
|
|
1826
1865
|
* Creates a new instance of LanceStorage
|
|
1866
|
+
* @param id The unique identifier for this storage instance
|
|
1867
|
+
* @param name The name for this storage instance
|
|
1827
1868
|
* @param uri The URI to connect to LanceDB
|
|
1828
|
-
* @param
|
|
1869
|
+
* @param connectionOptions connection options for LanceDB
|
|
1870
|
+
* @param storageOptions storage options including disableInit
|
|
1829
1871
|
*
|
|
1830
1872
|
* Usage:
|
|
1831
1873
|
*
|
|
1832
1874
|
* Connect to a local database
|
|
1833
1875
|
* ```ts
|
|
1834
|
-
* const store = await LanceStorage.create('/path/to/db');
|
|
1876
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db');
|
|
1835
1877
|
* ```
|
|
1836
1878
|
*
|
|
1837
1879
|
* Connect to a LanceDB cloud database
|
|
1838
1880
|
* ```ts
|
|
1839
|
-
* const store = await LanceStorage.create('db://host:port');
|
|
1881
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', 'db://host:port');
|
|
1840
1882
|
* ```
|
|
1841
1883
|
*
|
|
1842
1884
|
* Connect to a cloud database
|
|
1843
1885
|
* ```ts
|
|
1844
|
-
* const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
1886
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', 's3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
1887
|
+
* ```
|
|
1888
|
+
*
|
|
1889
|
+
* Disable auto-init for runtime (after CI/CD has run migrations)
|
|
1890
|
+
* ```ts
|
|
1891
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db', undefined, { disableInit: true });
|
|
1845
1892
|
* ```
|
|
1846
1893
|
*/
|
|
1847
|
-
static async create(name, uri,
|
|
1848
|
-
const instance = new _LanceStorage(name);
|
|
1894
|
+
static async create(id, name, uri, connectionOptions, storageOptions) {
|
|
1895
|
+
const instance = new _LanceStorage(id, name, storageOptions?.disableInit);
|
|
1849
1896
|
try {
|
|
1850
|
-
instance.lanceClient = await lancedb.connect(uri,
|
|
1851
|
-
const operations = new StoreOperationsLance({ client: instance.lanceClient });
|
|
1897
|
+
instance.lanceClient = await lancedb.connect(uri, connectionOptions);
|
|
1852
1898
|
instance.stores = {
|
|
1853
|
-
operations: new StoreOperationsLance({ client: instance.lanceClient }),
|
|
1854
1899
|
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1855
|
-
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1856
|
-
memory: new StoreMemoryLance({ client: instance.lanceClient
|
|
1857
|
-
};
|
|
1858
|
-
return instance;
|
|
1859
|
-
} catch (e) {
|
|
1860
|
-
throw new error.MastraError(
|
|
1861
|
-
{
|
|
1862
|
-
id: "
|
|
1863
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1864
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1865
|
-
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1866
|
-
details: { uri, optionsProvided: !!
|
|
1867
|
-
},
|
|
1868
|
-
e
|
|
1869
|
-
);
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
/**
|
|
1873
|
-
* @internal
|
|
1874
|
-
* Private constructor to enforce using the create factory method
|
|
1875
|
-
*/
|
|
1876
|
-
constructor(name) {
|
|
1877
|
-
super({ name });
|
|
1878
|
-
const operations = new StoreOperationsLance({ client: this.lanceClient });
|
|
1879
|
-
this.stores = {
|
|
1880
|
-
operations: new StoreOperationsLance({ client: this.lanceClient }),
|
|
1881
|
-
workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
|
|
1882
|
-
scores: new StoreScoresLance({ client: this.lanceClient }),
|
|
1883
|
-
memory: new StoreMemoryLance({ client: this.lanceClient, operations })
|
|
1884
|
-
};
|
|
1885
|
-
}
|
|
1886
|
-
async createTable({
|
|
1887
|
-
tableName,
|
|
1888
|
-
schema
|
|
1889
|
-
}) {
|
|
1890
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
1891
|
-
}
|
|
1892
|
-
async dropTable({ tableName }) {
|
|
1893
|
-
return this.stores.operations.dropTable({ tableName });
|
|
1894
|
-
}
|
|
1895
|
-
async alterTable({
|
|
1896
|
-
tableName,
|
|
1897
|
-
schema,
|
|
1898
|
-
ifNotExists
|
|
1899
|
-
}) {
|
|
1900
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
1901
|
-
}
|
|
1902
|
-
async clearTable({ tableName }) {
|
|
1903
|
-
return this.stores.operations.clearTable({ tableName });
|
|
1904
|
-
}
|
|
1905
|
-
async insert({ tableName, record }) {
|
|
1906
|
-
return this.stores.operations.insert({ tableName, record });
|
|
1907
|
-
}
|
|
1908
|
-
async batchInsert({ tableName, records }) {
|
|
1909
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
1910
|
-
}
|
|
1911
|
-
async load({ tableName, keys }) {
|
|
1912
|
-
return this.stores.operations.load({ tableName, keys });
|
|
1913
|
-
}
|
|
1914
|
-
async getThreadById({ threadId }) {
|
|
1915
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
1916
|
-
}
|
|
1917
|
-
async getThreadsByResourceId({ resourceId }) {
|
|
1918
|
-
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
1900
|
+
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1901
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient })
|
|
1902
|
+
};
|
|
1903
|
+
return instance;
|
|
1904
|
+
} catch (e) {
|
|
1905
|
+
throw new error.MastraError(
|
|
1906
|
+
{
|
|
1907
|
+
id: storage.createStorageErrorId("LANCE", "CONNECT", "FAILED"),
|
|
1908
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1909
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1910
|
+
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1911
|
+
details: { uri, optionsProvided: !!connectionOptions }
|
|
1912
|
+
},
|
|
1913
|
+
e
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1919
1916
|
}
|
|
1920
1917
|
/**
|
|
1921
|
-
*
|
|
1922
|
-
*
|
|
1923
|
-
*
|
|
1918
|
+
* Creates a new instance of LanceStorage from a pre-configured LanceDB connection.
|
|
1919
|
+
* Use this when you need to configure the connection before initialization.
|
|
1920
|
+
*
|
|
1921
|
+
* @param id The unique identifier for this storage instance
|
|
1922
|
+
* @param name The name for this storage instance
|
|
1923
|
+
* @param client Pre-configured LanceDB connection
|
|
1924
|
+
* @param options Storage options including disableInit
|
|
1925
|
+
*
|
|
1926
|
+
* @example
|
|
1927
|
+
* ```typescript
|
|
1928
|
+
* import { connect } from '@lancedb/lancedb';
|
|
1929
|
+
*
|
|
1930
|
+
* const client = await connect('/path/to/db', {
|
|
1931
|
+
* // Custom connection options
|
|
1932
|
+
* });
|
|
1933
|
+
*
|
|
1934
|
+
* const store = LanceStorage.fromClient('my-id', 'MyStorage', client);
|
|
1935
|
+
* ```
|
|
1924
1936
|
*/
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
}) {
|
|
1933
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
1934
|
-
}
|
|
1935
|
-
async deleteThread({ threadId }) {
|
|
1936
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
1937
|
-
}
|
|
1938
|
-
get supports() {
|
|
1939
|
-
return {
|
|
1940
|
-
selectByIncludeResourceScope: true,
|
|
1941
|
-
resourceWorkingMemory: true,
|
|
1942
|
-
hasColumn: true,
|
|
1943
|
-
createTable: true,
|
|
1944
|
-
deleteMessages: false,
|
|
1945
|
-
getScoresBySpan: true
|
|
1937
|
+
static fromClient(id, name, client, options) {
|
|
1938
|
+
const instance = new _LanceStorage(id, name, options?.disableInit);
|
|
1939
|
+
instance.lanceClient = client;
|
|
1940
|
+
instance.stores = {
|
|
1941
|
+
workflows: new StoreWorkflowsLance({ client }),
|
|
1942
|
+
scores: new StoreScoresLance({ client }),
|
|
1943
|
+
memory: new StoreMemoryLance({ client })
|
|
1946
1944
|
};
|
|
1947
|
-
|
|
1948
|
-
async getResourceById({ resourceId }) {
|
|
1949
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
1950
|
-
}
|
|
1951
|
-
async saveResource({ resource }) {
|
|
1952
|
-
return this.stores.memory.saveResource({ resource });
|
|
1953
|
-
}
|
|
1954
|
-
async updateResource({
|
|
1955
|
-
resourceId,
|
|
1956
|
-
workingMemory,
|
|
1957
|
-
metadata
|
|
1958
|
-
}) {
|
|
1959
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
1945
|
+
return instance;
|
|
1960
1946
|
}
|
|
1961
1947
|
/**
|
|
1962
|
-
*
|
|
1963
|
-
*
|
|
1964
|
-
*
|
|
1965
|
-
* @returns The processed array with context messages included
|
|
1948
|
+
* @internal
|
|
1949
|
+
* Private constructor to enforce using the create factory method.
|
|
1950
|
+
* Note: stores is initialized in create() after the lanceClient is connected.
|
|
1966
1951
|
*/
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
return records;
|
|
1971
|
-
}
|
|
1972
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1973
|
-
records.forEach((message, index) => {
|
|
1974
|
-
messageIndexMap.set(message.id, index);
|
|
1975
|
-
});
|
|
1976
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
1977
|
-
for (const item of messagesWithContext) {
|
|
1978
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
1979
|
-
if (messageIndex !== void 0) {
|
|
1980
|
-
if (item.withPreviousMessages) {
|
|
1981
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
1982
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
1983
|
-
additionalIndices.add(i);
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
if (item.withNextMessages) {
|
|
1987
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
1988
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
1989
|
-
additionalIndices.add(i);
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
if (additionalIndices.size === 0) {
|
|
1995
|
-
return records;
|
|
1996
|
-
}
|
|
1997
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1998
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
1999
|
-
records.forEach((record, index) => {
|
|
2000
|
-
if (originalMatchIds.has(record.id)) {
|
|
2001
|
-
allIndices.add(index);
|
|
2002
|
-
}
|
|
2003
|
-
});
|
|
2004
|
-
additionalIndices.forEach((index) => {
|
|
2005
|
-
allIndices.add(index);
|
|
2006
|
-
});
|
|
2007
|
-
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
2008
|
-
}
|
|
2009
|
-
async getMessages({
|
|
2010
|
-
threadId,
|
|
2011
|
-
resourceId,
|
|
2012
|
-
selectBy,
|
|
2013
|
-
format,
|
|
2014
|
-
threadConfig
|
|
2015
|
-
}) {
|
|
2016
|
-
return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
|
|
2017
|
-
}
|
|
2018
|
-
async saveMessages(args) {
|
|
2019
|
-
return this.stores.memory.saveMessages(args);
|
|
2020
|
-
}
|
|
2021
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
2022
|
-
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2023
|
-
}
|
|
2024
|
-
async getMessagesPaginated(args) {
|
|
2025
|
-
return this.stores.memory.getMessagesPaginated(args);
|
|
2026
|
-
}
|
|
2027
|
-
async updateMessages(_args) {
|
|
2028
|
-
return this.stores.memory.updateMessages(_args);
|
|
2029
|
-
}
|
|
2030
|
-
async listWorkflowRuns(args) {
|
|
2031
|
-
return this.stores.workflows.listWorkflowRuns(args);
|
|
2032
|
-
}
|
|
2033
|
-
async getWorkflowRunById(args) {
|
|
2034
|
-
return this.stores.workflows.getWorkflowRunById(args);
|
|
2035
|
-
}
|
|
2036
|
-
async updateWorkflowResults({
|
|
2037
|
-
workflowName,
|
|
2038
|
-
runId,
|
|
2039
|
-
stepId,
|
|
2040
|
-
result,
|
|
2041
|
-
requestContext
|
|
2042
|
-
}) {
|
|
2043
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2044
|
-
}
|
|
2045
|
-
async updateWorkflowState({
|
|
2046
|
-
workflowName,
|
|
2047
|
-
runId,
|
|
2048
|
-
opts
|
|
2049
|
-
}) {
|
|
2050
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2051
|
-
}
|
|
2052
|
-
async persistWorkflowSnapshot({
|
|
2053
|
-
workflowName,
|
|
2054
|
-
runId,
|
|
2055
|
-
resourceId,
|
|
2056
|
-
snapshot
|
|
2057
|
-
}) {
|
|
2058
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2059
|
-
}
|
|
2060
|
-
async loadWorkflowSnapshot({
|
|
2061
|
-
workflowName,
|
|
2062
|
-
runId
|
|
2063
|
-
}) {
|
|
2064
|
-
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2065
|
-
}
|
|
2066
|
-
async getScoreById({ id: _id }) {
|
|
2067
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
2068
|
-
}
|
|
2069
|
-
async getScoresByScorerId({
|
|
2070
|
-
scorerId,
|
|
2071
|
-
source,
|
|
2072
|
-
entityId,
|
|
2073
|
-
entityType,
|
|
2074
|
-
pagination
|
|
2075
|
-
}) {
|
|
2076
|
-
return this.stores.scores.getScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
|
|
2077
|
-
}
|
|
2078
|
-
async saveScore(_score) {
|
|
2079
|
-
return this.stores.scores.saveScore(_score);
|
|
2080
|
-
}
|
|
2081
|
-
async getScoresByRunId({
|
|
2082
|
-
runId,
|
|
2083
|
-
pagination
|
|
2084
|
-
}) {
|
|
2085
|
-
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
2086
|
-
}
|
|
2087
|
-
async getScoresByEntityId({
|
|
2088
|
-
entityId,
|
|
2089
|
-
entityType,
|
|
2090
|
-
pagination
|
|
2091
|
-
}) {
|
|
2092
|
-
return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
|
|
2093
|
-
}
|
|
2094
|
-
async getScoresBySpan({
|
|
2095
|
-
traceId,
|
|
2096
|
-
spanId,
|
|
2097
|
-
pagination
|
|
2098
|
-
}) {
|
|
2099
|
-
return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination });
|
|
1952
|
+
constructor(id, name, disableInit) {
|
|
1953
|
+
super({ id, name, disableInit });
|
|
1954
|
+
this.stores = {};
|
|
2100
1955
|
}
|
|
2101
1956
|
};
|
|
2102
1957
|
var LanceFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
@@ -2445,14 +2300,14 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2445
2300
|
* ```
|
|
2446
2301
|
*/
|
|
2447
2302
|
static async create(uri, options) {
|
|
2448
|
-
const instance = new _LanceVectorStore();
|
|
2303
|
+
const instance = new _LanceVectorStore(options?.id || crypto.randomUUID());
|
|
2449
2304
|
try {
|
|
2450
2305
|
instance.lanceClient = await lancedb.connect(uri, options);
|
|
2451
2306
|
return instance;
|
|
2452
2307
|
} catch (e) {
|
|
2453
2308
|
throw new error.MastraError(
|
|
2454
2309
|
{
|
|
2455
|
-
id: "
|
|
2310
|
+
id: storage.createVectorErrorId("LANCE", "CONNECT", "FAILED"),
|
|
2456
2311
|
domain: error.ErrorDomain.STORAGE,
|
|
2457
2312
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2458
2313
|
details: { uri }
|
|
@@ -2465,8 +2320,8 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2465
2320
|
* @internal
|
|
2466
2321
|
* Private constructor to enforce using the create factory method
|
|
2467
2322
|
*/
|
|
2468
|
-
constructor() {
|
|
2469
|
-
super();
|
|
2323
|
+
constructor(id) {
|
|
2324
|
+
super({ id });
|
|
2470
2325
|
}
|
|
2471
2326
|
close() {
|
|
2472
2327
|
if (this.lanceClient) {
|
|
@@ -2495,7 +2350,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2495
2350
|
} catch (error$1) {
|
|
2496
2351
|
throw new error.MastraError(
|
|
2497
2352
|
{
|
|
2498
|
-
id: "
|
|
2353
|
+
id: storage.createVectorErrorId("LANCE", "QUERY", "INVALID_ARGS"),
|
|
2499
2354
|
domain: error.ErrorDomain.STORAGE,
|
|
2500
2355
|
category: error.ErrorCategory.USER,
|
|
2501
2356
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2543,7 +2398,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2543
2398
|
} catch (error$1) {
|
|
2544
2399
|
throw new error.MastraError(
|
|
2545
2400
|
{
|
|
2546
|
-
id: "
|
|
2401
|
+
id: storage.createVectorErrorId("LANCE", "QUERY", "FAILED"),
|
|
2547
2402
|
domain: error.ErrorDomain.STORAGE,
|
|
2548
2403
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2549
2404
|
details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
|
|
@@ -2595,7 +2450,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2595
2450
|
} catch (error$1) {
|
|
2596
2451
|
throw new error.MastraError(
|
|
2597
2452
|
{
|
|
2598
|
-
id: "
|
|
2453
|
+
id: storage.createVectorErrorId("LANCE", "UPSERT", "INVALID_ARGS"),
|
|
2599
2454
|
domain: error.ErrorDomain.STORAGE,
|
|
2600
2455
|
category: error.ErrorCategory.USER,
|
|
2601
2456
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2631,7 +2486,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2631
2486
|
} catch (error$1) {
|
|
2632
2487
|
throw new error.MastraError(
|
|
2633
2488
|
{
|
|
2634
|
-
id: "
|
|
2489
|
+
id: storage.createVectorErrorId("LANCE", "UPSERT", "FAILED"),
|
|
2635
2490
|
domain: error.ErrorDomain.STORAGE,
|
|
2636
2491
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2637
2492
|
details: { tableName, vectorCount: vectors.length, metadataCount: metadata.length, idsCount: ids.length }
|
|
@@ -2658,7 +2513,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2658
2513
|
async createTable(tableName, data, options) {
|
|
2659
2514
|
if (!this.lanceClient) {
|
|
2660
2515
|
throw new error.MastraError({
|
|
2661
|
-
id: "
|
|
2516
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
|
|
2662
2517
|
domain: error.ErrorDomain.STORAGE,
|
|
2663
2518
|
category: error.ErrorCategory.USER,
|
|
2664
2519
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2673,7 +2528,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2673
2528
|
} catch (error$1) {
|
|
2674
2529
|
throw new error.MastraError(
|
|
2675
2530
|
{
|
|
2676
|
-
id: "
|
|
2531
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_TABLE", "FAILED"),
|
|
2677
2532
|
domain: error.ErrorDomain.STORAGE,
|
|
2678
2533
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2679
2534
|
details: { tableName }
|
|
@@ -2685,7 +2540,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2685
2540
|
async listTables() {
|
|
2686
2541
|
if (!this.lanceClient) {
|
|
2687
2542
|
throw new error.MastraError({
|
|
2688
|
-
id: "
|
|
2543
|
+
id: storage.createVectorErrorId("LANCE", "LIST_TABLES", "INVALID_ARGS"),
|
|
2689
2544
|
domain: error.ErrorDomain.STORAGE,
|
|
2690
2545
|
category: error.ErrorCategory.USER,
|
|
2691
2546
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2697,7 +2552,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2697
2552
|
} catch (error$1) {
|
|
2698
2553
|
throw new error.MastraError(
|
|
2699
2554
|
{
|
|
2700
|
-
id: "
|
|
2555
|
+
id: storage.createVectorErrorId("LANCE", "LIST_TABLES", "FAILED"),
|
|
2701
2556
|
domain: error.ErrorDomain.STORAGE,
|
|
2702
2557
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2703
2558
|
},
|
|
@@ -2708,7 +2563,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2708
2563
|
async getTableSchema(tableName) {
|
|
2709
2564
|
if (!this.lanceClient) {
|
|
2710
2565
|
throw new error.MastraError({
|
|
2711
|
-
id: "
|
|
2566
|
+
id: storage.createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
|
|
2712
2567
|
domain: error.ErrorDomain.STORAGE,
|
|
2713
2568
|
category: error.ErrorCategory.USER,
|
|
2714
2569
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2721,7 +2576,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2721
2576
|
} catch (error$1) {
|
|
2722
2577
|
throw new error.MastraError(
|
|
2723
2578
|
{
|
|
2724
|
-
id: "
|
|
2579
|
+
id: storage.createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
|
|
2725
2580
|
domain: error.ErrorDomain.STORAGE,
|
|
2726
2581
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2727
2582
|
details: { tableName }
|
|
@@ -2756,7 +2611,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2756
2611
|
} catch (err) {
|
|
2757
2612
|
throw new error.MastraError(
|
|
2758
2613
|
{
|
|
2759
|
-
id: "
|
|
2614
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_INDEX", "INVALID_ARGS"),
|
|
2760
2615
|
domain: error.ErrorDomain.STORAGE,
|
|
2761
2616
|
category: error.ErrorCategory.USER,
|
|
2762
2617
|
details: { tableName: tableName || "", indexName, dimension, metric }
|
|
@@ -2801,7 +2656,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2801
2656
|
} catch (error$1) {
|
|
2802
2657
|
throw new error.MastraError(
|
|
2803
2658
|
{
|
|
2804
|
-
id: "
|
|
2659
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_INDEX", "FAILED"),
|
|
2805
2660
|
domain: error.ErrorDomain.STORAGE,
|
|
2806
2661
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2807
2662
|
details: { tableName: tableName || "", indexName, dimension }
|
|
@@ -2813,7 +2668,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2813
2668
|
async listIndexes() {
|
|
2814
2669
|
if (!this.lanceClient) {
|
|
2815
2670
|
throw new error.MastraError({
|
|
2816
|
-
id: "
|
|
2671
|
+
id: storage.createVectorErrorId("LANCE", "LIST_INDEXES", "INVALID_ARGS"),
|
|
2817
2672
|
domain: error.ErrorDomain.STORAGE,
|
|
2818
2673
|
category: error.ErrorCategory.USER,
|
|
2819
2674
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2832,7 +2687,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2832
2687
|
} catch (error$1) {
|
|
2833
2688
|
throw new error.MastraError(
|
|
2834
2689
|
{
|
|
2835
|
-
id: "
|
|
2690
|
+
id: storage.createVectorErrorId("LANCE", "LIST_INDEXES", "FAILED"),
|
|
2836
2691
|
domain: error.ErrorDomain.STORAGE,
|
|
2837
2692
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2838
2693
|
},
|
|
@@ -2851,7 +2706,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2851
2706
|
} catch (err) {
|
|
2852
2707
|
throw new error.MastraError(
|
|
2853
2708
|
{
|
|
2854
|
-
id: "
|
|
2709
|
+
id: storage.createVectorErrorId("LANCE", "DESCRIBE_INDEX", "INVALID_ARGS"),
|
|
2855
2710
|
domain: error.ErrorDomain.STORAGE,
|
|
2856
2711
|
category: error.ErrorCategory.USER,
|
|
2857
2712
|
details: { indexName }
|
|
@@ -2886,7 +2741,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2886
2741
|
} catch (error$1) {
|
|
2887
2742
|
throw new error.MastraError(
|
|
2888
2743
|
{
|
|
2889
|
-
id: "
|
|
2744
|
+
id: storage.createVectorErrorId("LANCE", "DESCRIBE_INDEX", "FAILED"),
|
|
2890
2745
|
domain: error.ErrorDomain.STORAGE,
|
|
2891
2746
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2892
2747
|
details: { indexName }
|
|
@@ -2906,7 +2761,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2906
2761
|
} catch (err) {
|
|
2907
2762
|
throw new error.MastraError(
|
|
2908
2763
|
{
|
|
2909
|
-
id: "
|
|
2764
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_INDEX", "INVALID_ARGS"),
|
|
2910
2765
|
domain: error.ErrorDomain.STORAGE,
|
|
2911
2766
|
category: error.ErrorCategory.USER,
|
|
2912
2767
|
details: { indexName }
|
|
@@ -2929,7 +2784,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2929
2784
|
} catch (error$1) {
|
|
2930
2785
|
throw new error.MastraError(
|
|
2931
2786
|
{
|
|
2932
|
-
id: "
|
|
2787
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_INDEX", "FAILED"),
|
|
2933
2788
|
domain: error.ErrorDomain.STORAGE,
|
|
2934
2789
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2935
2790
|
details: { indexName }
|
|
@@ -2944,7 +2799,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2944
2799
|
async deleteAllTables() {
|
|
2945
2800
|
if (!this.lanceClient) {
|
|
2946
2801
|
throw new error.MastraError({
|
|
2947
|
-
id: "
|
|
2802
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "INVALID_ARGS"),
|
|
2948
2803
|
domain: error.ErrorDomain.STORAGE,
|
|
2949
2804
|
category: error.ErrorCategory.USER,
|
|
2950
2805
|
details: { methodName: "deleteAllTables" },
|
|
@@ -2956,7 +2811,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2956
2811
|
} catch (error$1) {
|
|
2957
2812
|
throw new error.MastraError(
|
|
2958
2813
|
{
|
|
2959
|
-
id: "
|
|
2814
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "FAILED"),
|
|
2960
2815
|
domain: error.ErrorDomain.STORAGE,
|
|
2961
2816
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2962
2817
|
details: { methodName: "deleteAllTables" }
|
|
@@ -2968,7 +2823,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2968
2823
|
async deleteTable(tableName) {
|
|
2969
2824
|
if (!this.lanceClient) {
|
|
2970
2825
|
throw new error.MastraError({
|
|
2971
|
-
id: "
|
|
2826
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_TABLE", "INVALID_ARGS"),
|
|
2972
2827
|
domain: error.ErrorDomain.STORAGE,
|
|
2973
2828
|
category: error.ErrorCategory.USER,
|
|
2974
2829
|
details: { tableName },
|
|
@@ -2980,7 +2835,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2980
2835
|
} catch (error$1) {
|
|
2981
2836
|
throw new error.MastraError(
|
|
2982
2837
|
{
|
|
2983
|
-
id: "
|
|
2838
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_TABLE", "FAILED"),
|
|
2984
2839
|
domain: error.ErrorDomain.STORAGE,
|
|
2985
2840
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2986
2841
|
details: { tableName }
|
|
@@ -2989,7 +2844,44 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2989
2844
|
);
|
|
2990
2845
|
}
|
|
2991
2846
|
}
|
|
2992
|
-
async updateVector(
|
|
2847
|
+
async updateVector(params) {
|
|
2848
|
+
const { indexName, update } = params;
|
|
2849
|
+
if ("id" in params && "filter" in params && params.id && params.filter) {
|
|
2850
|
+
throw new error.MastraError({
|
|
2851
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "MUTUALLY_EXCLUSIVE"),
|
|
2852
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2853
|
+
category: error.ErrorCategory.USER,
|
|
2854
|
+
text: "id and filter are mutually exclusive",
|
|
2855
|
+
details: { indexName }
|
|
2856
|
+
});
|
|
2857
|
+
}
|
|
2858
|
+
if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
|
|
2859
|
+
throw new error.MastraError({
|
|
2860
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_TARGET"),
|
|
2861
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2862
|
+
category: error.ErrorCategory.USER,
|
|
2863
|
+
text: "Either id or filter must be provided",
|
|
2864
|
+
details: { indexName }
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
|
|
2868
|
+
throw new error.MastraError({
|
|
2869
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "EMPTY_FILTER"),
|
|
2870
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2871
|
+
category: error.ErrorCategory.USER,
|
|
2872
|
+
text: "Cannot update with empty filter",
|
|
2873
|
+
details: { indexName }
|
|
2874
|
+
});
|
|
2875
|
+
}
|
|
2876
|
+
if (!update.vector && !update.metadata) {
|
|
2877
|
+
throw new error.MastraError({
|
|
2878
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_PAYLOAD"),
|
|
2879
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2880
|
+
category: error.ErrorCategory.USER,
|
|
2881
|
+
text: "No updates provided",
|
|
2882
|
+
details: { indexName }
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2993
2885
|
try {
|
|
2994
2886
|
if (!this.lanceClient) {
|
|
2995
2887
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
@@ -2997,21 +2889,6 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2997
2889
|
if (!indexName) {
|
|
2998
2890
|
throw new Error("indexName is required");
|
|
2999
2891
|
}
|
|
3000
|
-
if (!id) {
|
|
3001
|
-
throw new Error("id is required");
|
|
3002
|
-
}
|
|
3003
|
-
} catch (err) {
|
|
3004
|
-
throw new error.MastraError(
|
|
3005
|
-
{
|
|
3006
|
-
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
|
|
3007
|
-
domain: error.ErrorDomain.STORAGE,
|
|
3008
|
-
category: error.ErrorCategory.USER,
|
|
3009
|
-
details: { indexName, id }
|
|
3010
|
-
},
|
|
3011
|
-
err
|
|
3012
|
-
);
|
|
3013
|
-
}
|
|
3014
|
-
try {
|
|
3015
2892
|
const tables = await this.lanceClient.tableNames();
|
|
3016
2893
|
for (const tableName of tables) {
|
|
3017
2894
|
this.logger.debug("Checking table:" + tableName);
|
|
@@ -3021,39 +2898,66 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3021
2898
|
const hasColumn = schema.fields.some((field) => field.name === indexName);
|
|
3022
2899
|
if (hasColumn) {
|
|
3023
2900
|
this.logger.debug(`Found column ${indexName} in table ${tableName}`);
|
|
3024
|
-
|
|
3025
|
-
if (
|
|
3026
|
-
|
|
2901
|
+
let whereClause;
|
|
2902
|
+
if ("id" in params && params.id) {
|
|
2903
|
+
whereClause = `id = '${params.id}'`;
|
|
2904
|
+
} else if ("filter" in params && params.filter) {
|
|
2905
|
+
const translator = new LanceFilterTranslator();
|
|
2906
|
+
const processFilterKeys = (filter) => {
|
|
2907
|
+
const processedFilter = {};
|
|
2908
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
2909
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
2910
|
+
Object.entries(value).forEach(([nestedKey, nestedValue]) => {
|
|
2911
|
+
processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
|
|
2912
|
+
});
|
|
2913
|
+
} else {
|
|
2914
|
+
processedFilter[`metadata_${key}`] = value;
|
|
2915
|
+
}
|
|
2916
|
+
});
|
|
2917
|
+
return processedFilter;
|
|
2918
|
+
};
|
|
2919
|
+
const prefixedFilter = processFilterKeys(params.filter);
|
|
2920
|
+
whereClause = translator.translate(prefixedFilter) || "";
|
|
2921
|
+
if (!whereClause) {
|
|
2922
|
+
throw new Error("Failed to translate filter to SQL");
|
|
2923
|
+
}
|
|
2924
|
+
} else {
|
|
2925
|
+
throw new Error("Either id or filter must be provided");
|
|
3027
2926
|
}
|
|
3028
|
-
const
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
2927
|
+
const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
|
|
2928
|
+
if (existingRecords.length === 0) {
|
|
2929
|
+
this.logger.info(`No records found matching criteria in table ${tableName}`);
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
const updatedRecords = existingRecords.map((record) => {
|
|
2933
|
+
const rowData = {};
|
|
2934
|
+
Object.entries(record).forEach(([key, value]) => {
|
|
2935
|
+
if (key !== "_distance") {
|
|
2936
|
+
if (key === indexName) {
|
|
2937
|
+
if (update.vector) {
|
|
2938
|
+
rowData[key] = update.vector;
|
|
3039
2939
|
} else {
|
|
3040
|
-
|
|
2940
|
+
if (Array.isArray(value)) {
|
|
2941
|
+
rowData[key] = [...value];
|
|
2942
|
+
} else if (typeof value === "object" && value !== null) {
|
|
2943
|
+
rowData[key] = Array.from(value);
|
|
2944
|
+
} else {
|
|
2945
|
+
rowData[key] = value;
|
|
2946
|
+
}
|
|
3041
2947
|
}
|
|
2948
|
+
} else {
|
|
2949
|
+
rowData[key] = value;
|
|
3042
2950
|
}
|
|
3043
|
-
} else {
|
|
3044
|
-
rowData[key] = value;
|
|
3045
2951
|
}
|
|
2952
|
+
});
|
|
2953
|
+
if (update.metadata) {
|
|
2954
|
+
Object.entries(update.metadata).forEach(([key, value]) => {
|
|
2955
|
+
rowData[`metadata_${key}`] = value;
|
|
2956
|
+
});
|
|
3046
2957
|
}
|
|
2958
|
+
return rowData;
|
|
3047
2959
|
});
|
|
3048
|
-
|
|
3049
|
-
rowData[indexName] = update.vector;
|
|
3050
|
-
}
|
|
3051
|
-
if (update.metadata) {
|
|
3052
|
-
Object.entries(update.metadata).forEach(([key, value]) => {
|
|
3053
|
-
rowData[`metadata_${key}`] = value;
|
|
3054
|
-
});
|
|
3055
|
-
}
|
|
3056
|
-
await table.add([rowData], { mode: "overwrite" });
|
|
2960
|
+
await table.add(updatedRecords, { mode: "overwrite" });
|
|
3057
2961
|
return;
|
|
3058
2962
|
}
|
|
3059
2963
|
} catch (err) {
|
|
@@ -3063,12 +2967,19 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3063
2967
|
}
|
|
3064
2968
|
throw new Error(`No table found with column/index '${indexName}'`);
|
|
3065
2969
|
} catch (error$1) {
|
|
2970
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
3066
2971
|
throw new error.MastraError(
|
|
3067
2972
|
{
|
|
3068
|
-
id: "
|
|
2973
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "FAILED"),
|
|
3069
2974
|
domain: error.ErrorDomain.STORAGE,
|
|
3070
2975
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3071
|
-
details: {
|
|
2976
|
+
details: {
|
|
2977
|
+
indexName,
|
|
2978
|
+
..."id" in params && params.id && { id: params.id },
|
|
2979
|
+
..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
|
|
2980
|
+
hasVector: !!update.vector,
|
|
2981
|
+
hasMetadata: !!update.metadata
|
|
2982
|
+
}
|
|
3072
2983
|
},
|
|
3073
2984
|
error$1
|
|
3074
2985
|
);
|
|
@@ -3088,10 +2999,13 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3088
2999
|
} catch (err) {
|
|
3089
3000
|
throw new error.MastraError(
|
|
3090
3001
|
{
|
|
3091
|
-
id: "
|
|
3002
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTOR", "INVALID_ARGS"),
|
|
3092
3003
|
domain: error.ErrorDomain.STORAGE,
|
|
3093
3004
|
category: error.ErrorCategory.USER,
|
|
3094
|
-
details: {
|
|
3005
|
+
details: {
|
|
3006
|
+
indexName,
|
|
3007
|
+
...id && { id }
|
|
3008
|
+
}
|
|
3095
3009
|
},
|
|
3096
3010
|
err
|
|
3097
3011
|
);
|
|
@@ -3118,10 +3032,13 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3118
3032
|
} catch (error$1) {
|
|
3119
3033
|
throw new error.MastraError(
|
|
3120
3034
|
{
|
|
3121
|
-
id: "
|
|
3035
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTOR", "FAILED"),
|
|
3122
3036
|
domain: error.ErrorDomain.STORAGE,
|
|
3123
3037
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3124
|
-
details: {
|
|
3038
|
+
details: {
|
|
3039
|
+
indexName,
|
|
3040
|
+
...id && { id }
|
|
3041
|
+
}
|
|
3125
3042
|
},
|
|
3126
3043
|
error$1
|
|
3127
3044
|
);
|
|
@@ -3152,9 +3069,115 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3152
3069
|
});
|
|
3153
3070
|
return result;
|
|
3154
3071
|
}
|
|
3072
|
+
async deleteVectors({ indexName, filter, ids }) {
|
|
3073
|
+
if (ids && filter) {
|
|
3074
|
+
throw new error.MastraError({
|
|
3075
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
|
|
3076
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3077
|
+
category: error.ErrorCategory.USER,
|
|
3078
|
+
text: "ids and filter are mutually exclusive",
|
|
3079
|
+
details: { indexName }
|
|
3080
|
+
});
|
|
3081
|
+
}
|
|
3082
|
+
if (!ids && !filter) {
|
|
3083
|
+
throw new error.MastraError({
|
|
3084
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "NO_TARGET"),
|
|
3085
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3086
|
+
category: error.ErrorCategory.USER,
|
|
3087
|
+
text: "Either filter or ids must be provided",
|
|
3088
|
+
details: { indexName }
|
|
3089
|
+
});
|
|
3090
|
+
}
|
|
3091
|
+
if (ids && ids.length === 0) {
|
|
3092
|
+
throw new error.MastraError({
|
|
3093
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_IDS"),
|
|
3094
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3095
|
+
category: error.ErrorCategory.USER,
|
|
3096
|
+
text: "Cannot delete with empty ids array",
|
|
3097
|
+
details: { indexName }
|
|
3098
|
+
});
|
|
3099
|
+
}
|
|
3100
|
+
if (filter && Object.keys(filter).length === 0) {
|
|
3101
|
+
throw new error.MastraError({
|
|
3102
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_FILTER"),
|
|
3103
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3104
|
+
category: error.ErrorCategory.USER,
|
|
3105
|
+
text: "Cannot delete with empty filter",
|
|
3106
|
+
details: { indexName }
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
3109
|
+
try {
|
|
3110
|
+
if (!this.lanceClient) {
|
|
3111
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
3112
|
+
}
|
|
3113
|
+
if (!indexName) {
|
|
3114
|
+
throw new Error("indexName is required");
|
|
3115
|
+
}
|
|
3116
|
+
const tables = await this.lanceClient.tableNames();
|
|
3117
|
+
for (const tableName of tables) {
|
|
3118
|
+
this.logger.debug("Checking table:" + tableName);
|
|
3119
|
+
const table = await this.lanceClient.openTable(tableName);
|
|
3120
|
+
try {
|
|
3121
|
+
const schema = await table.schema();
|
|
3122
|
+
const hasColumn = schema.fields.some((field) => field.name === indexName);
|
|
3123
|
+
if (hasColumn) {
|
|
3124
|
+
this.logger.debug(`Found column ${indexName} in table ${tableName}`);
|
|
3125
|
+
if (ids) {
|
|
3126
|
+
const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
|
|
3127
|
+
await table.delete(idsConditions);
|
|
3128
|
+
} else if (filter) {
|
|
3129
|
+
const translator = new LanceFilterTranslator();
|
|
3130
|
+
const processFilterKeys = (filter2) => {
|
|
3131
|
+
const processedFilter = {};
|
|
3132
|
+
Object.entries(filter2).forEach(([key, value]) => {
|
|
3133
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3134
|
+
Object.entries(value).forEach(([nestedKey, nestedValue]) => {
|
|
3135
|
+
processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
|
|
3136
|
+
});
|
|
3137
|
+
} else {
|
|
3138
|
+
processedFilter[`metadata_${key}`] = value;
|
|
3139
|
+
}
|
|
3140
|
+
});
|
|
3141
|
+
return processedFilter;
|
|
3142
|
+
};
|
|
3143
|
+
const prefixedFilter = processFilterKeys(filter);
|
|
3144
|
+
const whereClause = translator.translate(prefixedFilter);
|
|
3145
|
+
if (!whereClause) {
|
|
3146
|
+
throw new Error("Failed to translate filter to SQL");
|
|
3147
|
+
}
|
|
3148
|
+
await table.delete(whereClause);
|
|
3149
|
+
}
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
} catch (err) {
|
|
3153
|
+
this.logger.error(`Error checking schema for table ${tableName}:` + err);
|
|
3154
|
+
continue;
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
throw new Error(`No table found with column/index '${indexName}'`);
|
|
3158
|
+
} catch (error$1) {
|
|
3159
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
3160
|
+
throw new error.MastraError(
|
|
3161
|
+
{
|
|
3162
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "FAILED"),
|
|
3163
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3164
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
3165
|
+
details: {
|
|
3166
|
+
indexName,
|
|
3167
|
+
...filter && { filter: JSON.stringify(filter) },
|
|
3168
|
+
...ids && { idsCount: ids.length }
|
|
3169
|
+
}
|
|
3170
|
+
},
|
|
3171
|
+
error$1
|
|
3172
|
+
);
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3155
3175
|
};
|
|
3156
3176
|
|
|
3157
3177
|
exports.LanceStorage = LanceStorage;
|
|
3158
3178
|
exports.LanceVectorStore = LanceVectorStore;
|
|
3179
|
+
exports.StoreMemoryLance = StoreMemoryLance;
|
|
3180
|
+
exports.StoreScoresLance = StoreScoresLance;
|
|
3181
|
+
exports.StoreWorkflowsLance = StoreWorkflowsLance;
|
|
3159
3182
|
//# sourceMappingURL=index.cjs.map
|
|
3160
3183
|
//# sourceMappingURL=index.cjs.map
|