@mastra/lance 0.0.0-netlify-no-bundle-20251127120354 → 0.0.0-new-button-export-20251219130424
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 +266 -18
- package/dist/index.cjs +1131 -993
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1132 -994
- 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 +6 -7
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +14 -6
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +16 -14
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +41 -40
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +5 -6
- 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.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { connect, Index } from '@lancedb/lancedb';
|
|
2
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
-
import { MastraStorage,
|
|
3
|
+
import { MastraStorage, createStorageErrorId, createVectorErrorId, MemoryStorage, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, normalizePerPage, calculatePagination, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, getDefaultValue, ensureDate } from '@mastra/core/storage';
|
|
4
4
|
import { MessageList } from '@mastra/core/agent';
|
|
5
|
+
import { MastraBase } from '@mastra/core/base';
|
|
5
6
|
import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
|
|
6
7
|
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
7
8
|
import { MastraVector } from '@mastra/core/vector';
|
|
@@ -89,7 +90,7 @@ async function getTableSchema({
|
|
|
89
90
|
} catch (validationError) {
|
|
90
91
|
throw new MastraError(
|
|
91
92
|
{
|
|
92
|
-
id: "
|
|
93
|
+
id: createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
|
|
93
94
|
domain: ErrorDomain.STORAGE,
|
|
94
95
|
category: ErrorCategory.USER,
|
|
95
96
|
text: validationError.message,
|
|
@@ -112,7 +113,7 @@ async function getTableSchema({
|
|
|
112
113
|
} catch (error) {
|
|
113
114
|
throw new MastraError(
|
|
114
115
|
{
|
|
115
|
-
id: "
|
|
116
|
+
id: createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
|
|
116
117
|
domain: ErrorDomain.STORAGE,
|
|
117
118
|
category: ErrorCategory.THIRD_PARTY,
|
|
118
119
|
details: { tableName }
|
|
@@ -122,1118 +123,1198 @@ async function getTableSchema({
|
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
// src/storage/
|
|
126
|
-
|
|
126
|
+
// src/storage/db/index.ts
|
|
127
|
+
function resolveLanceConfig(config) {
|
|
128
|
+
return config.client;
|
|
129
|
+
}
|
|
130
|
+
var LanceDB = class extends MastraBase {
|
|
127
131
|
client;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
super();
|
|
132
|
+
constructor({ client }) {
|
|
133
|
+
super({ name: "lance-db" });
|
|
131
134
|
this.client = client;
|
|
132
|
-
this.operations = operations;
|
|
133
135
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
getDefaultValue(type) {
|
|
137
|
+
switch (type) {
|
|
138
|
+
case "text":
|
|
139
|
+
return "''";
|
|
140
|
+
case "timestamp":
|
|
141
|
+
return "CURRENT_TIMESTAMP";
|
|
142
|
+
case "integer":
|
|
143
|
+
case "bigint":
|
|
144
|
+
return "0";
|
|
145
|
+
case "jsonb":
|
|
146
|
+
return "'{}'";
|
|
147
|
+
case "uuid":
|
|
148
|
+
return "''";
|
|
149
|
+
default:
|
|
150
|
+
return getDefaultValue(type);
|
|
151
|
+
}
|
|
137
152
|
}
|
|
138
|
-
async
|
|
153
|
+
async hasColumn(tableName, columnName) {
|
|
154
|
+
const table = await this.client.openTable(tableName);
|
|
155
|
+
const schema = await table.schema();
|
|
156
|
+
return schema.fields.some((field) => field.name === columnName);
|
|
157
|
+
}
|
|
158
|
+
translateSchema(schema) {
|
|
159
|
+
const fields = Object.entries(schema).map(([name, column]) => {
|
|
160
|
+
let arrowType;
|
|
161
|
+
switch (column.type.toLowerCase()) {
|
|
162
|
+
case "text":
|
|
163
|
+
case "uuid":
|
|
164
|
+
arrowType = new Utf8();
|
|
165
|
+
break;
|
|
166
|
+
case "int":
|
|
167
|
+
case "integer":
|
|
168
|
+
arrowType = new Int32();
|
|
169
|
+
break;
|
|
170
|
+
case "bigint":
|
|
171
|
+
arrowType = new Float64();
|
|
172
|
+
break;
|
|
173
|
+
case "float":
|
|
174
|
+
arrowType = new Float32();
|
|
175
|
+
break;
|
|
176
|
+
case "jsonb":
|
|
177
|
+
case "json":
|
|
178
|
+
arrowType = new Utf8();
|
|
179
|
+
break;
|
|
180
|
+
case "binary":
|
|
181
|
+
arrowType = new Binary();
|
|
182
|
+
break;
|
|
183
|
+
case "timestamp":
|
|
184
|
+
arrowType = new Float64();
|
|
185
|
+
break;
|
|
186
|
+
default:
|
|
187
|
+
arrowType = new Utf8();
|
|
188
|
+
}
|
|
189
|
+
return new Field(name, arrowType, column.nullable ?? true);
|
|
190
|
+
});
|
|
191
|
+
return new Schema(fields);
|
|
192
|
+
}
|
|
193
|
+
async createTable({
|
|
194
|
+
tableName,
|
|
195
|
+
schema
|
|
196
|
+
}) {
|
|
139
197
|
try {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
198
|
+
if (!this.client) {
|
|
199
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
200
|
+
}
|
|
201
|
+
if (!tableName) {
|
|
202
|
+
throw new Error("tableName is required for createTable.");
|
|
203
|
+
}
|
|
204
|
+
if (!schema) {
|
|
205
|
+
throw new Error("schema is required for createTable.");
|
|
143
206
|
}
|
|
144
|
-
return {
|
|
145
|
-
...thread,
|
|
146
|
-
createdAt: new Date(thread.createdAt),
|
|
147
|
-
updatedAt: new Date(thread.updatedAt)
|
|
148
|
-
};
|
|
149
207
|
} catch (error) {
|
|
150
208
|
throw new MastraError(
|
|
151
209
|
{
|
|
152
|
-
id: "
|
|
210
|
+
id: createStorageErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
|
|
153
211
|
domain: ErrorDomain.STORAGE,
|
|
154
|
-
category: ErrorCategory.
|
|
212
|
+
category: ErrorCategory.USER,
|
|
213
|
+
details: { tableName }
|
|
155
214
|
},
|
|
156
215
|
error
|
|
157
216
|
);
|
|
158
217
|
}
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
162
|
-
* @param thread - The thread to save
|
|
163
|
-
* @returns The saved thread
|
|
164
|
-
*/
|
|
165
|
-
async saveThread({ thread }) {
|
|
166
218
|
try {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
await table.add([record], { mode: "append" });
|
|
170
|
-
return thread;
|
|
219
|
+
const arrowSchema = this.translateSchema(schema);
|
|
220
|
+
await this.client.createEmptyTable(tableName, arrowSchema);
|
|
171
221
|
} catch (error) {
|
|
222
|
+
if (error.message?.includes("already exists")) {
|
|
223
|
+
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
172
226
|
throw new MastraError(
|
|
173
227
|
{
|
|
174
|
-
id: "
|
|
228
|
+
id: createStorageErrorId("LANCE", "CREATE_TABLE", "FAILED"),
|
|
175
229
|
domain: ErrorDomain.STORAGE,
|
|
176
|
-
category: ErrorCategory.THIRD_PARTY
|
|
230
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
231
|
+
details: { tableName }
|
|
177
232
|
},
|
|
178
233
|
error
|
|
179
234
|
);
|
|
180
235
|
}
|
|
181
236
|
}
|
|
182
|
-
async
|
|
183
|
-
id,
|
|
184
|
-
title,
|
|
185
|
-
metadata
|
|
186
|
-
}) {
|
|
187
|
-
const maxRetries = 5;
|
|
188
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
189
|
-
try {
|
|
190
|
-
const current = await this.getThreadById({ threadId: id });
|
|
191
|
-
if (!current) {
|
|
192
|
-
throw new Error(`Thread with id ${id} not found`);
|
|
193
|
-
}
|
|
194
|
-
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
195
|
-
const record = {
|
|
196
|
-
id,
|
|
197
|
-
title,
|
|
198
|
-
metadata: JSON.stringify(mergedMetadata),
|
|
199
|
-
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
200
|
-
};
|
|
201
|
-
const table = await this.client.openTable(TABLE_THREADS);
|
|
202
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
203
|
-
const updatedThread = await this.getThreadById({ threadId: id });
|
|
204
|
-
if (!updatedThread) {
|
|
205
|
-
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
206
|
-
}
|
|
207
|
-
return updatedThread;
|
|
208
|
-
} catch (error) {
|
|
209
|
-
if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
210
|
-
const delay = Math.pow(2, attempt) * 10;
|
|
211
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
throw new MastraError(
|
|
215
|
-
{
|
|
216
|
-
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
217
|
-
domain: ErrorDomain.STORAGE,
|
|
218
|
-
category: ErrorCategory.THIRD_PARTY
|
|
219
|
-
},
|
|
220
|
-
error
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
throw new MastraError(
|
|
225
|
-
{
|
|
226
|
-
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
227
|
-
domain: ErrorDomain.STORAGE,
|
|
228
|
-
category: ErrorCategory.THIRD_PARTY
|
|
229
|
-
},
|
|
230
|
-
new Error("All retries exhausted")
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
async deleteThread({ threadId }) {
|
|
237
|
+
async dropTable({ tableName }) {
|
|
234
238
|
try {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
if (!this.client) {
|
|
240
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
241
|
+
}
|
|
242
|
+
if (!tableName) {
|
|
243
|
+
throw new Error("tableName is required for dropTable.");
|
|
244
|
+
}
|
|
245
|
+
} catch (validationError) {
|
|
240
246
|
throw new MastraError(
|
|
241
247
|
{
|
|
242
|
-
id: "
|
|
248
|
+
id: createStorageErrorId("LANCE", "DROP_TABLE", "INVALID_ARGS"),
|
|
243
249
|
domain: ErrorDomain.STORAGE,
|
|
244
|
-
category: ErrorCategory.
|
|
250
|
+
category: ErrorCategory.USER,
|
|
251
|
+
text: validationError.message,
|
|
252
|
+
details: { tableName }
|
|
245
253
|
},
|
|
246
|
-
|
|
254
|
+
validationError
|
|
247
255
|
);
|
|
248
256
|
}
|
|
249
|
-
}
|
|
250
|
-
normalizeMessage(message) {
|
|
251
|
-
const { thread_id, ...rest } = message;
|
|
252
|
-
return {
|
|
253
|
-
...rest,
|
|
254
|
-
threadId: thread_id,
|
|
255
|
-
content: typeof message.content === "string" ? (() => {
|
|
256
|
-
try {
|
|
257
|
-
return JSON.parse(message.content);
|
|
258
|
-
} catch {
|
|
259
|
-
return message.content;
|
|
260
|
-
}
|
|
261
|
-
})() : message.content
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
async listMessagesById({ messageIds }) {
|
|
265
|
-
if (messageIds.length === 0) return { messages: [] };
|
|
266
257
|
try {
|
|
267
|
-
|
|
268
|
-
const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
|
|
269
|
-
const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
|
|
270
|
-
const messages = processResultWithTypeConversion(
|
|
271
|
-
allRecords,
|
|
272
|
-
await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
|
|
273
|
-
);
|
|
274
|
-
const list = new MessageList().add(
|
|
275
|
-
messages.map(this.normalizeMessage),
|
|
276
|
-
"memory"
|
|
277
|
-
);
|
|
278
|
-
return { messages: list.get.all.db() };
|
|
258
|
+
await this.client.dropTable(tableName);
|
|
279
259
|
} catch (error) {
|
|
260
|
+
if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
|
|
261
|
+
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
280
264
|
throw new MastraError(
|
|
281
265
|
{
|
|
282
|
-
id: "
|
|
266
|
+
id: createStorageErrorId("LANCE", "DROP_TABLE", "FAILED"),
|
|
283
267
|
domain: ErrorDomain.STORAGE,
|
|
284
268
|
category: ErrorCategory.THIRD_PARTY,
|
|
285
|
-
details: {
|
|
286
|
-
messageIds: JSON.stringify(messageIds)
|
|
287
|
-
}
|
|
269
|
+
details: { tableName }
|
|
288
270
|
},
|
|
289
271
|
error
|
|
290
272
|
);
|
|
291
273
|
}
|
|
292
274
|
}
|
|
293
|
-
async
|
|
294
|
-
|
|
295
|
-
|
|
275
|
+
async alterTable({
|
|
276
|
+
tableName,
|
|
277
|
+
schema,
|
|
278
|
+
ifNotExists
|
|
279
|
+
}) {
|
|
280
|
+
try {
|
|
281
|
+
if (!this.client) {
|
|
282
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
283
|
+
}
|
|
284
|
+
if (!tableName) {
|
|
285
|
+
throw new Error("tableName is required for alterTable.");
|
|
286
|
+
}
|
|
287
|
+
if (!schema) {
|
|
288
|
+
throw new Error("schema is required for alterTable.");
|
|
289
|
+
}
|
|
290
|
+
if (!ifNotExists || ifNotExists.length === 0) {
|
|
291
|
+
this.logger.debug("No columns specified to add in alterTable, skipping.");
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
} catch (validationError) {
|
|
296
295
|
throw new MastraError(
|
|
297
296
|
{
|
|
298
|
-
id: "
|
|
297
|
+
id: createStorageErrorId("LANCE", "ALTER_TABLE", "INVALID_ARGS"),
|
|
299
298
|
domain: ErrorDomain.STORAGE,
|
|
300
|
-
category: ErrorCategory.
|
|
301
|
-
|
|
299
|
+
category: ErrorCategory.USER,
|
|
300
|
+
text: validationError.message,
|
|
301
|
+
details: { tableName }
|
|
302
302
|
},
|
|
303
|
-
|
|
303
|
+
validationError
|
|
304
304
|
);
|
|
305
305
|
}
|
|
306
|
-
const perPage = normalizePerPage(perPageInput, 40);
|
|
307
|
-
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
308
306
|
try {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
const conditions = [`thread_id = '${this.escapeSql(threadId)}'`];
|
|
323
|
-
if (resourceId) {
|
|
324
|
-
conditions.push(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
325
|
-
}
|
|
326
|
-
if (filter?.dateRange?.start) {
|
|
327
|
-
const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
|
|
328
|
-
conditions.push(`\`createdAt\` >= ${startTime}`);
|
|
329
|
-
}
|
|
330
|
-
if (filter?.dateRange?.end) {
|
|
331
|
-
const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
|
|
332
|
-
conditions.push(`\`createdAt\` <= ${endTime}`);
|
|
333
|
-
}
|
|
334
|
-
const whereClause = conditions.join(" AND ");
|
|
335
|
-
const total = await table.countRows(whereClause);
|
|
336
|
-
const query = table.query().where(whereClause);
|
|
337
|
-
let allRecords = await query.toArray();
|
|
338
|
-
allRecords.sort((a, b) => {
|
|
339
|
-
const aValue = field === "createdAt" ? a.createdAt : a[field];
|
|
340
|
-
const bValue = field === "createdAt" ? b.createdAt : b[field];
|
|
341
|
-
if (aValue == null && bValue == null) return 0;
|
|
342
|
-
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
343
|
-
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
344
|
-
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
345
|
-
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
346
|
-
}
|
|
347
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
348
|
-
});
|
|
349
|
-
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
350
|
-
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
351
|
-
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
307
|
+
const table = await this.client.openTable(tableName);
|
|
308
|
+
const currentSchema = await table.schema();
|
|
309
|
+
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
310
|
+
const typeMap = {
|
|
311
|
+
text: "string",
|
|
312
|
+
integer: "int",
|
|
313
|
+
bigint: "bigint",
|
|
314
|
+
timestamp: "timestamp",
|
|
315
|
+
jsonb: "string",
|
|
316
|
+
uuid: "string"
|
|
317
|
+
};
|
|
318
|
+
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
319
|
+
const colDef = schema[col];
|
|
352
320
|
return {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
page,
|
|
356
|
-
perPage: perPageForResponse,
|
|
357
|
-
hasMore: false
|
|
321
|
+
name: col,
|
|
322
|
+
valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
|
|
358
323
|
};
|
|
359
|
-
}
|
|
360
|
-
const messageIds = new Set(messages.map((m) => m.id));
|
|
361
|
-
if (include && include.length > 0) {
|
|
362
|
-
const threadIds = [...new Set(include.map((item) => item.threadId || threadId))];
|
|
363
|
-
const allThreadMessages = [];
|
|
364
|
-
for (const tid of threadIds) {
|
|
365
|
-
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
366
|
-
let threadRecords = await threadQuery.toArray();
|
|
367
|
-
allThreadMessages.push(...threadRecords);
|
|
368
|
-
}
|
|
369
|
-
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
370
|
-
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
371
|
-
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
372
|
-
for (const includeMsg of includedMessages) {
|
|
373
|
-
if (!messageIds.has(includeMsg.id)) {
|
|
374
|
-
messages.push(includeMsg);
|
|
375
|
-
messageIds.add(includeMsg.id);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const list = new MessageList().add(messages, "memory");
|
|
380
|
-
let finalMessages = list.get.all.db();
|
|
381
|
-
finalMessages = finalMessages.sort((a, b) => {
|
|
382
|
-
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
383
|
-
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
384
|
-
if (aValue == null && bValue == null) return 0;
|
|
385
|
-
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
386
|
-
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
387
|
-
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
388
|
-
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
389
|
-
}
|
|
390
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
391
324
|
});
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return {
|
|
397
|
-
messages: finalMessages,
|
|
398
|
-
total,
|
|
399
|
-
page,
|
|
400
|
-
perPage: perPageForResponse,
|
|
401
|
-
hasMore
|
|
402
|
-
};
|
|
325
|
+
if (columnsToAdd.length > 0) {
|
|
326
|
+
await table.addColumns(columnsToAdd);
|
|
327
|
+
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
328
|
+
}
|
|
403
329
|
} catch (error) {
|
|
404
|
-
|
|
330
|
+
throw new MastraError(
|
|
405
331
|
{
|
|
406
|
-
id: "
|
|
332
|
+
id: createStorageErrorId("LANCE", "ALTER_TABLE", "FAILED"),
|
|
407
333
|
domain: ErrorDomain.STORAGE,
|
|
408
334
|
category: ErrorCategory.THIRD_PARTY,
|
|
409
|
-
details: {
|
|
410
|
-
threadId,
|
|
411
|
-
resourceId: resourceId ?? ""
|
|
412
|
-
}
|
|
335
|
+
details: { tableName }
|
|
413
336
|
},
|
|
414
337
|
error
|
|
415
338
|
);
|
|
416
|
-
this.logger?.error?.(mastraError.toString());
|
|
417
|
-
this.logger?.trackException?.(mastraError);
|
|
418
|
-
return {
|
|
419
|
-
messages: [],
|
|
420
|
-
total: 0,
|
|
421
|
-
page,
|
|
422
|
-
perPage: perPageForResponse,
|
|
423
|
-
hasMore: false
|
|
424
|
-
};
|
|
425
339
|
}
|
|
426
340
|
}
|
|
427
|
-
async
|
|
341
|
+
async clearTable({ tableName }) {
|
|
428
342
|
try {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
return { messages: [] };
|
|
432
|
-
}
|
|
433
|
-
const threadId = messages[0]?.threadId;
|
|
434
|
-
if (!threadId) {
|
|
435
|
-
throw new Error("Thread ID is required");
|
|
343
|
+
if (!this.client) {
|
|
344
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
436
345
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
throw new Error("Message ID is required");
|
|
440
|
-
}
|
|
441
|
-
if (!message.threadId) {
|
|
442
|
-
throw new Error("Thread ID is required for all messages");
|
|
443
|
-
}
|
|
444
|
-
if (message.resourceId === null || message.resourceId === void 0) {
|
|
445
|
-
throw new Error("Resource ID cannot be null or undefined");
|
|
446
|
-
}
|
|
447
|
-
if (!message.content) {
|
|
448
|
-
throw new Error("Message content is required");
|
|
449
|
-
}
|
|
346
|
+
if (!tableName) {
|
|
347
|
+
throw new Error("tableName is required for clearTable.");
|
|
450
348
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const
|
|
465
|
-
await
|
|
466
|
-
const list = new MessageList().add(messages, "memory");
|
|
467
|
-
return { messages: list.get.all.db() };
|
|
349
|
+
} catch (validationError) {
|
|
350
|
+
throw new MastraError(
|
|
351
|
+
{
|
|
352
|
+
id: createStorageErrorId("LANCE", "CLEAR_TABLE", "INVALID_ARGS"),
|
|
353
|
+
domain: ErrorDomain.STORAGE,
|
|
354
|
+
category: ErrorCategory.USER,
|
|
355
|
+
text: validationError.message,
|
|
356
|
+
details: { tableName }
|
|
357
|
+
},
|
|
358
|
+
validationError
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
const table = await this.client.openTable(tableName);
|
|
363
|
+
await table.delete("1=1");
|
|
468
364
|
} catch (error) {
|
|
469
365
|
throw new MastraError(
|
|
470
366
|
{
|
|
471
|
-
id: "
|
|
367
|
+
id: createStorageErrorId("LANCE", "CLEAR_TABLE", "FAILED"),
|
|
472
368
|
domain: ErrorDomain.STORAGE,
|
|
473
|
-
category: ErrorCategory.THIRD_PARTY
|
|
369
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
370
|
+
details: { tableName }
|
|
474
371
|
},
|
|
475
372
|
error
|
|
476
373
|
);
|
|
477
374
|
}
|
|
478
375
|
}
|
|
479
|
-
async
|
|
376
|
+
async insert({ tableName, record }) {
|
|
480
377
|
try {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
if (page < 0) {
|
|
484
|
-
throw new MastraError(
|
|
485
|
-
{
|
|
486
|
-
id: "STORAGE_LANCE_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
|
|
487
|
-
domain: ErrorDomain.STORAGE,
|
|
488
|
-
category: ErrorCategory.USER,
|
|
489
|
-
details: { page }
|
|
490
|
-
},
|
|
491
|
-
new Error("page must be >= 0")
|
|
492
|
-
);
|
|
378
|
+
if (!this.client) {
|
|
379
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
493
380
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
});
|
|
511
|
-
const paginatedRecords = records.slice(offset, offset + perPage);
|
|
512
|
-
const schema = await getTableSchema({ tableName: TABLE_THREADS, client: this.client });
|
|
513
|
-
const threads = paginatedRecords.map(
|
|
514
|
-
(record) => processResultWithTypeConversion(record, schema)
|
|
381
|
+
if (!tableName) {
|
|
382
|
+
throw new Error("tableName is required for insert.");
|
|
383
|
+
}
|
|
384
|
+
if (!record || Object.keys(record).length === 0) {
|
|
385
|
+
throw new Error("record is required and cannot be empty for insert.");
|
|
386
|
+
}
|
|
387
|
+
} catch (validationError) {
|
|
388
|
+
throw new MastraError(
|
|
389
|
+
{
|
|
390
|
+
id: createStorageErrorId("LANCE", "INSERT", "INVALID_ARGS"),
|
|
391
|
+
domain: ErrorDomain.STORAGE,
|
|
392
|
+
category: ErrorCategory.USER,
|
|
393
|
+
text: validationError.message,
|
|
394
|
+
details: { tableName }
|
|
395
|
+
},
|
|
396
|
+
validationError
|
|
515
397
|
);
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
398
|
+
}
|
|
399
|
+
try {
|
|
400
|
+
const table = await this.client.openTable(tableName);
|
|
401
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
402
|
+
const processedRecord = { ...record };
|
|
403
|
+
for (const key in processedRecord) {
|
|
404
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
405
|
+
this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
|
|
406
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
523
410
|
} catch (error) {
|
|
524
411
|
throw new MastraError(
|
|
525
412
|
{
|
|
526
|
-
id: "
|
|
413
|
+
id: createStorageErrorId("LANCE", "INSERT", "FAILED"),
|
|
527
414
|
domain: ErrorDomain.STORAGE,
|
|
528
|
-
category: ErrorCategory.THIRD_PARTY
|
|
415
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
416
|
+
details: { tableName }
|
|
529
417
|
},
|
|
530
418
|
error
|
|
531
419
|
);
|
|
532
420
|
}
|
|
533
421
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
* @returns The processed array with context messages included
|
|
539
|
-
*/
|
|
540
|
-
processMessagesWithContext(records, include) {
|
|
541
|
-
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
542
|
-
if (messagesWithContext.length === 0) {
|
|
543
|
-
return records;
|
|
544
|
-
}
|
|
545
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
546
|
-
records.forEach((message, index) => {
|
|
547
|
-
messageIndexMap.set(message.id, index);
|
|
548
|
-
});
|
|
549
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
550
|
-
for (const item of messagesWithContext) {
|
|
551
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
552
|
-
if (messageIndex !== void 0) {
|
|
553
|
-
if (item.withPreviousMessages) {
|
|
554
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
555
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
556
|
-
additionalIndices.add(i);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
if (item.withNextMessages) {
|
|
560
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
561
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
562
|
-
additionalIndices.add(i);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
422
|
+
async batchInsert({ tableName, records }) {
|
|
423
|
+
try {
|
|
424
|
+
if (!this.client) {
|
|
425
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
565
426
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
return records;
|
|
569
|
-
}
|
|
570
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
571
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
572
|
-
records.forEach((record, index) => {
|
|
573
|
-
if (originalMatchIds.has(record.id)) {
|
|
574
|
-
allIndices.add(index);
|
|
427
|
+
if (!tableName) {
|
|
428
|
+
throw new Error("tableName is required for batchInsert.");
|
|
575
429
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
})
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
content: typeof data.content === "string" ? (() => {
|
|
591
|
-
try {
|
|
592
|
-
return JSON.parse(data.content);
|
|
593
|
-
} catch {
|
|
594
|
-
return data.content;
|
|
595
|
-
}
|
|
596
|
-
})() : data.content,
|
|
597
|
-
createdAt: new Date(data.createdAt),
|
|
598
|
-
updatedAt: new Date(data.updatedAt)
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
|
-
async updateMessages(args) {
|
|
602
|
-
const { messages } = args;
|
|
603
|
-
this.logger.debug("Updating messages", { count: messages.length });
|
|
604
|
-
if (!messages.length) {
|
|
605
|
-
return [];
|
|
430
|
+
if (!records || records.length === 0) {
|
|
431
|
+
throw new Error("records array is required and cannot be empty for batchInsert.");
|
|
432
|
+
}
|
|
433
|
+
} catch (validationError) {
|
|
434
|
+
throw new MastraError(
|
|
435
|
+
{
|
|
436
|
+
id: createStorageErrorId("LANCE", "BATCH_INSERT", "INVALID_ARGS"),
|
|
437
|
+
domain: ErrorDomain.STORAGE,
|
|
438
|
+
category: ErrorCategory.USER,
|
|
439
|
+
text: validationError.message,
|
|
440
|
+
details: { tableName }
|
|
441
|
+
},
|
|
442
|
+
validationError
|
|
443
|
+
);
|
|
606
444
|
}
|
|
607
|
-
const updatedMessages = [];
|
|
608
|
-
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
609
445
|
try {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
continue;
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
const originalThreadId = existingMsg.threadId;
|
|
619
|
-
affectedThreadIds.add(originalThreadId);
|
|
620
|
-
const updatePayload = {};
|
|
621
|
-
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
622
|
-
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
623
|
-
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
624
|
-
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
625
|
-
updatePayload.thread_id = updates.threadId;
|
|
626
|
-
affectedThreadIds.add(updates.threadId);
|
|
627
|
-
}
|
|
628
|
-
if (updates.content) {
|
|
629
|
-
const existingContent = existingMsg.content;
|
|
630
|
-
let newContent = { ...existingContent };
|
|
631
|
-
if (updates.content.metadata !== void 0) {
|
|
632
|
-
newContent.metadata = {
|
|
633
|
-
...existingContent.metadata || {},
|
|
634
|
-
...updates.content.metadata || {}
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
if (updates.content.content !== void 0) {
|
|
638
|
-
newContent.content = updates.content.content;
|
|
639
|
-
}
|
|
640
|
-
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
641
|
-
newContent.parts = updates.content.parts;
|
|
446
|
+
const table = await this.client.openTable(tableName);
|
|
447
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
448
|
+
const processedRecords = records.map((record) => {
|
|
449
|
+
const processedRecord = { ...record };
|
|
450
|
+
for (const key in processedRecord) {
|
|
451
|
+
if (processedRecord[key] == null) continue;
|
|
452
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
453
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
642
454
|
}
|
|
643
|
-
updatePayload.content = JSON.stringify(newContent);
|
|
644
|
-
}
|
|
645
|
-
await this.operations.insert({ tableName: TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
646
|
-
const updatedMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
|
|
647
|
-
if (updatedMessage) {
|
|
648
|
-
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
649
455
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
tableName: TABLE_THREADS,
|
|
654
|
-
record: { id: threadId, updatedAt: Date.now() }
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
return updatedMessages;
|
|
456
|
+
return processedRecord;
|
|
457
|
+
});
|
|
458
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
|
|
658
459
|
} catch (error) {
|
|
659
460
|
throw new MastraError(
|
|
660
461
|
{
|
|
661
|
-
id: "
|
|
462
|
+
id: createStorageErrorId("LANCE", "BATCH_INSERT", "FAILED"),
|
|
662
463
|
domain: ErrorDomain.STORAGE,
|
|
663
464
|
category: ErrorCategory.THIRD_PARTY,
|
|
664
|
-
details: {
|
|
465
|
+
details: { tableName }
|
|
665
466
|
},
|
|
666
467
|
error
|
|
667
468
|
);
|
|
668
469
|
}
|
|
669
470
|
}
|
|
670
|
-
async
|
|
471
|
+
async load({ tableName, keys }) {
|
|
671
472
|
try {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
return null;
|
|
675
|
-
}
|
|
676
|
-
let createdAt;
|
|
677
|
-
let updatedAt;
|
|
678
|
-
try {
|
|
679
|
-
if (resource.createdAt instanceof Date) {
|
|
680
|
-
createdAt = resource.createdAt;
|
|
681
|
-
} else if (typeof resource.createdAt === "string") {
|
|
682
|
-
createdAt = new Date(resource.createdAt);
|
|
683
|
-
} else if (typeof resource.createdAt === "number") {
|
|
684
|
-
createdAt = new Date(resource.createdAt);
|
|
685
|
-
} else {
|
|
686
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
687
|
-
}
|
|
688
|
-
if (isNaN(createdAt.getTime())) {
|
|
689
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
690
|
-
}
|
|
691
|
-
} catch {
|
|
692
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
693
|
-
}
|
|
694
|
-
try {
|
|
695
|
-
if (resource.updatedAt instanceof Date) {
|
|
696
|
-
updatedAt = resource.updatedAt;
|
|
697
|
-
} else if (typeof resource.updatedAt === "string") {
|
|
698
|
-
updatedAt = new Date(resource.updatedAt);
|
|
699
|
-
} else if (typeof resource.updatedAt === "number") {
|
|
700
|
-
updatedAt = new Date(resource.updatedAt);
|
|
701
|
-
} else {
|
|
702
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
703
|
-
}
|
|
704
|
-
if (isNaN(updatedAt.getTime())) {
|
|
705
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
706
|
-
}
|
|
707
|
-
} catch {
|
|
708
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
473
|
+
if (!this.client) {
|
|
474
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
709
475
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
workingMemory = void 0;
|
|
713
|
-
} else if (workingMemory === "") {
|
|
714
|
-
workingMemory = "";
|
|
715
|
-
} else if (typeof workingMemory === "object") {
|
|
716
|
-
workingMemory = JSON.stringify(workingMemory);
|
|
476
|
+
if (!tableName) {
|
|
477
|
+
throw new Error("tableName is required for load.");
|
|
717
478
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
metadata = void 0;
|
|
721
|
-
} else if (typeof metadata === "string") {
|
|
722
|
-
try {
|
|
723
|
-
metadata = JSON.parse(metadata);
|
|
724
|
-
} catch {
|
|
725
|
-
metadata = metadata;
|
|
726
|
-
}
|
|
479
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
480
|
+
throw new Error("keys are required and cannot be empty for load.");
|
|
727
481
|
}
|
|
728
|
-
|
|
729
|
-
...resource,
|
|
730
|
-
createdAt,
|
|
731
|
-
updatedAt,
|
|
732
|
-
workingMemory,
|
|
733
|
-
metadata
|
|
734
|
-
};
|
|
735
|
-
} catch (error) {
|
|
482
|
+
} catch (validationError) {
|
|
736
483
|
throw new MastraError(
|
|
737
484
|
{
|
|
738
|
-
id: "
|
|
485
|
+
id: createStorageErrorId("LANCE", "LOAD", "INVALID_ARGS"),
|
|
739
486
|
domain: ErrorDomain.STORAGE,
|
|
740
|
-
category: ErrorCategory.
|
|
487
|
+
category: ErrorCategory.USER,
|
|
488
|
+
text: validationError.message,
|
|
489
|
+
details: { tableName }
|
|
741
490
|
},
|
|
742
|
-
|
|
491
|
+
validationError
|
|
743
492
|
);
|
|
744
493
|
}
|
|
745
|
-
}
|
|
746
|
-
async saveResource({ resource }) {
|
|
747
494
|
try {
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
495
|
+
const table = await this.client.openTable(tableName);
|
|
496
|
+
const tableSchema = await getTableSchema({ tableName, client: this.client });
|
|
497
|
+
const query = table.query();
|
|
498
|
+
if (Object.keys(keys).length > 0) {
|
|
499
|
+
validateKeyTypes(keys, tableSchema);
|
|
500
|
+
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
501
|
+
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
502
|
+
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
503
|
+
if (typeof value === "string") {
|
|
504
|
+
return `${quotedKey} = '${value}'`;
|
|
505
|
+
} else if (value === null) {
|
|
506
|
+
return `${quotedKey} IS NULL`;
|
|
507
|
+
} else {
|
|
508
|
+
return `${quotedKey} = ${value}`;
|
|
509
|
+
}
|
|
510
|
+
}).join(" AND ");
|
|
511
|
+
this.logger.debug("where clause generated: " + filterConditions);
|
|
512
|
+
query.where(filterConditions);
|
|
513
|
+
}
|
|
514
|
+
const result = await query.limit(1).toArray();
|
|
515
|
+
if (result.length === 0) {
|
|
516
|
+
this.logger.debug("No record found");
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
return processResultWithTypeConversion(result[0], tableSchema);
|
|
759
520
|
} catch (error) {
|
|
521
|
+
if (error instanceof MastraError) throw error;
|
|
760
522
|
throw new MastraError(
|
|
761
523
|
{
|
|
762
|
-
id: "
|
|
524
|
+
id: createStorageErrorId("LANCE", "LOAD", "FAILED"),
|
|
763
525
|
domain: ErrorDomain.STORAGE,
|
|
764
|
-
category: ErrorCategory.THIRD_PARTY
|
|
526
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
527
|
+
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
765
528
|
},
|
|
766
529
|
error
|
|
767
530
|
);
|
|
768
531
|
}
|
|
769
532
|
}
|
|
770
|
-
async updateResource({
|
|
771
|
-
resourceId,
|
|
772
|
-
workingMemory,
|
|
773
|
-
metadata
|
|
774
|
-
}) {
|
|
775
|
-
const maxRetries = 3;
|
|
776
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
777
|
-
try {
|
|
778
|
-
const existingResource = await this.getResourceById({ resourceId });
|
|
779
|
-
if (!existingResource) {
|
|
780
|
-
const newResource = {
|
|
781
|
-
id: resourceId,
|
|
782
|
-
workingMemory,
|
|
783
|
-
metadata: metadata || {},
|
|
784
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
785
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
786
|
-
};
|
|
787
|
-
return this.saveResource({ resource: newResource });
|
|
788
|
-
}
|
|
789
|
-
const updatedResource = {
|
|
790
|
-
...existingResource,
|
|
791
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
792
|
-
metadata: {
|
|
793
|
-
...existingResource.metadata,
|
|
794
|
-
...metadata
|
|
795
|
-
},
|
|
796
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
797
|
-
};
|
|
798
|
-
const record = {
|
|
799
|
-
id: resourceId,
|
|
800
|
-
workingMemory: updatedResource.workingMemory || "",
|
|
801
|
-
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
802
|
-
updatedAt: updatedResource.updatedAt.getTime()
|
|
803
|
-
// Store as timestamp (milliseconds)
|
|
804
|
-
};
|
|
805
|
-
const table = await this.client.openTable(TABLE_RESOURCES);
|
|
806
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
807
|
-
return updatedResource;
|
|
808
|
-
} catch (error) {
|
|
809
|
-
if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
810
|
-
const delay = Math.pow(2, attempt) * 10;
|
|
811
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
812
|
-
continue;
|
|
813
|
-
}
|
|
814
|
-
throw new MastraError(
|
|
815
|
-
{
|
|
816
|
-
id: "LANCE_STORE_UPDATE_RESOURCE_FAILED",
|
|
817
|
-
domain: ErrorDomain.STORAGE,
|
|
818
|
-
category: ErrorCategory.THIRD_PARTY
|
|
819
|
-
},
|
|
820
|
-
error
|
|
821
|
-
);
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
throw new Error("Unexpected end of retry loop");
|
|
825
|
-
}
|
|
826
533
|
};
|
|
827
|
-
|
|
534
|
+
|
|
535
|
+
// src/storage/domains/memory/index.ts
|
|
536
|
+
var StoreMemoryLance = class extends MemoryStorage {
|
|
828
537
|
client;
|
|
829
|
-
|
|
538
|
+
#db;
|
|
539
|
+
constructor(config) {
|
|
830
540
|
super();
|
|
541
|
+
const client = resolveLanceConfig(config);
|
|
831
542
|
this.client = client;
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
case "jsonb":
|
|
843
|
-
return "'{}'";
|
|
844
|
-
case "uuid":
|
|
845
|
-
return "''";
|
|
846
|
-
default:
|
|
847
|
-
return super.getDefaultValue(type);
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
async hasColumn(tableName, columnName) {
|
|
851
|
-
const table = await this.client.openTable(tableName);
|
|
852
|
-
const schema = await table.schema();
|
|
853
|
-
return schema.fields.some((field) => field.name === columnName);
|
|
854
|
-
}
|
|
855
|
-
translateSchema(schema) {
|
|
856
|
-
const fields = Object.entries(schema).map(([name, column]) => {
|
|
857
|
-
let arrowType;
|
|
858
|
-
switch (column.type.toLowerCase()) {
|
|
859
|
-
case "text":
|
|
860
|
-
case "uuid":
|
|
861
|
-
arrowType = new Utf8();
|
|
862
|
-
break;
|
|
863
|
-
case "int":
|
|
864
|
-
case "integer":
|
|
865
|
-
arrowType = new Int32();
|
|
866
|
-
break;
|
|
867
|
-
case "bigint":
|
|
868
|
-
arrowType = new Float64();
|
|
869
|
-
break;
|
|
870
|
-
case "float":
|
|
871
|
-
arrowType = new Float32();
|
|
872
|
-
break;
|
|
873
|
-
case "jsonb":
|
|
874
|
-
case "json":
|
|
875
|
-
arrowType = new Utf8();
|
|
876
|
-
break;
|
|
877
|
-
case "binary":
|
|
878
|
-
arrowType = new Binary();
|
|
879
|
-
break;
|
|
880
|
-
case "timestamp":
|
|
881
|
-
arrowType = new Float64();
|
|
882
|
-
break;
|
|
883
|
-
default:
|
|
884
|
-
arrowType = new Utf8();
|
|
885
|
-
}
|
|
886
|
-
return new Field(name, arrowType, column.nullable ?? true);
|
|
543
|
+
this.#db = new LanceDB({ client });
|
|
544
|
+
}
|
|
545
|
+
async init() {
|
|
546
|
+
await this.#db.createTable({ tableName: TABLE_THREADS, schema: TABLE_SCHEMAS[TABLE_THREADS] });
|
|
547
|
+
await this.#db.createTable({ tableName: TABLE_MESSAGES, schema: TABLE_SCHEMAS[TABLE_MESSAGES] });
|
|
548
|
+
await this.#db.createTable({ tableName: TABLE_RESOURCES, schema: TABLE_SCHEMAS[TABLE_RESOURCES] });
|
|
549
|
+
await this.#db.alterTable({
|
|
550
|
+
tableName: TABLE_MESSAGES,
|
|
551
|
+
schema: TABLE_SCHEMAS[TABLE_MESSAGES],
|
|
552
|
+
ifNotExists: ["resourceId"]
|
|
887
553
|
});
|
|
888
|
-
return new Schema(fields);
|
|
889
554
|
}
|
|
890
|
-
async
|
|
891
|
-
tableName
|
|
892
|
-
|
|
893
|
-
|
|
555
|
+
async dangerouslyClearAll() {
|
|
556
|
+
await this.#db.clearTable({ tableName: TABLE_THREADS });
|
|
557
|
+
await this.#db.clearTable({ tableName: TABLE_MESSAGES });
|
|
558
|
+
await this.#db.clearTable({ tableName: TABLE_RESOURCES });
|
|
559
|
+
}
|
|
560
|
+
async deleteMessages(messageIds) {
|
|
561
|
+
if (!messageIds || messageIds.length === 0) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
this.logger.debug("Deleting messages", { count: messageIds.length });
|
|
894
565
|
try {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
566
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
567
|
+
for (const messageId of messageIds) {
|
|
568
|
+
const message = await this.#db.load({ tableName: TABLE_MESSAGES, keys: { id: messageId } });
|
|
569
|
+
if (message?.thread_id) {
|
|
570
|
+
threadIds.add(message.thread_id);
|
|
571
|
+
}
|
|
900
572
|
}
|
|
901
|
-
|
|
902
|
-
|
|
573
|
+
const messagesTable = await this.client.openTable(TABLE_MESSAGES);
|
|
574
|
+
const idConditions = messageIds.map((id) => `id = '${this.escapeSql(id)}'`).join(" OR ");
|
|
575
|
+
await messagesTable.delete(idConditions);
|
|
576
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
577
|
+
const threadsTable = await this.client.openTable(TABLE_THREADS);
|
|
578
|
+
for (const threadId of threadIds) {
|
|
579
|
+
const thread = await this.getThreadById({ threadId });
|
|
580
|
+
if (thread) {
|
|
581
|
+
const record = {
|
|
582
|
+
id: threadId,
|
|
583
|
+
resourceId: thread.resourceId,
|
|
584
|
+
title: thread.title,
|
|
585
|
+
metadata: JSON.stringify(thread.metadata),
|
|
586
|
+
createdAt: new Date(thread.createdAt).getTime(),
|
|
587
|
+
updatedAt: now
|
|
588
|
+
};
|
|
589
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
590
|
+
}
|
|
903
591
|
}
|
|
904
592
|
} catch (error) {
|
|
905
593
|
throw new MastraError(
|
|
906
594
|
{
|
|
907
|
-
id: "
|
|
595
|
+
id: createStorageErrorId("LANCE", "DELETE_MESSAGES", "FAILED"),
|
|
908
596
|
domain: ErrorDomain.STORAGE,
|
|
909
|
-
category: ErrorCategory.
|
|
910
|
-
details: {
|
|
597
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
598
|
+
details: { count: messageIds.length }
|
|
911
599
|
},
|
|
912
600
|
error
|
|
913
601
|
);
|
|
914
602
|
}
|
|
603
|
+
}
|
|
604
|
+
// Utility to escape single quotes in SQL strings
|
|
605
|
+
escapeSql(str) {
|
|
606
|
+
return str.replace(/'/g, "''");
|
|
607
|
+
}
|
|
608
|
+
async getThreadById({ threadId }) {
|
|
915
609
|
try {
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
if (error.message?.includes("already exists")) {
|
|
920
|
-
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
921
|
-
return;
|
|
610
|
+
const thread = await this.#db.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
|
|
611
|
+
if (!thread) {
|
|
612
|
+
return null;
|
|
922
613
|
}
|
|
614
|
+
return {
|
|
615
|
+
...thread,
|
|
616
|
+
createdAt: new Date(thread.createdAt),
|
|
617
|
+
updatedAt: new Date(thread.updatedAt)
|
|
618
|
+
};
|
|
619
|
+
} catch (error) {
|
|
923
620
|
throw new MastraError(
|
|
924
621
|
{
|
|
925
|
-
id: "
|
|
622
|
+
id: createStorageErrorId("LANCE", "GET_THREAD_BY_ID", "FAILED"),
|
|
926
623
|
domain: ErrorDomain.STORAGE,
|
|
927
|
-
category: ErrorCategory.THIRD_PARTY
|
|
928
|
-
details: { tableName }
|
|
624
|
+
category: ErrorCategory.THIRD_PARTY
|
|
929
625
|
},
|
|
930
626
|
error
|
|
931
627
|
);
|
|
932
628
|
}
|
|
933
629
|
}
|
|
934
|
-
|
|
630
|
+
/**
|
|
631
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
632
|
+
* @param thread - The thread to save
|
|
633
|
+
* @returns The saved thread
|
|
634
|
+
*/
|
|
635
|
+
async saveThread({ thread }) {
|
|
935
636
|
try {
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
}
|
|
942
|
-
} catch (validationError) {
|
|
637
|
+
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
638
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
639
|
+
await table.add([record], { mode: "append" });
|
|
640
|
+
return thread;
|
|
641
|
+
} catch (error) {
|
|
943
642
|
throw new MastraError(
|
|
944
643
|
{
|
|
945
|
-
id: "
|
|
644
|
+
id: createStorageErrorId("LANCE", "SAVE_THREAD", "FAILED"),
|
|
946
645
|
domain: ErrorDomain.STORAGE,
|
|
947
|
-
category: ErrorCategory.
|
|
948
|
-
text: validationError.message,
|
|
949
|
-
details: { tableName }
|
|
646
|
+
category: ErrorCategory.THIRD_PARTY
|
|
950
647
|
},
|
|
951
|
-
|
|
648
|
+
error
|
|
952
649
|
);
|
|
953
650
|
}
|
|
651
|
+
}
|
|
652
|
+
async updateThread({
|
|
653
|
+
id,
|
|
654
|
+
title,
|
|
655
|
+
metadata
|
|
656
|
+
}) {
|
|
657
|
+
const maxRetries = 5;
|
|
658
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
659
|
+
try {
|
|
660
|
+
const current = await this.getThreadById({ threadId: id });
|
|
661
|
+
if (!current) {
|
|
662
|
+
throw new Error(`Thread with id ${id} not found`);
|
|
663
|
+
}
|
|
664
|
+
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
665
|
+
const record = {
|
|
666
|
+
id,
|
|
667
|
+
title,
|
|
668
|
+
metadata: JSON.stringify(mergedMetadata),
|
|
669
|
+
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
670
|
+
};
|
|
671
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
672
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
673
|
+
const updatedThread = await this.getThreadById({ threadId: id });
|
|
674
|
+
if (!updatedThread) {
|
|
675
|
+
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
676
|
+
}
|
|
677
|
+
return updatedThread;
|
|
678
|
+
} catch (error) {
|
|
679
|
+
if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
680
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
681
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
throw new MastraError(
|
|
685
|
+
{
|
|
686
|
+
id: createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
687
|
+
domain: ErrorDomain.STORAGE,
|
|
688
|
+
category: ErrorCategory.THIRD_PARTY
|
|
689
|
+
},
|
|
690
|
+
error
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
throw new MastraError(
|
|
695
|
+
{
|
|
696
|
+
id: createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
697
|
+
domain: ErrorDomain.STORAGE,
|
|
698
|
+
category: ErrorCategory.THIRD_PARTY
|
|
699
|
+
},
|
|
700
|
+
new Error("All retries exhausted")
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
async deleteThread({ threadId }) {
|
|
954
704
|
try {
|
|
955
|
-
await this.client.
|
|
705
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
706
|
+
await table.delete(`id = '${threadId}'`);
|
|
707
|
+
const messagesTable = await this.client.openTable(TABLE_MESSAGES);
|
|
708
|
+
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
956
709
|
} catch (error) {
|
|
957
|
-
if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
|
|
958
|
-
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
710
|
throw new MastraError(
|
|
962
711
|
{
|
|
963
|
-
id: "
|
|
712
|
+
id: createStorageErrorId("LANCE", "DELETE_THREAD", "FAILED"),
|
|
964
713
|
domain: ErrorDomain.STORAGE,
|
|
965
|
-
category: ErrorCategory.THIRD_PARTY
|
|
966
|
-
details: { tableName }
|
|
714
|
+
category: ErrorCategory.THIRD_PARTY
|
|
967
715
|
},
|
|
968
716
|
error
|
|
969
717
|
);
|
|
970
718
|
}
|
|
971
719
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
this.logger.debug("No columns specified to add in alterTable, skipping.");
|
|
989
|
-
return;
|
|
990
|
-
}
|
|
991
|
-
} catch (validationError) {
|
|
992
|
-
throw new MastraError(
|
|
993
|
-
{
|
|
994
|
-
id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_INVALID_ARGS",
|
|
995
|
-
domain: ErrorDomain.STORAGE,
|
|
996
|
-
category: ErrorCategory.USER,
|
|
997
|
-
text: validationError.message,
|
|
998
|
-
details: { tableName }
|
|
999
|
-
},
|
|
1000
|
-
validationError
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
720
|
+
normalizeMessage(message) {
|
|
721
|
+
const { thread_id, ...rest } = message;
|
|
722
|
+
return {
|
|
723
|
+
...rest,
|
|
724
|
+
threadId: thread_id,
|
|
725
|
+
content: typeof message.content === "string" ? (() => {
|
|
726
|
+
try {
|
|
727
|
+
return JSON.parse(message.content);
|
|
728
|
+
} catch {
|
|
729
|
+
return message.content;
|
|
730
|
+
}
|
|
731
|
+
})() : message.content
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
async listMessagesById({ messageIds }) {
|
|
735
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1003
736
|
try {
|
|
1004
|
-
const table = await this.client.openTable(
|
|
1005
|
-
const
|
|
1006
|
-
const
|
|
1007
|
-
const
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
const colDef = schema[col];
|
|
1017
|
-
return {
|
|
1018
|
-
name: col,
|
|
1019
|
-
valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
|
|
1020
|
-
};
|
|
1021
|
-
});
|
|
1022
|
-
if (columnsToAdd.length > 0) {
|
|
1023
|
-
await table.addColumns(columnsToAdd);
|
|
1024
|
-
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
1025
|
-
}
|
|
737
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
738
|
+
const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
|
|
739
|
+
const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
|
|
740
|
+
const messages = processResultWithTypeConversion(
|
|
741
|
+
allRecords,
|
|
742
|
+
await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
|
|
743
|
+
);
|
|
744
|
+
const list = new MessageList().add(
|
|
745
|
+
messages.map(this.normalizeMessage),
|
|
746
|
+
"memory"
|
|
747
|
+
);
|
|
748
|
+
return { messages: list.get.all.db() };
|
|
1026
749
|
} catch (error) {
|
|
1027
750
|
throw new MastraError(
|
|
1028
751
|
{
|
|
1029
|
-
id: "
|
|
752
|
+
id: createStorageErrorId("LANCE", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1030
753
|
domain: ErrorDomain.STORAGE,
|
|
1031
754
|
category: ErrorCategory.THIRD_PARTY,
|
|
1032
|
-
details: {
|
|
755
|
+
details: {
|
|
756
|
+
messageIds: JSON.stringify(messageIds)
|
|
757
|
+
}
|
|
1033
758
|
},
|
|
1034
759
|
error
|
|
1035
760
|
);
|
|
1036
761
|
}
|
|
1037
762
|
}
|
|
1038
|
-
async
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
}
|
|
1043
|
-
if (!tableName) {
|
|
1044
|
-
throw new Error("tableName is required for clearTable.");
|
|
1045
|
-
}
|
|
1046
|
-
} catch (validationError) {
|
|
763
|
+
async listMessages(args) {
|
|
764
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
765
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
766
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
1047
767
|
throw new MastraError(
|
|
1048
768
|
{
|
|
1049
|
-
id: "
|
|
769
|
+
id: createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1050
770
|
domain: ErrorDomain.STORAGE,
|
|
1051
|
-
category: ErrorCategory.
|
|
1052
|
-
|
|
1053
|
-
details: { tableName }
|
|
771
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
772
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1054
773
|
},
|
|
1055
|
-
|
|
774
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1056
775
|
);
|
|
1057
776
|
}
|
|
777
|
+
const perPage = normalizePerPage(perPageInput, 40);
|
|
778
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1058
779
|
try {
|
|
1059
|
-
|
|
1060
|
-
|
|
780
|
+
if (page < 0) {
|
|
781
|
+
throw new MastraError(
|
|
782
|
+
{
|
|
783
|
+
id: createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
784
|
+
domain: ErrorDomain.STORAGE,
|
|
785
|
+
category: ErrorCategory.USER,
|
|
786
|
+
details: { page }
|
|
787
|
+
},
|
|
788
|
+
new Error("page must be >= 0")
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
792
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
793
|
+
const threadCondition = threadIds.length === 1 ? `thread_id = '${this.escapeSql(threadIds[0])}'` : `thread_id IN (${threadIds.map((t) => `'${this.escapeSql(t)}'`).join(", ")})`;
|
|
794
|
+
const conditions = [threadCondition];
|
|
795
|
+
if (resourceId) {
|
|
796
|
+
conditions.push(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
797
|
+
}
|
|
798
|
+
if (filter?.dateRange?.start) {
|
|
799
|
+
const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
|
|
800
|
+
conditions.push(`\`createdAt\` >= ${startTime}`);
|
|
801
|
+
}
|
|
802
|
+
if (filter?.dateRange?.end) {
|
|
803
|
+
const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
|
|
804
|
+
conditions.push(`\`createdAt\` <= ${endTime}`);
|
|
805
|
+
}
|
|
806
|
+
const whereClause = conditions.join(" AND ");
|
|
807
|
+
const total = await table.countRows(whereClause);
|
|
808
|
+
const query = table.query().where(whereClause);
|
|
809
|
+
let allRecords = await query.toArray();
|
|
810
|
+
allRecords.sort((a, b) => {
|
|
811
|
+
const aValue = field === "createdAt" ? a.createdAt : a[field];
|
|
812
|
+
const bValue = field === "createdAt" ? b.createdAt : b[field];
|
|
813
|
+
if (aValue == null && bValue == null) return 0;
|
|
814
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
815
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
816
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
817
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
818
|
+
}
|
|
819
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
820
|
+
});
|
|
821
|
+
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
822
|
+
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
823
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
824
|
+
return {
|
|
825
|
+
messages: [],
|
|
826
|
+
total: 0,
|
|
827
|
+
page,
|
|
828
|
+
perPage: perPageForResponse,
|
|
829
|
+
hasMore: false
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
833
|
+
if (include && include.length > 0) {
|
|
834
|
+
const threadIds2 = [...new Set(include.map((item) => item.threadId || threadId))];
|
|
835
|
+
const allThreadMessages = [];
|
|
836
|
+
for (const tid of threadIds2) {
|
|
837
|
+
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
838
|
+
let threadRecords = await threadQuery.toArray();
|
|
839
|
+
allThreadMessages.push(...threadRecords);
|
|
840
|
+
}
|
|
841
|
+
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
842
|
+
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
843
|
+
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
844
|
+
for (const includeMsg of includedMessages) {
|
|
845
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
846
|
+
messages.push(includeMsg);
|
|
847
|
+
messageIds.add(includeMsg.id);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
const list = new MessageList().add(messages, "memory");
|
|
852
|
+
let finalMessages = list.get.all.db();
|
|
853
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
854
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
855
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
856
|
+
if (aValue == null && bValue == null) return 0;
|
|
857
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
858
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
859
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
860
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
861
|
+
}
|
|
862
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
863
|
+
});
|
|
864
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
865
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
866
|
+
const fetchedAll = perPageInput === false || allThreadMessagesReturned;
|
|
867
|
+
const hasMore = !fetchedAll && offset + perPage < total;
|
|
868
|
+
return {
|
|
869
|
+
messages: finalMessages,
|
|
870
|
+
total,
|
|
871
|
+
page,
|
|
872
|
+
perPage: perPageForResponse,
|
|
873
|
+
hasMore
|
|
874
|
+
};
|
|
1061
875
|
} catch (error) {
|
|
1062
|
-
|
|
876
|
+
const mastraError = new MastraError(
|
|
1063
877
|
{
|
|
1064
|
-
id: "
|
|
878
|
+
id: createStorageErrorId("LANCE", "LIST_MESSAGES", "FAILED"),
|
|
1065
879
|
domain: ErrorDomain.STORAGE,
|
|
1066
880
|
category: ErrorCategory.THIRD_PARTY,
|
|
1067
|
-
details: {
|
|
881
|
+
details: {
|
|
882
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
883
|
+
resourceId: resourceId ?? ""
|
|
884
|
+
}
|
|
1068
885
|
},
|
|
1069
886
|
error
|
|
1070
887
|
);
|
|
888
|
+
this.logger?.error?.(mastraError.toString());
|
|
889
|
+
this.logger?.trackException?.(mastraError);
|
|
890
|
+
return {
|
|
891
|
+
messages: [],
|
|
892
|
+
total: 0,
|
|
893
|
+
page,
|
|
894
|
+
perPage: perPageForResponse,
|
|
895
|
+
hasMore: false
|
|
896
|
+
};
|
|
1071
897
|
}
|
|
1072
898
|
}
|
|
1073
|
-
async
|
|
899
|
+
async saveMessages(args) {
|
|
1074
900
|
try {
|
|
1075
|
-
|
|
1076
|
-
|
|
901
|
+
const { messages } = args;
|
|
902
|
+
if (messages.length === 0) {
|
|
903
|
+
return { messages: [] };
|
|
1077
904
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
905
|
+
const threadId = messages[0]?.threadId;
|
|
906
|
+
if (!threadId) {
|
|
907
|
+
throw new Error("Thread ID is required");
|
|
1080
908
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
909
|
+
for (const message of messages) {
|
|
910
|
+
if (!message.id) {
|
|
911
|
+
throw new Error("Message ID is required");
|
|
912
|
+
}
|
|
913
|
+
if (!message.threadId) {
|
|
914
|
+
throw new Error("Thread ID is required for all messages");
|
|
915
|
+
}
|
|
916
|
+
if (message.resourceId === null || message.resourceId === void 0) {
|
|
917
|
+
throw new Error("Resource ID cannot be null or undefined");
|
|
918
|
+
}
|
|
919
|
+
if (!message.content) {
|
|
920
|
+
throw new Error("Message content is required");
|
|
921
|
+
}
|
|
1083
922
|
}
|
|
1084
|
-
|
|
923
|
+
const transformedMessages = messages.map((message) => {
|
|
924
|
+
const { threadId: threadId2, type, ...rest } = message;
|
|
925
|
+
return {
|
|
926
|
+
...rest,
|
|
927
|
+
thread_id: threadId2,
|
|
928
|
+
type: type ?? "v2",
|
|
929
|
+
content: JSON.stringify(message.content)
|
|
930
|
+
};
|
|
931
|
+
});
|
|
932
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
933
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
934
|
+
const threadsTable = await this.client.openTable(TABLE_THREADS);
|
|
935
|
+
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
936
|
+
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
937
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
938
|
+
const list = new MessageList().add(messages, "memory");
|
|
939
|
+
return { messages: list.get.all.db() };
|
|
940
|
+
} catch (error) {
|
|
1085
941
|
throw new MastraError(
|
|
1086
942
|
{
|
|
1087
|
-
id: "
|
|
943
|
+
id: createStorageErrorId("LANCE", "SAVE_MESSAGES", "FAILED"),
|
|
1088
944
|
domain: ErrorDomain.STORAGE,
|
|
1089
|
-
category: ErrorCategory.
|
|
1090
|
-
text: validationError.message,
|
|
1091
|
-
details: { tableName }
|
|
945
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1092
946
|
},
|
|
1093
|
-
|
|
947
|
+
error
|
|
1094
948
|
);
|
|
1095
949
|
}
|
|
950
|
+
}
|
|
951
|
+
async listThreadsByResourceId(args) {
|
|
1096
952
|
try {
|
|
1097
|
-
const
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
953
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
954
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
955
|
+
if (page < 0) {
|
|
956
|
+
throw new MastraError(
|
|
957
|
+
{
|
|
958
|
+
id: createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
959
|
+
domain: ErrorDomain.STORAGE,
|
|
960
|
+
category: ErrorCategory.USER,
|
|
961
|
+
details: { page }
|
|
962
|
+
},
|
|
963
|
+
new Error("page must be >= 0")
|
|
964
|
+
);
|
|
1105
965
|
}
|
|
1106
|
-
|
|
1107
|
-
|
|
966
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
967
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
968
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
969
|
+
const total = await table.countRows(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
970
|
+
const query = table.query().where(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
971
|
+
const records = await query.toArray();
|
|
972
|
+
records.sort((a, b) => {
|
|
973
|
+
const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
|
|
974
|
+
const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
|
|
975
|
+
if (aValue == null && bValue == null) return 0;
|
|
976
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
977
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
978
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
979
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
980
|
+
}
|
|
981
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
982
|
+
});
|
|
983
|
+
const paginatedRecords = records.slice(offset, offset + perPage);
|
|
984
|
+
const schema = await getTableSchema({ tableName: TABLE_THREADS, client: this.client });
|
|
985
|
+
const threads = paginatedRecords.map(
|
|
986
|
+
(record) => processResultWithTypeConversion(record, schema)
|
|
987
|
+
);
|
|
988
|
+
return {
|
|
989
|
+
threads,
|
|
990
|
+
total,
|
|
991
|
+
page,
|
|
992
|
+
perPage: perPageForResponse,
|
|
993
|
+
hasMore: offset + perPage < total
|
|
994
|
+
};
|
|
1108
995
|
} catch (error) {
|
|
1109
996
|
throw new MastraError(
|
|
1110
997
|
{
|
|
1111
|
-
id: "
|
|
998
|
+
id: createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
1112
999
|
domain: ErrorDomain.STORAGE,
|
|
1113
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1114
|
-
details: { tableName }
|
|
1000
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1115
1001
|
},
|
|
1116
1002
|
error
|
|
1117
1003
|
);
|
|
1118
1004
|
}
|
|
1119
1005
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1006
|
+
/**
|
|
1007
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
1008
|
+
* @param records - The sorted array of records to process
|
|
1009
|
+
* @param include - The array of include specifications with context parameters
|
|
1010
|
+
* @returns The processed array with context messages included
|
|
1011
|
+
*/
|
|
1012
|
+
processMessagesWithContext(records, include) {
|
|
1013
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
1014
|
+
if (messagesWithContext.length === 0) {
|
|
1015
|
+
return records;
|
|
1016
|
+
}
|
|
1017
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1018
|
+
records.forEach((message, index) => {
|
|
1019
|
+
messageIndexMap.set(message.id, index);
|
|
1020
|
+
});
|
|
1021
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
1022
|
+
for (const item of messagesWithContext) {
|
|
1023
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
1024
|
+
if (messageIndex !== void 0) {
|
|
1025
|
+
if (item.withPreviousMessages) {
|
|
1026
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
1027
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
1028
|
+
additionalIndices.add(i);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
if (item.withNextMessages) {
|
|
1032
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
1033
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
1034
|
+
additionalIndices.add(i);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1127
1037
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1038
|
+
}
|
|
1039
|
+
if (additionalIndices.size === 0) {
|
|
1040
|
+
return records;
|
|
1041
|
+
}
|
|
1042
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1043
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
1044
|
+
records.forEach((record, index) => {
|
|
1045
|
+
if (originalMatchIds.has(record.id)) {
|
|
1046
|
+
allIndices.add(index);
|
|
1130
1047
|
}
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1048
|
+
});
|
|
1049
|
+
additionalIndices.forEach((index) => {
|
|
1050
|
+
allIndices.add(index);
|
|
1051
|
+
});
|
|
1052
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Parse message data from LanceDB record format to MastraDBMessage format
|
|
1056
|
+
*/
|
|
1057
|
+
parseMessageData(data) {
|
|
1058
|
+
const { thread_id, ...rest } = data;
|
|
1059
|
+
return {
|
|
1060
|
+
...rest,
|
|
1061
|
+
threadId: thread_id,
|
|
1062
|
+
content: typeof data.content === "string" ? (() => {
|
|
1063
|
+
try {
|
|
1064
|
+
return JSON.parse(data.content);
|
|
1065
|
+
} catch {
|
|
1066
|
+
return data.content;
|
|
1067
|
+
}
|
|
1068
|
+
})() : data.content,
|
|
1069
|
+
createdAt: new Date(data.createdAt),
|
|
1070
|
+
updatedAt: new Date(data.updatedAt)
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
async updateMessages(args) {
|
|
1074
|
+
const { messages } = args;
|
|
1075
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1076
|
+
if (!messages.length) {
|
|
1077
|
+
return [];
|
|
1142
1078
|
}
|
|
1079
|
+
const updatedMessages = [];
|
|
1080
|
+
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
1143
1081
|
try {
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1082
|
+
for (const updateData of messages) {
|
|
1083
|
+
const { id, ...updates } = updateData;
|
|
1084
|
+
const existingMessage = await this.#db.load({ tableName: TABLE_MESSAGES, keys: { id } });
|
|
1085
|
+
if (!existingMessage) {
|
|
1086
|
+
this.logger.warn("Message not found for update", { id });
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
const existingMsg = this.parseMessageData(existingMessage);
|
|
1090
|
+
const originalThreadId = existingMsg.threadId;
|
|
1091
|
+
affectedThreadIds.add(originalThreadId);
|
|
1092
|
+
const updatePayload = {};
|
|
1093
|
+
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
1094
|
+
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
1095
|
+
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
1096
|
+
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
1097
|
+
updatePayload.thread_id = updates.threadId;
|
|
1098
|
+
affectedThreadIds.add(updates.threadId);
|
|
1099
|
+
}
|
|
1100
|
+
if (updates.content) {
|
|
1101
|
+
const existingContent = existingMsg.content;
|
|
1102
|
+
let newContent = { ...existingContent };
|
|
1103
|
+
if (updates.content.metadata !== void 0) {
|
|
1104
|
+
newContent.metadata = {
|
|
1105
|
+
...existingContent.metadata || {},
|
|
1106
|
+
...updates.content.metadata || {}
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
if (updates.content.content !== void 0) {
|
|
1110
|
+
newContent.content = updates.content.content;
|
|
1152
1111
|
}
|
|
1112
|
+
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
1113
|
+
newContent.parts = updates.content.parts;
|
|
1114
|
+
}
|
|
1115
|
+
updatePayload.content = JSON.stringify(newContent);
|
|
1153
1116
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1117
|
+
await this.#db.insert({ tableName: TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
1118
|
+
const updatedMessage = await this.#db.load({ tableName: TABLE_MESSAGES, keys: { id } });
|
|
1119
|
+
if (updatedMessage) {
|
|
1120
|
+
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
for (const threadId of affectedThreadIds) {
|
|
1124
|
+
await this.#db.insert({
|
|
1125
|
+
tableName: TABLE_THREADS,
|
|
1126
|
+
record: { id: threadId, updatedAt: Date.now() }
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
return updatedMessages;
|
|
1157
1130
|
} catch (error) {
|
|
1158
1131
|
throw new MastraError(
|
|
1159
1132
|
{
|
|
1160
|
-
id: "
|
|
1133
|
+
id: createStorageErrorId("LANCE", "UPDATE_MESSAGES", "FAILED"),
|
|
1161
1134
|
domain: ErrorDomain.STORAGE,
|
|
1162
1135
|
category: ErrorCategory.THIRD_PARTY,
|
|
1163
|
-
details: {
|
|
1136
|
+
details: { count: messages.length }
|
|
1164
1137
|
},
|
|
1165
1138
|
error
|
|
1166
1139
|
);
|
|
1167
1140
|
}
|
|
1168
1141
|
}
|
|
1169
|
-
async
|
|
1142
|
+
async getResourceById({ resourceId }) {
|
|
1170
1143
|
try {
|
|
1171
|
-
|
|
1172
|
-
|
|
1144
|
+
const resource = await this.#db.load({ tableName: TABLE_RESOURCES, keys: { id: resourceId } });
|
|
1145
|
+
if (!resource) {
|
|
1146
|
+
return null;
|
|
1173
1147
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1148
|
+
let createdAt;
|
|
1149
|
+
let updatedAt;
|
|
1150
|
+
try {
|
|
1151
|
+
if (resource.createdAt instanceof Date) {
|
|
1152
|
+
createdAt = resource.createdAt;
|
|
1153
|
+
} else if (typeof resource.createdAt === "string") {
|
|
1154
|
+
createdAt = new Date(resource.createdAt);
|
|
1155
|
+
} else if (typeof resource.createdAt === "number") {
|
|
1156
|
+
createdAt = new Date(resource.createdAt);
|
|
1157
|
+
} else {
|
|
1158
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1159
|
+
}
|
|
1160
|
+
if (isNaN(createdAt.getTime())) {
|
|
1161
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1162
|
+
}
|
|
1163
|
+
} catch {
|
|
1164
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1176
1165
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1166
|
+
try {
|
|
1167
|
+
if (resource.updatedAt instanceof Date) {
|
|
1168
|
+
updatedAt = resource.updatedAt;
|
|
1169
|
+
} else if (typeof resource.updatedAt === "string") {
|
|
1170
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1171
|
+
} else if (typeof resource.updatedAt === "number") {
|
|
1172
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1173
|
+
} else {
|
|
1174
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1175
|
+
}
|
|
1176
|
+
if (isNaN(updatedAt.getTime())) {
|
|
1177
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1178
|
+
}
|
|
1179
|
+
} catch {
|
|
1180
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1179
1181
|
}
|
|
1180
|
-
|
|
1182
|
+
let workingMemory = resource.workingMemory;
|
|
1183
|
+
if (workingMemory === null || workingMemory === void 0) {
|
|
1184
|
+
workingMemory = void 0;
|
|
1185
|
+
} else if (workingMemory === "") {
|
|
1186
|
+
workingMemory = "";
|
|
1187
|
+
} else if (typeof workingMemory === "object") {
|
|
1188
|
+
workingMemory = JSON.stringify(workingMemory);
|
|
1189
|
+
}
|
|
1190
|
+
let metadata = resource.metadata;
|
|
1191
|
+
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
1192
|
+
metadata = void 0;
|
|
1193
|
+
} else if (typeof metadata === "string") {
|
|
1194
|
+
try {
|
|
1195
|
+
metadata = JSON.parse(metadata);
|
|
1196
|
+
} catch {
|
|
1197
|
+
metadata = metadata;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return {
|
|
1201
|
+
...resource,
|
|
1202
|
+
createdAt,
|
|
1203
|
+
updatedAt,
|
|
1204
|
+
workingMemory,
|
|
1205
|
+
metadata
|
|
1206
|
+
};
|
|
1207
|
+
} catch (error) {
|
|
1181
1208
|
throw new MastraError(
|
|
1182
1209
|
{
|
|
1183
|
-
id: "
|
|
1210
|
+
id: createStorageErrorId("LANCE", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
1184
1211
|
domain: ErrorDomain.STORAGE,
|
|
1185
|
-
category: ErrorCategory.
|
|
1186
|
-
text: validationError.message,
|
|
1187
|
-
details: { tableName }
|
|
1212
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1188
1213
|
},
|
|
1189
|
-
|
|
1214
|
+
error
|
|
1190
1215
|
);
|
|
1191
1216
|
}
|
|
1217
|
+
}
|
|
1218
|
+
async saveResource({ resource }) {
|
|
1192
1219
|
try {
|
|
1193
|
-
const
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
return `${quotedKey} IS NULL`;
|
|
1205
|
-
} else {
|
|
1206
|
-
return `${quotedKey} = ${value}`;
|
|
1207
|
-
}
|
|
1208
|
-
}).join(" AND ");
|
|
1209
|
-
this.logger.debug("where clause generated: " + filterConditions);
|
|
1210
|
-
query.where(filterConditions);
|
|
1211
|
-
}
|
|
1212
|
-
const result = await query.limit(1).toArray();
|
|
1213
|
-
if (result.length === 0) {
|
|
1214
|
-
this.logger.debug("No record found");
|
|
1215
|
-
return null;
|
|
1216
|
-
}
|
|
1217
|
-
return processResultWithTypeConversion(result[0], tableSchema);
|
|
1220
|
+
const record = {
|
|
1221
|
+
...resource,
|
|
1222
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
1223
|
+
createdAt: resource.createdAt.getTime(),
|
|
1224
|
+
// Store as timestamp (milliseconds)
|
|
1225
|
+
updatedAt: resource.updatedAt.getTime()
|
|
1226
|
+
// Store as timestamp (milliseconds)
|
|
1227
|
+
};
|
|
1228
|
+
const table = await this.client.openTable(TABLE_RESOURCES);
|
|
1229
|
+
await table.add([record], { mode: "append" });
|
|
1230
|
+
return resource;
|
|
1218
1231
|
} catch (error) {
|
|
1219
|
-
if (error instanceof MastraError) throw error;
|
|
1220
1232
|
throw new MastraError(
|
|
1221
1233
|
{
|
|
1222
|
-
id: "
|
|
1234
|
+
id: createStorageErrorId("LANCE", "SAVE_RESOURCE", "FAILED"),
|
|
1223
1235
|
domain: ErrorDomain.STORAGE,
|
|
1224
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1225
|
-
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
1236
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1226
1237
|
},
|
|
1227
1238
|
error
|
|
1228
1239
|
);
|
|
1229
1240
|
}
|
|
1230
1241
|
}
|
|
1242
|
+
async updateResource({
|
|
1243
|
+
resourceId,
|
|
1244
|
+
workingMemory,
|
|
1245
|
+
metadata
|
|
1246
|
+
}) {
|
|
1247
|
+
const maxRetries = 3;
|
|
1248
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1249
|
+
try {
|
|
1250
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1251
|
+
if (!existingResource) {
|
|
1252
|
+
const newResource = {
|
|
1253
|
+
id: resourceId,
|
|
1254
|
+
workingMemory,
|
|
1255
|
+
metadata: metadata || {},
|
|
1256
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1257
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1258
|
+
};
|
|
1259
|
+
return this.saveResource({ resource: newResource });
|
|
1260
|
+
}
|
|
1261
|
+
const updatedResource = {
|
|
1262
|
+
...existingResource,
|
|
1263
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1264
|
+
metadata: {
|
|
1265
|
+
...existingResource.metadata,
|
|
1266
|
+
...metadata
|
|
1267
|
+
},
|
|
1268
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1269
|
+
};
|
|
1270
|
+
const record = {
|
|
1271
|
+
id: resourceId,
|
|
1272
|
+
workingMemory: updatedResource.workingMemory || "",
|
|
1273
|
+
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
1274
|
+
updatedAt: updatedResource.updatedAt.getTime()
|
|
1275
|
+
// Store as timestamp (milliseconds)
|
|
1276
|
+
};
|
|
1277
|
+
const table = await this.client.openTable(TABLE_RESOURCES);
|
|
1278
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1279
|
+
return updatedResource;
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
1282
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
1283
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
throw new MastraError(
|
|
1287
|
+
{
|
|
1288
|
+
id: createStorageErrorId("LANCE", "UPDATE_RESOURCE", "FAILED"),
|
|
1289
|
+
domain: ErrorDomain.STORAGE,
|
|
1290
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1291
|
+
},
|
|
1292
|
+
error
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
throw new Error("Unexpected end of retry loop");
|
|
1297
|
+
}
|
|
1231
1298
|
};
|
|
1232
1299
|
var StoreScoresLance = class extends ScoresStorage {
|
|
1233
1300
|
client;
|
|
1234
|
-
|
|
1301
|
+
#db;
|
|
1302
|
+
constructor(config) {
|
|
1235
1303
|
super();
|
|
1304
|
+
const client = resolveLanceConfig(config);
|
|
1236
1305
|
this.client = client;
|
|
1306
|
+
this.#db = new LanceDB({ client });
|
|
1307
|
+
}
|
|
1308
|
+
async init() {
|
|
1309
|
+
await this.#db.createTable({ tableName: TABLE_SCORERS, schema: SCORERS_SCHEMA });
|
|
1310
|
+
await this.#db.alterTable({
|
|
1311
|
+
tableName: TABLE_SCORERS,
|
|
1312
|
+
schema: SCORERS_SCHEMA,
|
|
1313
|
+
ifNotExists: ["spanId", "requestContext"]
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
async dangerouslyClearAll() {
|
|
1317
|
+
await this.#db.clearTable({ tableName: TABLE_SCORERS });
|
|
1237
1318
|
}
|
|
1238
1319
|
async saveScore(score) {
|
|
1239
1320
|
let validatedScore;
|
|
@@ -1242,39 +1323,47 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1242
1323
|
} catch (error) {
|
|
1243
1324
|
throw new MastraError(
|
|
1244
1325
|
{
|
|
1245
|
-
id: "
|
|
1326
|
+
id: createStorageErrorId("LANCE", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
1246
1327
|
text: "Failed to save score in LanceStorage",
|
|
1247
1328
|
domain: ErrorDomain.STORAGE,
|
|
1248
|
-
category: ErrorCategory.
|
|
1329
|
+
category: ErrorCategory.USER,
|
|
1330
|
+
details: {
|
|
1331
|
+
scorer: score.scorer?.id ?? "unknown",
|
|
1332
|
+
entityId: score.entityId ?? "unknown",
|
|
1333
|
+
entityType: score.entityType ?? "unknown",
|
|
1334
|
+
traceId: score.traceId ?? "",
|
|
1335
|
+
spanId: score.spanId ?? ""
|
|
1336
|
+
}
|
|
1249
1337
|
},
|
|
1250
1338
|
error
|
|
1251
1339
|
);
|
|
1252
1340
|
}
|
|
1341
|
+
const id = crypto.randomUUID();
|
|
1342
|
+
const now = /* @__PURE__ */ new Date();
|
|
1253
1343
|
try {
|
|
1254
|
-
const id = crypto.randomUUID();
|
|
1255
1344
|
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1256
1345
|
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1257
1346
|
const allowedFields = new Set(schema.fields.map((f) => f.name));
|
|
1258
1347
|
const filteredScore = {};
|
|
1259
|
-
Object.keys(validatedScore)
|
|
1348
|
+
for (const key of Object.keys(validatedScore)) {
|
|
1260
1349
|
if (allowedFields.has(key)) {
|
|
1261
|
-
filteredScore[key] =
|
|
1350
|
+
filteredScore[key] = validatedScore[key];
|
|
1262
1351
|
}
|
|
1263
|
-
}
|
|
1352
|
+
}
|
|
1264
1353
|
for (const key in filteredScore) {
|
|
1265
1354
|
if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
|
|
1266
1355
|
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
1267
1356
|
}
|
|
1268
1357
|
}
|
|
1269
|
-
filteredScore.createdAt = /* @__PURE__ */ new Date();
|
|
1270
|
-
filteredScore.updatedAt = /* @__PURE__ */ new Date();
|
|
1271
1358
|
filteredScore.id = id;
|
|
1359
|
+
filteredScore.createdAt = now;
|
|
1360
|
+
filteredScore.updatedAt = now;
|
|
1272
1361
|
await table.add([filteredScore], { mode: "append" });
|
|
1273
|
-
return { score };
|
|
1362
|
+
return { score: { ...validatedScore, id, createdAt: now, updatedAt: now } };
|
|
1274
1363
|
} catch (error) {
|
|
1275
1364
|
throw new MastraError(
|
|
1276
1365
|
{
|
|
1277
|
-
id: "
|
|
1366
|
+
id: createStorageErrorId("LANCE", "SAVE_SCORE", "FAILED"),
|
|
1278
1367
|
text: "Failed to save score in LanceStorage",
|
|
1279
1368
|
domain: ErrorDomain.STORAGE,
|
|
1280
1369
|
category: ErrorCategory.THIRD_PARTY,
|
|
@@ -1294,7 +1383,7 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1294
1383
|
} catch (error) {
|
|
1295
1384
|
throw new MastraError(
|
|
1296
1385
|
{
|
|
1297
|
-
id: "
|
|
1386
|
+
id: createStorageErrorId("LANCE", "GET_SCORE_BY_ID", "FAILED"),
|
|
1298
1387
|
text: "Failed to get score by id in LanceStorage",
|
|
1299
1388
|
domain: ErrorDomain.STORAGE,
|
|
1300
1389
|
category: ErrorCategory.THIRD_PARTY,
|
|
@@ -1304,15 +1393,21 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1304
1393
|
);
|
|
1305
1394
|
}
|
|
1306
1395
|
}
|
|
1396
|
+
/**
|
|
1397
|
+
* LanceDB-specific score row transformation.
|
|
1398
|
+
*
|
|
1399
|
+
* Note: This implementation does NOT use coreTransformScoreRow because:
|
|
1400
|
+
* 1. LanceDB stores schema information in the table itself (requires async fetch)
|
|
1401
|
+
* 2. Uses processResultWithTypeConversion utility for LanceDB-specific type handling
|
|
1402
|
+
*/
|
|
1307
1403
|
async transformScoreRow(row) {
|
|
1308
1404
|
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1309
1405
|
const transformed = processResultWithTypeConversion(row, schema);
|
|
1310
|
-
|
|
1406
|
+
return {
|
|
1311
1407
|
...transformed,
|
|
1312
1408
|
createdAt: row.createdAt,
|
|
1313
1409
|
updatedAt: row.updatedAt
|
|
1314
1410
|
};
|
|
1315
|
-
return result;
|
|
1316
1411
|
}
|
|
1317
1412
|
async listScoresByScorerId({
|
|
1318
1413
|
scorerId,
|
|
@@ -1367,7 +1462,7 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1367
1462
|
} catch (error) {
|
|
1368
1463
|
throw new MastraError(
|
|
1369
1464
|
{
|
|
1370
|
-
id: "
|
|
1465
|
+
id: createStorageErrorId("LANCE", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
|
|
1371
1466
|
text: "Failed to get scores by scorerId in LanceStorage",
|
|
1372
1467
|
domain: ErrorDomain.STORAGE,
|
|
1373
1468
|
category: ErrorCategory.THIRD_PARTY,
|
|
@@ -1408,7 +1503,7 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1408
1503
|
} catch (error) {
|
|
1409
1504
|
throw new MastraError(
|
|
1410
1505
|
{
|
|
1411
|
-
id: "
|
|
1506
|
+
id: createStorageErrorId("LANCE", "LIST_SCORES_BY_RUN_ID", "FAILED"),
|
|
1412
1507
|
text: "Failed to get scores by runId in LanceStorage",
|
|
1413
1508
|
domain: ErrorDomain.STORAGE,
|
|
1414
1509
|
category: ErrorCategory.THIRD_PARTY,
|
|
@@ -1450,7 +1545,7 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1450
1545
|
} catch (error) {
|
|
1451
1546
|
throw new MastraError(
|
|
1452
1547
|
{
|
|
1453
|
-
id: "
|
|
1548
|
+
id: createStorageErrorId("LANCE", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
|
|
1454
1549
|
text: "Failed to get scores by entityId and entityType in LanceStorage",
|
|
1455
1550
|
domain: ErrorDomain.STORAGE,
|
|
1456
1551
|
category: ErrorCategory.THIRD_PARTY,
|
|
@@ -1492,7 +1587,7 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1492
1587
|
} catch (error) {
|
|
1493
1588
|
throw new MastraError(
|
|
1494
1589
|
{
|
|
1495
|
-
id: "
|
|
1590
|
+
id: createStorageErrorId("LANCE", "LIST_SCORES_BY_SPAN", "FAILED"),
|
|
1496
1591
|
text: "Failed to get scores by traceId and spanId in LanceStorage",
|
|
1497
1592
|
domain: ErrorDomain.STORAGE,
|
|
1498
1593
|
category: ErrorCategory.THIRD_PARTY,
|
|
@@ -1503,6 +1598,9 @@ var StoreScoresLance = class extends ScoresStorage {
|
|
|
1503
1598
|
}
|
|
1504
1599
|
}
|
|
1505
1600
|
};
|
|
1601
|
+
function escapeSql(str) {
|
|
1602
|
+
return str.replace(/'/g, "''");
|
|
1603
|
+
}
|
|
1506
1604
|
function parseWorkflowRun(row) {
|
|
1507
1605
|
let parsedSnapshot = row.snapshot;
|
|
1508
1606
|
if (typeof parsedSnapshot === "string") {
|
|
@@ -1523,42 +1621,88 @@ function parseWorkflowRun(row) {
|
|
|
1523
1621
|
}
|
|
1524
1622
|
var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
1525
1623
|
client;
|
|
1526
|
-
|
|
1624
|
+
#db;
|
|
1625
|
+
constructor(config) {
|
|
1527
1626
|
super();
|
|
1627
|
+
const client = resolveLanceConfig(config);
|
|
1528
1628
|
this.client = client;
|
|
1629
|
+
this.#db = new LanceDB({ client });
|
|
1630
|
+
}
|
|
1631
|
+
async init() {
|
|
1632
|
+
const schema = TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT];
|
|
1633
|
+
await this.#db.createTable({ tableName: TABLE_WORKFLOW_SNAPSHOT, schema });
|
|
1634
|
+
await this.#db.alterTable({
|
|
1635
|
+
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
1636
|
+
schema,
|
|
1637
|
+
ifNotExists: ["resourceId"]
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
async dangerouslyClearAll() {
|
|
1641
|
+
await this.#db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
|
|
1529
1642
|
}
|
|
1530
|
-
updateWorkflowResults({
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1643
|
+
async updateWorkflowResults({
|
|
1644
|
+
workflowName,
|
|
1645
|
+
runId,
|
|
1646
|
+
stepId,
|
|
1647
|
+
result,
|
|
1648
|
+
requestContext
|
|
1536
1649
|
}) {
|
|
1537
|
-
|
|
1650
|
+
let snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
1651
|
+
if (!snapshot) {
|
|
1652
|
+
snapshot = {
|
|
1653
|
+
context: {},
|
|
1654
|
+
activePaths: [],
|
|
1655
|
+
timestamp: Date.now(),
|
|
1656
|
+
suspendedPaths: {},
|
|
1657
|
+
activeStepsPath: {},
|
|
1658
|
+
resumeLabels: {},
|
|
1659
|
+
serializedStepGraph: [],
|
|
1660
|
+
status: "pending",
|
|
1661
|
+
value: {},
|
|
1662
|
+
waitingPaths: {},
|
|
1663
|
+
runId,
|
|
1664
|
+
requestContext: {}
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
snapshot.context[stepId] = result;
|
|
1668
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
1669
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
1670
|
+
return snapshot.context;
|
|
1538
1671
|
}
|
|
1539
|
-
updateWorkflowState({
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1672
|
+
async updateWorkflowState({
|
|
1673
|
+
workflowName,
|
|
1674
|
+
runId,
|
|
1675
|
+
opts
|
|
1543
1676
|
}) {
|
|
1544
|
-
|
|
1677
|
+
const snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
1678
|
+
if (!snapshot) {
|
|
1679
|
+
return void 0;
|
|
1680
|
+
}
|
|
1681
|
+
if (!snapshot.context) {
|
|
1682
|
+
throw new Error(`Snapshot not found for runId ${runId}`);
|
|
1683
|
+
}
|
|
1684
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
1685
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
|
|
1686
|
+
return updatedSnapshot;
|
|
1545
1687
|
}
|
|
1546
1688
|
async persistWorkflowSnapshot({
|
|
1547
1689
|
workflowName,
|
|
1548
1690
|
runId,
|
|
1549
1691
|
resourceId,
|
|
1550
|
-
snapshot
|
|
1692
|
+
snapshot,
|
|
1693
|
+
createdAt,
|
|
1694
|
+
updatedAt
|
|
1551
1695
|
}) {
|
|
1552
1696
|
try {
|
|
1553
1697
|
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1554
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1698
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1555
1699
|
const records = await query.toArray();
|
|
1556
|
-
let
|
|
1557
|
-
const now = Date.now();
|
|
1700
|
+
let createdAtValue;
|
|
1701
|
+
const now = createdAt?.getTime() ?? Date.now();
|
|
1558
1702
|
if (records.length > 0) {
|
|
1559
|
-
|
|
1703
|
+
createdAtValue = records[0].createdAt ?? now;
|
|
1560
1704
|
} else {
|
|
1561
|
-
|
|
1705
|
+
createdAtValue = now;
|
|
1562
1706
|
}
|
|
1563
1707
|
const { status, value, ...rest } = snapshot;
|
|
1564
1708
|
const record = {
|
|
@@ -1567,14 +1711,14 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1567
1711
|
resourceId,
|
|
1568
1712
|
snapshot: JSON.stringify({ status, value, ...rest }),
|
|
1569
1713
|
// this is to ensure status is always just before value, for when querying the db by status
|
|
1570
|
-
createdAt,
|
|
1571
|
-
updatedAt: now
|
|
1714
|
+
createdAt: createdAtValue,
|
|
1715
|
+
updatedAt: updatedAt ?? now
|
|
1572
1716
|
};
|
|
1573
1717
|
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1574
1718
|
} catch (error) {
|
|
1575
1719
|
throw new MastraError(
|
|
1576
1720
|
{
|
|
1577
|
-
id: "
|
|
1721
|
+
id: createStorageErrorId("LANCE", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1578
1722
|
domain: ErrorDomain.STORAGE,
|
|
1579
1723
|
category: ErrorCategory.THIRD_PARTY,
|
|
1580
1724
|
details: { workflowName, runId }
|
|
@@ -1589,13 +1733,13 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1589
1733
|
}) {
|
|
1590
1734
|
try {
|
|
1591
1735
|
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1592
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1736
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1593
1737
|
const records = await query.toArray();
|
|
1594
1738
|
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1595
1739
|
} catch (error) {
|
|
1596
1740
|
throw new MastraError(
|
|
1597
1741
|
{
|
|
1598
|
-
id: "
|
|
1742
|
+
id: createStorageErrorId("LANCE", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1599
1743
|
domain: ErrorDomain.STORAGE,
|
|
1600
1744
|
category: ErrorCategory.THIRD_PARTY,
|
|
1601
1745
|
details: { workflowName, runId }
|
|
@@ -1607,9 +1751,9 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1607
1751
|
async getWorkflowRunById(args) {
|
|
1608
1752
|
try {
|
|
1609
1753
|
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1610
|
-
let whereClause = `run_id = '${args.runId}'`;
|
|
1754
|
+
let whereClause = `run_id = '${escapeSql(args.runId)}'`;
|
|
1611
1755
|
if (args.workflowName) {
|
|
1612
|
-
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
1756
|
+
whereClause += ` AND workflow_name = '${escapeSql(args.workflowName)}'`;
|
|
1613
1757
|
}
|
|
1614
1758
|
const query = table.query().where(whereClause);
|
|
1615
1759
|
const records = await query.toArray();
|
|
@@ -1619,7 +1763,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1619
1763
|
} catch (error) {
|
|
1620
1764
|
throw new MastraError(
|
|
1621
1765
|
{
|
|
1622
|
-
id: "
|
|
1766
|
+
id: createStorageErrorId("LANCE", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1623
1767
|
domain: ErrorDomain.STORAGE,
|
|
1624
1768
|
category: ErrorCategory.THIRD_PARTY,
|
|
1625
1769
|
details: { runId: args.runId, workflowName: args.workflowName ?? "" }
|
|
@@ -1628,20 +1772,37 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1628
1772
|
);
|
|
1629
1773
|
}
|
|
1630
1774
|
}
|
|
1775
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
1776
|
+
try {
|
|
1777
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1778
|
+
const whereClause = `run_id = '${escapeSql(runId)}' AND workflow_name = '${escapeSql(workflowName)}'`;
|
|
1779
|
+
await table.delete(whereClause);
|
|
1780
|
+
} catch (error) {
|
|
1781
|
+
throw new MastraError(
|
|
1782
|
+
{
|
|
1783
|
+
id: createStorageErrorId("LANCE", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1784
|
+
domain: ErrorDomain.STORAGE,
|
|
1785
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1786
|
+
details: { runId, workflowName }
|
|
1787
|
+
},
|
|
1788
|
+
error
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1631
1792
|
async listWorkflowRuns(args) {
|
|
1632
1793
|
try {
|
|
1633
1794
|
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1634
1795
|
let query = table.query();
|
|
1635
1796
|
const conditions = [];
|
|
1636
1797
|
if (args?.workflowName) {
|
|
1637
|
-
conditions.push(`workflow_name = '${args.workflowName
|
|
1798
|
+
conditions.push(`workflow_name = '${escapeSql(args.workflowName)}'`);
|
|
1638
1799
|
}
|
|
1639
1800
|
if (args?.status) {
|
|
1640
1801
|
const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
1641
1802
|
conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
|
|
1642
1803
|
}
|
|
1643
1804
|
if (args?.resourceId) {
|
|
1644
|
-
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1805
|
+
conditions.push(`\`resourceId\` = '${escapeSql(args.resourceId)}'`);
|
|
1645
1806
|
}
|
|
1646
1807
|
if (args?.fromDate instanceof Date) {
|
|
1647
1808
|
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
@@ -1661,7 +1822,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1661
1822
|
if (args.page < 0 || !Number.isInteger(args.page)) {
|
|
1662
1823
|
throw new MastraError(
|
|
1663
1824
|
{
|
|
1664
|
-
id: "
|
|
1825
|
+
id: createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "INVALID_PAGINATION"),
|
|
1665
1826
|
domain: ErrorDomain.STORAGE,
|
|
1666
1827
|
category: ErrorCategory.USER,
|
|
1667
1828
|
details: { page: args.page, perPage: args.perPage }
|
|
@@ -1681,7 +1842,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
|
1681
1842
|
} catch (error) {
|
|
1682
1843
|
throw new MastraError(
|
|
1683
1844
|
{
|
|
1684
|
-
id: "
|
|
1845
|
+
id: createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
1685
1846
|
domain: ErrorDomain.STORAGE,
|
|
1686
1847
|
category: ErrorCategory.THIRD_PARTY,
|
|
1687
1848
|
details: { resourceId: args?.resourceId ?? "", workflowName: args?.workflowName ?? "" }
|
|
@@ -1701,7 +1862,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1701
1862
|
* @param id The unique identifier for this storage instance
|
|
1702
1863
|
* @param name The name for this storage instance
|
|
1703
1864
|
* @param uri The URI to connect to LanceDB
|
|
1704
|
-
* @param
|
|
1865
|
+
* @param connectionOptions connection options for LanceDB
|
|
1866
|
+
* @param storageOptions storage options including disableInit
|
|
1705
1867
|
*
|
|
1706
1868
|
* Usage:
|
|
1707
1869
|
*
|
|
@@ -1719,27 +1881,30 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1719
1881
|
* ```ts
|
|
1720
1882
|
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', 's3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
1721
1883
|
* ```
|
|
1884
|
+
*
|
|
1885
|
+
* Disable auto-init for runtime (after CI/CD has run migrations)
|
|
1886
|
+
* ```ts
|
|
1887
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db', undefined, { disableInit: true });
|
|
1888
|
+
* ```
|
|
1722
1889
|
*/
|
|
1723
|
-
static async create(id, name, uri,
|
|
1724
|
-
const instance = new _LanceStorage(id, name);
|
|
1890
|
+
static async create(id, name, uri, connectionOptions, storageOptions) {
|
|
1891
|
+
const instance = new _LanceStorage(id, name, storageOptions?.disableInit);
|
|
1725
1892
|
try {
|
|
1726
|
-
instance.lanceClient = await connect(uri,
|
|
1727
|
-
const operations = new StoreOperationsLance({ client: instance.lanceClient });
|
|
1893
|
+
instance.lanceClient = await connect(uri, connectionOptions);
|
|
1728
1894
|
instance.stores = {
|
|
1729
|
-
operations: new StoreOperationsLance({ client: instance.lanceClient }),
|
|
1730
1895
|
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1731
1896
|
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1732
|
-
memory: new StoreMemoryLance({ client: instance.lanceClient
|
|
1897
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient })
|
|
1733
1898
|
};
|
|
1734
1899
|
return instance;
|
|
1735
1900
|
} catch (e) {
|
|
1736
1901
|
throw new MastraError(
|
|
1737
1902
|
{
|
|
1738
|
-
id: "
|
|
1903
|
+
id: createStorageErrorId("LANCE", "CONNECT", "FAILED"),
|
|
1739
1904
|
domain: ErrorDomain.STORAGE,
|
|
1740
1905
|
category: ErrorCategory.THIRD_PARTY,
|
|
1741
1906
|
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1742
|
-
details: { uri, optionsProvided: !!
|
|
1907
|
+
details: { uri, optionsProvided: !!connectionOptions }
|
|
1743
1908
|
},
|
|
1744
1909
|
e
|
|
1745
1910
|
);
|
|
@@ -1747,45 +1912,12 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1747
1912
|
}
|
|
1748
1913
|
/**
|
|
1749
1914
|
* @internal
|
|
1750
|
-
* Private constructor to enforce using the create factory method
|
|
1915
|
+
* Private constructor to enforce using the create factory method.
|
|
1916
|
+
* Note: stores is initialized in create() after the lanceClient is connected.
|
|
1751
1917
|
*/
|
|
1752
|
-
constructor(id, name) {
|
|
1753
|
-
super({ id, name });
|
|
1754
|
-
|
|
1755
|
-
this.stores = {
|
|
1756
|
-
operations: new StoreOperationsLance({ client: this.lanceClient }),
|
|
1757
|
-
workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
|
|
1758
|
-
scores: new StoreScoresLance({ client: this.lanceClient }),
|
|
1759
|
-
memory: new StoreMemoryLance({ client: this.lanceClient, operations })
|
|
1760
|
-
};
|
|
1761
|
-
}
|
|
1762
|
-
async createTable({
|
|
1763
|
-
tableName,
|
|
1764
|
-
schema
|
|
1765
|
-
}) {
|
|
1766
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
1767
|
-
}
|
|
1768
|
-
async dropTable({ tableName }) {
|
|
1769
|
-
return this.stores.operations.dropTable({ tableName });
|
|
1770
|
-
}
|
|
1771
|
-
async alterTable({
|
|
1772
|
-
tableName,
|
|
1773
|
-
schema,
|
|
1774
|
-
ifNotExists
|
|
1775
|
-
}) {
|
|
1776
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
1777
|
-
}
|
|
1778
|
-
async clearTable({ tableName }) {
|
|
1779
|
-
return this.stores.operations.clearTable({ tableName });
|
|
1780
|
-
}
|
|
1781
|
-
async insert({ tableName, record }) {
|
|
1782
|
-
return this.stores.operations.insert({ tableName, record });
|
|
1783
|
-
}
|
|
1784
|
-
async batchInsert({ tableName, records }) {
|
|
1785
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
1786
|
-
}
|
|
1787
|
-
async load({ tableName, keys }) {
|
|
1788
|
-
return this.stores.operations.load({ tableName, keys });
|
|
1918
|
+
constructor(id, name, disableInit) {
|
|
1919
|
+
super({ id, name, disableInit });
|
|
1920
|
+
this.stores = {};
|
|
1789
1921
|
}
|
|
1790
1922
|
async getThreadById({ threadId }) {
|
|
1791
1923
|
return this.stores.memory.getThreadById({ threadId });
|
|
@@ -1808,13 +1940,16 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1808
1940
|
async deleteThread({ threadId }) {
|
|
1809
1941
|
return this.stores.memory.deleteThread({ threadId });
|
|
1810
1942
|
}
|
|
1943
|
+
async deleteMessages(messageIds) {
|
|
1944
|
+
return this.stores.memory.deleteMessages(messageIds);
|
|
1945
|
+
}
|
|
1811
1946
|
get supports() {
|
|
1812
1947
|
return {
|
|
1813
1948
|
selectByIncludeResourceScope: true,
|
|
1814
1949
|
resourceWorkingMemory: true,
|
|
1815
1950
|
hasColumn: true,
|
|
1816
1951
|
createTable: true,
|
|
1817
|
-
deleteMessages:
|
|
1952
|
+
deleteMessages: true,
|
|
1818
1953
|
listScoresBySpan: true
|
|
1819
1954
|
};
|
|
1820
1955
|
}
|
|
@@ -1894,6 +2029,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1894
2029
|
async getWorkflowRunById(args) {
|
|
1895
2030
|
return this.stores.workflows.getWorkflowRunById(args);
|
|
1896
2031
|
}
|
|
2032
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
2033
|
+
return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
|
|
2034
|
+
}
|
|
1897
2035
|
async updateWorkflowResults({
|
|
1898
2036
|
workflowName,
|
|
1899
2037
|
runId,
|
|
@@ -1936,8 +2074,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1936
2074
|
}) {
|
|
1937
2075
|
return this.stores.scores.listScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
|
|
1938
2076
|
}
|
|
1939
|
-
async saveScore(
|
|
1940
|
-
return this.stores.scores.saveScore(
|
|
2077
|
+
async saveScore(score) {
|
|
2078
|
+
return this.stores.scores.saveScore(score);
|
|
1941
2079
|
}
|
|
1942
2080
|
async listScoresByRunId({
|
|
1943
2081
|
runId,
|
|
@@ -2313,7 +2451,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2313
2451
|
} catch (e) {
|
|
2314
2452
|
throw new MastraError(
|
|
2315
2453
|
{
|
|
2316
|
-
id: "
|
|
2454
|
+
id: createVectorErrorId("LANCE", "CONNECT", "FAILED"),
|
|
2317
2455
|
domain: ErrorDomain.STORAGE,
|
|
2318
2456
|
category: ErrorCategory.THIRD_PARTY,
|
|
2319
2457
|
details: { uri }
|
|
@@ -2356,7 +2494,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2356
2494
|
} catch (error) {
|
|
2357
2495
|
throw new MastraError(
|
|
2358
2496
|
{
|
|
2359
|
-
id: "
|
|
2497
|
+
id: createVectorErrorId("LANCE", "QUERY", "INVALID_ARGS"),
|
|
2360
2498
|
domain: ErrorDomain.STORAGE,
|
|
2361
2499
|
category: ErrorCategory.USER,
|
|
2362
2500
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2404,7 +2542,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2404
2542
|
} catch (error) {
|
|
2405
2543
|
throw new MastraError(
|
|
2406
2544
|
{
|
|
2407
|
-
id: "
|
|
2545
|
+
id: createVectorErrorId("LANCE", "QUERY", "FAILED"),
|
|
2408
2546
|
domain: ErrorDomain.STORAGE,
|
|
2409
2547
|
category: ErrorCategory.THIRD_PARTY,
|
|
2410
2548
|
details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
|
|
@@ -2456,7 +2594,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2456
2594
|
} catch (error) {
|
|
2457
2595
|
throw new MastraError(
|
|
2458
2596
|
{
|
|
2459
|
-
id: "
|
|
2597
|
+
id: createVectorErrorId("LANCE", "UPSERT", "INVALID_ARGS"),
|
|
2460
2598
|
domain: ErrorDomain.STORAGE,
|
|
2461
2599
|
category: ErrorCategory.USER,
|
|
2462
2600
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2492,7 +2630,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2492
2630
|
} catch (error) {
|
|
2493
2631
|
throw new MastraError(
|
|
2494
2632
|
{
|
|
2495
|
-
id: "
|
|
2633
|
+
id: createVectorErrorId("LANCE", "UPSERT", "FAILED"),
|
|
2496
2634
|
domain: ErrorDomain.STORAGE,
|
|
2497
2635
|
category: ErrorCategory.THIRD_PARTY,
|
|
2498
2636
|
details: { tableName, vectorCount: vectors.length, metadataCount: metadata.length, idsCount: ids.length }
|
|
@@ -2519,7 +2657,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2519
2657
|
async createTable(tableName, data, options) {
|
|
2520
2658
|
if (!this.lanceClient) {
|
|
2521
2659
|
throw new MastraError({
|
|
2522
|
-
id: "
|
|
2660
|
+
id: createVectorErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
|
|
2523
2661
|
domain: ErrorDomain.STORAGE,
|
|
2524
2662
|
category: ErrorCategory.USER,
|
|
2525
2663
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2534,7 +2672,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2534
2672
|
} catch (error) {
|
|
2535
2673
|
throw new MastraError(
|
|
2536
2674
|
{
|
|
2537
|
-
id: "
|
|
2675
|
+
id: createVectorErrorId("LANCE", "CREATE_TABLE", "FAILED"),
|
|
2538
2676
|
domain: ErrorDomain.STORAGE,
|
|
2539
2677
|
category: ErrorCategory.THIRD_PARTY,
|
|
2540
2678
|
details: { tableName }
|
|
@@ -2546,7 +2684,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2546
2684
|
async listTables() {
|
|
2547
2685
|
if (!this.lanceClient) {
|
|
2548
2686
|
throw new MastraError({
|
|
2549
|
-
id: "
|
|
2687
|
+
id: createVectorErrorId("LANCE", "LIST_TABLES", "INVALID_ARGS"),
|
|
2550
2688
|
domain: ErrorDomain.STORAGE,
|
|
2551
2689
|
category: ErrorCategory.USER,
|
|
2552
2690
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2558,7 +2696,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2558
2696
|
} catch (error) {
|
|
2559
2697
|
throw new MastraError(
|
|
2560
2698
|
{
|
|
2561
|
-
id: "
|
|
2699
|
+
id: createVectorErrorId("LANCE", "LIST_TABLES", "FAILED"),
|
|
2562
2700
|
domain: ErrorDomain.STORAGE,
|
|
2563
2701
|
category: ErrorCategory.THIRD_PARTY
|
|
2564
2702
|
},
|
|
@@ -2569,7 +2707,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2569
2707
|
async getTableSchema(tableName) {
|
|
2570
2708
|
if (!this.lanceClient) {
|
|
2571
2709
|
throw new MastraError({
|
|
2572
|
-
id: "
|
|
2710
|
+
id: createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
|
|
2573
2711
|
domain: ErrorDomain.STORAGE,
|
|
2574
2712
|
category: ErrorCategory.USER,
|
|
2575
2713
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2582,7 +2720,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2582
2720
|
} catch (error) {
|
|
2583
2721
|
throw new MastraError(
|
|
2584
2722
|
{
|
|
2585
|
-
id: "
|
|
2723
|
+
id: createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
|
|
2586
2724
|
domain: ErrorDomain.STORAGE,
|
|
2587
2725
|
category: ErrorCategory.THIRD_PARTY,
|
|
2588
2726
|
details: { tableName }
|
|
@@ -2617,7 +2755,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2617
2755
|
} catch (err) {
|
|
2618
2756
|
throw new MastraError(
|
|
2619
2757
|
{
|
|
2620
|
-
id: "
|
|
2758
|
+
id: createVectorErrorId("LANCE", "CREATE_INDEX", "INVALID_ARGS"),
|
|
2621
2759
|
domain: ErrorDomain.STORAGE,
|
|
2622
2760
|
category: ErrorCategory.USER,
|
|
2623
2761
|
details: { tableName: tableName || "", indexName, dimension, metric }
|
|
@@ -2662,7 +2800,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2662
2800
|
} catch (error) {
|
|
2663
2801
|
throw new MastraError(
|
|
2664
2802
|
{
|
|
2665
|
-
id: "
|
|
2803
|
+
id: createVectorErrorId("LANCE", "CREATE_INDEX", "FAILED"),
|
|
2666
2804
|
domain: ErrorDomain.STORAGE,
|
|
2667
2805
|
category: ErrorCategory.THIRD_PARTY,
|
|
2668
2806
|
details: { tableName: tableName || "", indexName, dimension }
|
|
@@ -2674,7 +2812,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2674
2812
|
async listIndexes() {
|
|
2675
2813
|
if (!this.lanceClient) {
|
|
2676
2814
|
throw new MastraError({
|
|
2677
|
-
id: "
|
|
2815
|
+
id: createVectorErrorId("LANCE", "LIST_INDEXES", "INVALID_ARGS"),
|
|
2678
2816
|
domain: ErrorDomain.STORAGE,
|
|
2679
2817
|
category: ErrorCategory.USER,
|
|
2680
2818
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2693,7 +2831,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2693
2831
|
} catch (error) {
|
|
2694
2832
|
throw new MastraError(
|
|
2695
2833
|
{
|
|
2696
|
-
id: "
|
|
2834
|
+
id: createVectorErrorId("LANCE", "LIST_INDEXES", "FAILED"),
|
|
2697
2835
|
domain: ErrorDomain.STORAGE,
|
|
2698
2836
|
category: ErrorCategory.THIRD_PARTY
|
|
2699
2837
|
},
|
|
@@ -2712,7 +2850,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2712
2850
|
} catch (err) {
|
|
2713
2851
|
throw new MastraError(
|
|
2714
2852
|
{
|
|
2715
|
-
id: "
|
|
2853
|
+
id: createVectorErrorId("LANCE", "DESCRIBE_INDEX", "INVALID_ARGS"),
|
|
2716
2854
|
domain: ErrorDomain.STORAGE,
|
|
2717
2855
|
category: ErrorCategory.USER,
|
|
2718
2856
|
details: { indexName }
|
|
@@ -2747,7 +2885,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2747
2885
|
} catch (error) {
|
|
2748
2886
|
throw new MastraError(
|
|
2749
2887
|
{
|
|
2750
|
-
id: "
|
|
2888
|
+
id: createVectorErrorId("LANCE", "DESCRIBE_INDEX", "FAILED"),
|
|
2751
2889
|
domain: ErrorDomain.STORAGE,
|
|
2752
2890
|
category: ErrorCategory.THIRD_PARTY,
|
|
2753
2891
|
details: { indexName }
|
|
@@ -2767,7 +2905,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2767
2905
|
} catch (err) {
|
|
2768
2906
|
throw new MastraError(
|
|
2769
2907
|
{
|
|
2770
|
-
id: "
|
|
2908
|
+
id: createVectorErrorId("LANCE", "DELETE_INDEX", "INVALID_ARGS"),
|
|
2771
2909
|
domain: ErrorDomain.STORAGE,
|
|
2772
2910
|
category: ErrorCategory.USER,
|
|
2773
2911
|
details: { indexName }
|
|
@@ -2790,7 +2928,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2790
2928
|
} catch (error) {
|
|
2791
2929
|
throw new MastraError(
|
|
2792
2930
|
{
|
|
2793
|
-
id: "
|
|
2931
|
+
id: createVectorErrorId("LANCE", "DELETE_INDEX", "FAILED"),
|
|
2794
2932
|
domain: ErrorDomain.STORAGE,
|
|
2795
2933
|
category: ErrorCategory.THIRD_PARTY,
|
|
2796
2934
|
details: { indexName }
|
|
@@ -2805,7 +2943,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2805
2943
|
async deleteAllTables() {
|
|
2806
2944
|
if (!this.lanceClient) {
|
|
2807
2945
|
throw new MastraError({
|
|
2808
|
-
id: "
|
|
2946
|
+
id: createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "INVALID_ARGS"),
|
|
2809
2947
|
domain: ErrorDomain.STORAGE,
|
|
2810
2948
|
category: ErrorCategory.USER,
|
|
2811
2949
|
details: { methodName: "deleteAllTables" },
|
|
@@ -2817,7 +2955,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2817
2955
|
} catch (error) {
|
|
2818
2956
|
throw new MastraError(
|
|
2819
2957
|
{
|
|
2820
|
-
id: "
|
|
2958
|
+
id: createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "FAILED"),
|
|
2821
2959
|
domain: ErrorDomain.STORAGE,
|
|
2822
2960
|
category: ErrorCategory.THIRD_PARTY,
|
|
2823
2961
|
details: { methodName: "deleteAllTables" }
|
|
@@ -2829,7 +2967,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2829
2967
|
async deleteTable(tableName) {
|
|
2830
2968
|
if (!this.lanceClient) {
|
|
2831
2969
|
throw new MastraError({
|
|
2832
|
-
id: "
|
|
2970
|
+
id: createVectorErrorId("LANCE", "DELETE_TABLE", "INVALID_ARGS"),
|
|
2833
2971
|
domain: ErrorDomain.STORAGE,
|
|
2834
2972
|
category: ErrorCategory.USER,
|
|
2835
2973
|
details: { tableName },
|
|
@@ -2841,7 +2979,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2841
2979
|
} catch (error) {
|
|
2842
2980
|
throw new MastraError(
|
|
2843
2981
|
{
|
|
2844
|
-
id: "
|
|
2982
|
+
id: createVectorErrorId("LANCE", "DELETE_TABLE", "FAILED"),
|
|
2845
2983
|
domain: ErrorDomain.STORAGE,
|
|
2846
2984
|
category: ErrorCategory.THIRD_PARTY,
|
|
2847
2985
|
details: { tableName }
|
|
@@ -2854,7 +2992,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2854
2992
|
const { indexName, update } = params;
|
|
2855
2993
|
if ("id" in params && "filter" in params && params.id && params.filter) {
|
|
2856
2994
|
throw new MastraError({
|
|
2857
|
-
id: "
|
|
2995
|
+
id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "MUTUALLY_EXCLUSIVE"),
|
|
2858
2996
|
domain: ErrorDomain.STORAGE,
|
|
2859
2997
|
category: ErrorCategory.USER,
|
|
2860
2998
|
text: "id and filter are mutually exclusive",
|
|
@@ -2863,7 +3001,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2863
3001
|
}
|
|
2864
3002
|
if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
|
|
2865
3003
|
throw new MastraError({
|
|
2866
|
-
id: "
|
|
3004
|
+
id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_TARGET"),
|
|
2867
3005
|
domain: ErrorDomain.STORAGE,
|
|
2868
3006
|
category: ErrorCategory.USER,
|
|
2869
3007
|
text: "Either id or filter must be provided",
|
|
@@ -2872,7 +3010,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2872
3010
|
}
|
|
2873
3011
|
if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
|
|
2874
3012
|
throw new MastraError({
|
|
2875
|
-
id: "
|
|
3013
|
+
id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "EMPTY_FILTER"),
|
|
2876
3014
|
domain: ErrorDomain.STORAGE,
|
|
2877
3015
|
category: ErrorCategory.USER,
|
|
2878
3016
|
text: "Cannot update with empty filter",
|
|
@@ -2881,7 +3019,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2881
3019
|
}
|
|
2882
3020
|
if (!update.vector && !update.metadata) {
|
|
2883
3021
|
throw new MastraError({
|
|
2884
|
-
id: "
|
|
3022
|
+
id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_PAYLOAD"),
|
|
2885
3023
|
domain: ErrorDomain.STORAGE,
|
|
2886
3024
|
category: ErrorCategory.USER,
|
|
2887
3025
|
text: "No updates provided",
|
|
@@ -2976,7 +3114,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2976
3114
|
if (error instanceof MastraError) throw error;
|
|
2977
3115
|
throw new MastraError(
|
|
2978
3116
|
{
|
|
2979
|
-
id: "
|
|
3117
|
+
id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "FAILED"),
|
|
2980
3118
|
domain: ErrorDomain.STORAGE,
|
|
2981
3119
|
category: ErrorCategory.THIRD_PARTY,
|
|
2982
3120
|
details: {
|
|
@@ -3005,7 +3143,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
3005
3143
|
} catch (err) {
|
|
3006
3144
|
throw new MastraError(
|
|
3007
3145
|
{
|
|
3008
|
-
id: "
|
|
3146
|
+
id: createVectorErrorId("LANCE", "DELETE_VECTOR", "INVALID_ARGS"),
|
|
3009
3147
|
domain: ErrorDomain.STORAGE,
|
|
3010
3148
|
category: ErrorCategory.USER,
|
|
3011
3149
|
details: {
|
|
@@ -3038,7 +3176,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
3038
3176
|
} catch (error) {
|
|
3039
3177
|
throw new MastraError(
|
|
3040
3178
|
{
|
|
3041
|
-
id: "
|
|
3179
|
+
id: createVectorErrorId("LANCE", "DELETE_VECTOR", "FAILED"),
|
|
3042
3180
|
domain: ErrorDomain.STORAGE,
|
|
3043
3181
|
category: ErrorCategory.THIRD_PARTY,
|
|
3044
3182
|
details: {
|
|
@@ -3078,7 +3216,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
3078
3216
|
async deleteVectors({ indexName, filter, ids }) {
|
|
3079
3217
|
if (ids && filter) {
|
|
3080
3218
|
throw new MastraError({
|
|
3081
|
-
id: "
|
|
3219
|
+
id: createVectorErrorId("LANCE", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
|
|
3082
3220
|
domain: ErrorDomain.STORAGE,
|
|
3083
3221
|
category: ErrorCategory.USER,
|
|
3084
3222
|
text: "ids and filter are mutually exclusive",
|
|
@@ -3087,7 +3225,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
3087
3225
|
}
|
|
3088
3226
|
if (!ids && !filter) {
|
|
3089
3227
|
throw new MastraError({
|
|
3090
|
-
id: "
|
|
3228
|
+
id: createVectorErrorId("LANCE", "DELETE_VECTORS", "NO_TARGET"),
|
|
3091
3229
|
domain: ErrorDomain.STORAGE,
|
|
3092
3230
|
category: ErrorCategory.USER,
|
|
3093
3231
|
text: "Either filter or ids must be provided",
|
|
@@ -3096,7 +3234,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
3096
3234
|
}
|
|
3097
3235
|
if (ids && ids.length === 0) {
|
|
3098
3236
|
throw new MastraError({
|
|
3099
|
-
id: "
|
|
3237
|
+
id: createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_IDS"),
|
|
3100
3238
|
domain: ErrorDomain.STORAGE,
|
|
3101
3239
|
category: ErrorCategory.USER,
|
|
3102
3240
|
text: "Cannot delete with empty ids array",
|
|
@@ -3105,7 +3243,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
3105
3243
|
}
|
|
3106
3244
|
if (filter && Object.keys(filter).length === 0) {
|
|
3107
3245
|
throw new MastraError({
|
|
3108
|
-
id: "
|
|
3246
|
+
id: createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_FILTER"),
|
|
3109
3247
|
domain: ErrorDomain.STORAGE,
|
|
3110
3248
|
category: ErrorCategory.USER,
|
|
3111
3249
|
text: "Cannot delete with empty filter",
|
|
@@ -3165,7 +3303,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
3165
3303
|
if (error instanceof MastraError) throw error;
|
|
3166
3304
|
throw new MastraError(
|
|
3167
3305
|
{
|
|
3168
|
-
id: "
|
|
3306
|
+
id: createVectorErrorId("LANCE", "DELETE_VECTORS", "FAILED"),
|
|
3169
3307
|
domain: ErrorDomain.STORAGE,
|
|
3170
3308
|
category: ErrorCategory.THIRD_PARTY,
|
|
3171
3309
|
details: {
|