@mastra/lance 1.0.0-beta.7 → 1.0.0-beta.9
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 +234 -0
- package/dist/index.cjs +1039 -1087
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1038 -1089
- 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 +11 -22
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +10 -6
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +66 -174
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
- package/dist/storage/domains/utils.d.ts.map +0 -1
- /package/dist/storage/{domains → db}/utils.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var lancedb = require('@lancedb/lancedb');
|
|
|
4
4
|
var error = require('@mastra/core/error');
|
|
5
5
|
var storage = require('@mastra/core/storage');
|
|
6
6
|
var agent = require('@mastra/core/agent');
|
|
7
|
+
var base = require('@mastra/core/base');
|
|
7
8
|
var apacheArrow = require('apache-arrow');
|
|
8
9
|
var evals = require('@mastra/core/evals');
|
|
9
10
|
var vector = require('@mastra/core/vector');
|
|
@@ -124,622 +125,503 @@ async function getTableSchema({
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
// src/storage/
|
|
128
|
-
|
|
128
|
+
// src/storage/db/index.ts
|
|
129
|
+
function resolveLanceConfig(config) {
|
|
130
|
+
return config.client;
|
|
131
|
+
}
|
|
132
|
+
var LanceDB = class extends base.MastraBase {
|
|
129
133
|
client;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
super();
|
|
134
|
+
constructor({ client }) {
|
|
135
|
+
super({ name: "lance-db" });
|
|
133
136
|
this.client = client;
|
|
134
|
-
this.operations = operations;
|
|
135
137
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
getDefaultValue(type) {
|
|
139
|
+
switch (type) {
|
|
140
|
+
case "text":
|
|
141
|
+
return "''";
|
|
142
|
+
case "timestamp":
|
|
143
|
+
return "CURRENT_TIMESTAMP";
|
|
144
|
+
case "integer":
|
|
145
|
+
case "bigint":
|
|
146
|
+
return "0";
|
|
147
|
+
case "jsonb":
|
|
148
|
+
return "'{}'";
|
|
149
|
+
case "uuid":
|
|
150
|
+
return "''";
|
|
151
|
+
default:
|
|
152
|
+
return storage.getDefaultValue(type);
|
|
153
|
+
}
|
|
139
154
|
}
|
|
140
|
-
async
|
|
155
|
+
async hasColumn(tableName, columnName) {
|
|
156
|
+
const table = await this.client.openTable(tableName);
|
|
157
|
+
const schema = await table.schema();
|
|
158
|
+
return schema.fields.some((field) => field.name === columnName);
|
|
159
|
+
}
|
|
160
|
+
translateSchema(schema) {
|
|
161
|
+
const fields = Object.entries(schema).map(([name, column]) => {
|
|
162
|
+
let arrowType;
|
|
163
|
+
switch (column.type.toLowerCase()) {
|
|
164
|
+
case "text":
|
|
165
|
+
case "uuid":
|
|
166
|
+
arrowType = new apacheArrow.Utf8();
|
|
167
|
+
break;
|
|
168
|
+
case "int":
|
|
169
|
+
case "integer":
|
|
170
|
+
arrowType = new apacheArrow.Int32();
|
|
171
|
+
break;
|
|
172
|
+
case "bigint":
|
|
173
|
+
arrowType = new apacheArrow.Float64();
|
|
174
|
+
break;
|
|
175
|
+
case "float":
|
|
176
|
+
arrowType = new apacheArrow.Float32();
|
|
177
|
+
break;
|
|
178
|
+
case "jsonb":
|
|
179
|
+
case "json":
|
|
180
|
+
arrowType = new apacheArrow.Utf8();
|
|
181
|
+
break;
|
|
182
|
+
case "binary":
|
|
183
|
+
arrowType = new apacheArrow.Binary();
|
|
184
|
+
break;
|
|
185
|
+
case "timestamp":
|
|
186
|
+
arrowType = new apacheArrow.Float64();
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
arrowType = new apacheArrow.Utf8();
|
|
190
|
+
}
|
|
191
|
+
return new apacheArrow.Field(name, arrowType, column.nullable ?? true);
|
|
192
|
+
});
|
|
193
|
+
return new apacheArrow.Schema(fields);
|
|
194
|
+
}
|
|
195
|
+
async createTable({
|
|
196
|
+
tableName,
|
|
197
|
+
schema
|
|
198
|
+
}) {
|
|
141
199
|
try {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
200
|
+
if (!this.client) {
|
|
201
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
202
|
+
}
|
|
203
|
+
if (!tableName) {
|
|
204
|
+
throw new Error("tableName is required for createTable.");
|
|
205
|
+
}
|
|
206
|
+
if (!schema) {
|
|
207
|
+
throw new Error("schema is required for createTable.");
|
|
145
208
|
}
|
|
146
|
-
return {
|
|
147
|
-
...thread,
|
|
148
|
-
createdAt: new Date(thread.createdAt),
|
|
149
|
-
updatedAt: new Date(thread.updatedAt)
|
|
150
|
-
};
|
|
151
209
|
} catch (error$1) {
|
|
152
210
|
throw new error.MastraError(
|
|
153
211
|
{
|
|
154
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
212
|
+
id: storage.createStorageErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
|
|
155
213
|
domain: error.ErrorDomain.STORAGE,
|
|
156
|
-
category: error.ErrorCategory.
|
|
214
|
+
category: error.ErrorCategory.USER,
|
|
215
|
+
details: { tableName }
|
|
157
216
|
},
|
|
158
217
|
error$1
|
|
159
218
|
);
|
|
160
219
|
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
164
|
-
* @param thread - The thread to save
|
|
165
|
-
* @returns The saved thread
|
|
166
|
-
*/
|
|
167
|
-
async saveThread({ thread }) {
|
|
168
220
|
try {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
await table.add([record], { mode: "append" });
|
|
172
|
-
return thread;
|
|
221
|
+
const arrowSchema = this.translateSchema(schema);
|
|
222
|
+
await this.client.createEmptyTable(tableName, arrowSchema);
|
|
173
223
|
} catch (error$1) {
|
|
224
|
+
if (error$1.message?.includes("already exists")) {
|
|
225
|
+
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
174
228
|
throw new error.MastraError(
|
|
175
229
|
{
|
|
176
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
230
|
+
id: storage.createStorageErrorId("LANCE", "CREATE_TABLE", "FAILED"),
|
|
177
231
|
domain: error.ErrorDomain.STORAGE,
|
|
178
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
232
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
233
|
+
details: { tableName }
|
|
179
234
|
},
|
|
180
235
|
error$1
|
|
181
236
|
);
|
|
182
237
|
}
|
|
183
238
|
}
|
|
184
|
-
async
|
|
185
|
-
id,
|
|
186
|
-
title,
|
|
187
|
-
metadata
|
|
188
|
-
}) {
|
|
189
|
-
const maxRetries = 5;
|
|
190
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
191
|
-
try {
|
|
192
|
-
const current = await this.getThreadById({ threadId: id });
|
|
193
|
-
if (!current) {
|
|
194
|
-
throw new Error(`Thread with id ${id} not found`);
|
|
195
|
-
}
|
|
196
|
-
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
197
|
-
const record = {
|
|
198
|
-
id,
|
|
199
|
-
title,
|
|
200
|
-
metadata: JSON.stringify(mergedMetadata),
|
|
201
|
-
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
202
|
-
};
|
|
203
|
-
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
204
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
205
|
-
const updatedThread = await this.getThreadById({ threadId: id });
|
|
206
|
-
if (!updatedThread) {
|
|
207
|
-
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
208
|
-
}
|
|
209
|
-
return updatedThread;
|
|
210
|
-
} catch (error$1) {
|
|
211
|
-
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
212
|
-
const delay = Math.pow(2, attempt) * 10;
|
|
213
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
throw new error.MastraError(
|
|
217
|
-
{
|
|
218
|
-
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
219
|
-
domain: error.ErrorDomain.STORAGE,
|
|
220
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
221
|
-
},
|
|
222
|
-
error$1
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
throw new error.MastraError(
|
|
227
|
-
{
|
|
228
|
-
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
229
|
-
domain: error.ErrorDomain.STORAGE,
|
|
230
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
231
|
-
},
|
|
232
|
-
new Error("All retries exhausted")
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
async deleteThread({ threadId }) {
|
|
239
|
+
async dropTable({ tableName }) {
|
|
236
240
|
try {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
241
|
+
if (!this.client) {
|
|
242
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
243
|
+
}
|
|
244
|
+
if (!tableName) {
|
|
245
|
+
throw new Error("tableName is required for dropTable.");
|
|
246
|
+
}
|
|
247
|
+
} catch (validationError) {
|
|
242
248
|
throw new error.MastraError(
|
|
243
249
|
{
|
|
244
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
250
|
+
id: storage.createStorageErrorId("LANCE", "DROP_TABLE", "INVALID_ARGS"),
|
|
245
251
|
domain: error.ErrorDomain.STORAGE,
|
|
246
|
-
category: error.ErrorCategory.
|
|
252
|
+
category: error.ErrorCategory.USER,
|
|
253
|
+
text: validationError.message,
|
|
254
|
+
details: { tableName }
|
|
247
255
|
},
|
|
248
|
-
|
|
256
|
+
validationError
|
|
249
257
|
);
|
|
250
258
|
}
|
|
251
|
-
}
|
|
252
|
-
normalizeMessage(message) {
|
|
253
|
-
const { thread_id, ...rest } = message;
|
|
254
|
-
return {
|
|
255
|
-
...rest,
|
|
256
|
-
threadId: thread_id,
|
|
257
|
-
content: typeof message.content === "string" ? (() => {
|
|
258
|
-
try {
|
|
259
|
-
return JSON.parse(message.content);
|
|
260
|
-
} catch {
|
|
261
|
-
return message.content;
|
|
262
|
-
}
|
|
263
|
-
})() : message.content
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
async listMessagesById({ messageIds }) {
|
|
267
|
-
if (messageIds.length === 0) return { messages: [] };
|
|
268
259
|
try {
|
|
269
|
-
|
|
270
|
-
const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
|
|
271
|
-
const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
|
|
272
|
-
const messages = processResultWithTypeConversion(
|
|
273
|
-
allRecords,
|
|
274
|
-
await getTableSchema({ tableName: storage.TABLE_MESSAGES, client: this.client })
|
|
275
|
-
);
|
|
276
|
-
const list = new agent.MessageList().add(
|
|
277
|
-
messages.map(this.normalizeMessage),
|
|
278
|
-
"memory"
|
|
279
|
-
);
|
|
280
|
-
return { messages: list.get.all.db() };
|
|
260
|
+
await this.client.dropTable(tableName);
|
|
281
261
|
} catch (error$1) {
|
|
262
|
+
if (error$1.toString().includes("was not found") || error$1.message?.includes("Table not found")) {
|
|
263
|
+
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
282
266
|
throw new error.MastraError(
|
|
283
267
|
{
|
|
284
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
268
|
+
id: storage.createStorageErrorId("LANCE", "DROP_TABLE", "FAILED"),
|
|
285
269
|
domain: error.ErrorDomain.STORAGE,
|
|
286
270
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
287
|
-
details: {
|
|
288
|
-
messageIds: JSON.stringify(messageIds)
|
|
289
|
-
}
|
|
271
|
+
details: { tableName }
|
|
290
272
|
},
|
|
291
273
|
error$1
|
|
292
274
|
);
|
|
293
275
|
}
|
|
294
276
|
}
|
|
295
|
-
async
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
277
|
+
async alterTable({
|
|
278
|
+
tableName,
|
|
279
|
+
schema,
|
|
280
|
+
ifNotExists
|
|
281
|
+
}) {
|
|
282
|
+
try {
|
|
283
|
+
if (!this.client) {
|
|
284
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
285
|
+
}
|
|
286
|
+
if (!tableName) {
|
|
287
|
+
throw new Error("tableName is required for alterTable.");
|
|
288
|
+
}
|
|
289
|
+
if (!schema) {
|
|
290
|
+
throw new Error("schema is required for alterTable.");
|
|
291
|
+
}
|
|
292
|
+
if (!ifNotExists || ifNotExists.length === 0) {
|
|
293
|
+
this.logger.debug("No columns specified to add in alterTable, skipping.");
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
} catch (validationError) {
|
|
299
297
|
throw new error.MastraError(
|
|
300
298
|
{
|
|
301
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
299
|
+
id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "INVALID_ARGS"),
|
|
302
300
|
domain: error.ErrorDomain.STORAGE,
|
|
303
|
-
category: error.ErrorCategory.
|
|
304
|
-
|
|
301
|
+
category: error.ErrorCategory.USER,
|
|
302
|
+
text: validationError.message,
|
|
303
|
+
details: { tableName }
|
|
305
304
|
},
|
|
306
|
-
|
|
305
|
+
validationError
|
|
307
306
|
);
|
|
308
307
|
}
|
|
309
|
-
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
310
|
-
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
311
308
|
try {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
309
|
+
const table = await this.client.openTable(tableName);
|
|
310
|
+
const currentSchema = await table.schema();
|
|
311
|
+
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
312
|
+
const typeMap = {
|
|
313
|
+
text: "string",
|
|
314
|
+
integer: "int",
|
|
315
|
+
bigint: "bigint",
|
|
316
|
+
timestamp: "timestamp",
|
|
317
|
+
jsonb: "string",
|
|
318
|
+
uuid: "string"
|
|
319
|
+
};
|
|
320
|
+
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
321
|
+
const colDef = schema[col];
|
|
322
|
+
return {
|
|
323
|
+
name: col,
|
|
324
|
+
valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
if (columnsToAdd.length > 0) {
|
|
328
|
+
await table.addColumns(columnsToAdd);
|
|
329
|
+
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
322
330
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
331
|
+
} catch (error$1) {
|
|
332
|
+
throw new error.MastraError(
|
|
333
|
+
{
|
|
334
|
+
id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "FAILED"),
|
|
335
|
+
domain: error.ErrorDomain.STORAGE,
|
|
336
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
337
|
+
details: { tableName }
|
|
338
|
+
},
|
|
339
|
+
error$1
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async clearTable({ tableName }) {
|
|
344
|
+
try {
|
|
345
|
+
if (!this.client) {
|
|
346
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
329
347
|
}
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
conditions.push(`\`createdAt\` >= ${startTime}`);
|
|
348
|
+
if (!tableName) {
|
|
349
|
+
throw new Error("tableName is required for clearTable.");
|
|
333
350
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
351
|
+
} catch (validationError) {
|
|
352
|
+
throw new error.MastraError(
|
|
353
|
+
{
|
|
354
|
+
id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "INVALID_ARGS"),
|
|
355
|
+
domain: error.ErrorDomain.STORAGE,
|
|
356
|
+
category: error.ErrorCategory.USER,
|
|
357
|
+
text: validationError.message,
|
|
358
|
+
details: { tableName }
|
|
359
|
+
},
|
|
360
|
+
validationError
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
const table = await this.client.openTable(tableName);
|
|
365
|
+
await table.delete("1=1");
|
|
366
|
+
} catch (error$1) {
|
|
367
|
+
throw new error.MastraError(
|
|
368
|
+
{
|
|
369
|
+
id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "FAILED"),
|
|
370
|
+
domain: error.ErrorDomain.STORAGE,
|
|
371
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
372
|
+
details: { tableName }
|
|
373
|
+
},
|
|
374
|
+
error$1
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async insert({ tableName, record }) {
|
|
379
|
+
try {
|
|
380
|
+
if (!this.client) {
|
|
381
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
337
382
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const query = table.query().where(whereClause);
|
|
341
|
-
let allRecords = await query.toArray();
|
|
342
|
-
allRecords.sort((a, b) => {
|
|
343
|
-
const aValue = field === "createdAt" ? a.createdAt : a[field];
|
|
344
|
-
const bValue = field === "createdAt" ? b.createdAt : b[field];
|
|
345
|
-
if (aValue == null && bValue == null) return 0;
|
|
346
|
-
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
347
|
-
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
348
|
-
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
349
|
-
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
350
|
-
}
|
|
351
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
352
|
-
});
|
|
353
|
-
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
354
|
-
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
355
|
-
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
356
|
-
return {
|
|
357
|
-
messages: [],
|
|
358
|
-
total: 0,
|
|
359
|
-
page,
|
|
360
|
-
perPage: perPageForResponse,
|
|
361
|
-
hasMore: false
|
|
362
|
-
};
|
|
383
|
+
if (!tableName) {
|
|
384
|
+
throw new Error("tableName is required for insert.");
|
|
363
385
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const threadIds2 = [...new Set(include.map((item) => item.threadId || threadId))];
|
|
367
|
-
const allThreadMessages = [];
|
|
368
|
-
for (const tid of threadIds2) {
|
|
369
|
-
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
370
|
-
let threadRecords = await threadQuery.toArray();
|
|
371
|
-
allThreadMessages.push(...threadRecords);
|
|
372
|
-
}
|
|
373
|
-
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
374
|
-
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
375
|
-
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
376
|
-
for (const includeMsg of includedMessages) {
|
|
377
|
-
if (!messageIds.has(includeMsg.id)) {
|
|
378
|
-
messages.push(includeMsg);
|
|
379
|
-
messageIds.add(includeMsg.id);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
386
|
+
if (!record || Object.keys(record).length === 0) {
|
|
387
|
+
throw new Error("record is required and cannot be empty for insert.");
|
|
382
388
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
389
|
+
} catch (validationError) {
|
|
390
|
+
throw new error.MastraError(
|
|
391
|
+
{
|
|
392
|
+
id: storage.createStorageErrorId("LANCE", "INSERT", "INVALID_ARGS"),
|
|
393
|
+
domain: error.ErrorDomain.STORAGE,
|
|
394
|
+
category: error.ErrorCategory.USER,
|
|
395
|
+
text: validationError.message,
|
|
396
|
+
details: { tableName }
|
|
397
|
+
},
|
|
398
|
+
validationError
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const table = await this.client.openTable(tableName);
|
|
403
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
404
|
+
const processedRecord = { ...record };
|
|
405
|
+
for (const key in processedRecord) {
|
|
406
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
407
|
+
this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
|
|
408
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
393
409
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
397
|
-
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
398
|
-
const fetchedAll = perPageInput === false || allThreadMessagesReturned;
|
|
399
|
-
const hasMore = !fetchedAll && offset + perPage < total;
|
|
400
|
-
return {
|
|
401
|
-
messages: finalMessages,
|
|
402
|
-
total,
|
|
403
|
-
page,
|
|
404
|
-
perPage: perPageForResponse,
|
|
405
|
-
hasMore
|
|
406
|
-
};
|
|
410
|
+
}
|
|
411
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
407
412
|
} catch (error$1) {
|
|
408
|
-
|
|
413
|
+
throw new error.MastraError(
|
|
409
414
|
{
|
|
410
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
415
|
+
id: storage.createStorageErrorId("LANCE", "INSERT", "FAILED"),
|
|
411
416
|
domain: error.ErrorDomain.STORAGE,
|
|
412
417
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
413
|
-
details: {
|
|
414
|
-
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
415
|
-
resourceId: resourceId ?? ""
|
|
416
|
-
}
|
|
418
|
+
details: { tableName }
|
|
417
419
|
},
|
|
418
420
|
error$1
|
|
419
421
|
);
|
|
420
|
-
this.logger?.error?.(mastraError.toString());
|
|
421
|
-
this.logger?.trackException?.(mastraError);
|
|
422
|
-
return {
|
|
423
|
-
messages: [],
|
|
424
|
-
total: 0,
|
|
425
|
-
page,
|
|
426
|
-
perPage: perPageForResponse,
|
|
427
|
-
hasMore: false
|
|
428
|
-
};
|
|
429
422
|
}
|
|
430
423
|
}
|
|
431
|
-
async
|
|
424
|
+
async batchInsert({ tableName, records }) {
|
|
432
425
|
try {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
return { messages: [] };
|
|
426
|
+
if (!this.client) {
|
|
427
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
436
428
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
throw new Error("Thread ID is required");
|
|
429
|
+
if (!tableName) {
|
|
430
|
+
throw new Error("tableName is required for batchInsert.");
|
|
440
431
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
throw new Error("Message ID is required");
|
|
444
|
-
}
|
|
445
|
-
if (!message.threadId) {
|
|
446
|
-
throw new Error("Thread ID is required for all messages");
|
|
447
|
-
}
|
|
448
|
-
if (message.resourceId === null || message.resourceId === void 0) {
|
|
449
|
-
throw new Error("Resource ID cannot be null or undefined");
|
|
450
|
-
}
|
|
451
|
-
if (!message.content) {
|
|
452
|
-
throw new Error("Message content is required");
|
|
453
|
-
}
|
|
432
|
+
if (!records || records.length === 0) {
|
|
433
|
+
throw new Error("records array is required and cannot be empty for batchInsert.");
|
|
454
434
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
435
|
+
} catch (validationError) {
|
|
436
|
+
throw new error.MastraError(
|
|
437
|
+
{
|
|
438
|
+
id: storage.createStorageErrorId("LANCE", "BATCH_INSERT", "INVALID_ARGS"),
|
|
439
|
+
domain: error.ErrorDomain.STORAGE,
|
|
440
|
+
category: error.ErrorCategory.USER,
|
|
441
|
+
text: validationError.message,
|
|
442
|
+
details: { tableName }
|
|
443
|
+
},
|
|
444
|
+
validationError
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
const table = await this.client.openTable(tableName);
|
|
449
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
450
|
+
const processedRecords = records.map((record) => {
|
|
451
|
+
const processedRecord = { ...record };
|
|
452
|
+
for (const key in processedRecord) {
|
|
453
|
+
if (processedRecord[key] == null) continue;
|
|
454
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
455
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return processedRecord;
|
|
463
459
|
});
|
|
464
|
-
|
|
465
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
466
|
-
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
467
|
-
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
468
|
-
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
469
|
-
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
470
|
-
const list = new agent.MessageList().add(messages, "memory");
|
|
471
|
-
return { messages: list.get.all.db() };
|
|
460
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
|
|
472
461
|
} catch (error$1) {
|
|
473
462
|
throw new error.MastraError(
|
|
474
463
|
{
|
|
475
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
464
|
+
id: storage.createStorageErrorId("LANCE", "BATCH_INSERT", "FAILED"),
|
|
476
465
|
domain: error.ErrorDomain.STORAGE,
|
|
477
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
466
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
467
|
+
details: { tableName }
|
|
478
468
|
},
|
|
479
469
|
error$1
|
|
480
470
|
);
|
|
481
471
|
}
|
|
482
472
|
}
|
|
483
|
-
async
|
|
473
|
+
async load({ tableName, keys }) {
|
|
484
474
|
try {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
if (page < 0) {
|
|
488
|
-
throw new error.MastraError(
|
|
489
|
-
{
|
|
490
|
-
id: storage.createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
491
|
-
domain: error.ErrorDomain.STORAGE,
|
|
492
|
-
category: error.ErrorCategory.USER,
|
|
493
|
-
details: { page }
|
|
494
|
-
},
|
|
495
|
-
new Error("page must be >= 0")
|
|
496
|
-
);
|
|
475
|
+
if (!this.client) {
|
|
476
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
497
477
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
});
|
|
515
|
-
const paginatedRecords = records.slice(offset, offset + perPage);
|
|
516
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client });
|
|
517
|
-
const threads = paginatedRecords.map(
|
|
518
|
-
(record) => processResultWithTypeConversion(record, schema)
|
|
478
|
+
if (!tableName) {
|
|
479
|
+
throw new Error("tableName is required for load.");
|
|
480
|
+
}
|
|
481
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
482
|
+
throw new Error("keys are required and cannot be empty for load.");
|
|
483
|
+
}
|
|
484
|
+
} catch (validationError) {
|
|
485
|
+
throw new error.MastraError(
|
|
486
|
+
{
|
|
487
|
+
id: storage.createStorageErrorId("LANCE", "LOAD", "INVALID_ARGS"),
|
|
488
|
+
domain: error.ErrorDomain.STORAGE,
|
|
489
|
+
category: error.ErrorCategory.USER,
|
|
490
|
+
text: validationError.message,
|
|
491
|
+
details: { tableName }
|
|
492
|
+
},
|
|
493
|
+
validationError
|
|
519
494
|
);
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
495
|
+
}
|
|
496
|
+
try {
|
|
497
|
+
const table = await this.client.openTable(tableName);
|
|
498
|
+
const tableSchema = await getTableSchema({ tableName, client: this.client });
|
|
499
|
+
const query = table.query();
|
|
500
|
+
if (Object.keys(keys).length > 0) {
|
|
501
|
+
validateKeyTypes(keys, tableSchema);
|
|
502
|
+
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
503
|
+
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
504
|
+
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
505
|
+
if (typeof value === "string") {
|
|
506
|
+
return `${quotedKey} = '${value}'`;
|
|
507
|
+
} else if (value === null) {
|
|
508
|
+
return `${quotedKey} IS NULL`;
|
|
509
|
+
} else {
|
|
510
|
+
return `${quotedKey} = ${value}`;
|
|
511
|
+
}
|
|
512
|
+
}).join(" AND ");
|
|
513
|
+
this.logger.debug("where clause generated: " + filterConditions);
|
|
514
|
+
query.where(filterConditions);
|
|
515
|
+
}
|
|
516
|
+
const result = await query.limit(1).toArray();
|
|
517
|
+
if (result.length === 0) {
|
|
518
|
+
this.logger.debug("No record found");
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
return processResultWithTypeConversion(result[0], tableSchema);
|
|
527
522
|
} catch (error$1) {
|
|
523
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
528
524
|
throw new error.MastraError(
|
|
529
525
|
{
|
|
530
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
526
|
+
id: storage.createStorageErrorId("LANCE", "LOAD", "FAILED"),
|
|
531
527
|
domain: error.ErrorDomain.STORAGE,
|
|
532
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
528
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
529
|
+
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
533
530
|
},
|
|
534
531
|
error$1
|
|
535
532
|
);
|
|
536
533
|
}
|
|
537
534
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
559
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
560
|
-
additionalIndices.add(i);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
if (item.withNextMessages) {
|
|
564
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
565
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
566
|
-
additionalIndices.add(i);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
if (additionalIndices.size === 0) {
|
|
572
|
-
return records;
|
|
573
|
-
}
|
|
574
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
575
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
576
|
-
records.forEach((record, index) => {
|
|
577
|
-
if (originalMatchIds.has(record.id)) {
|
|
578
|
-
allIndices.add(index);
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
additionalIndices.forEach((index) => {
|
|
582
|
-
allIndices.add(index);
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
// src/storage/domains/memory/index.ts
|
|
538
|
+
var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
539
|
+
client;
|
|
540
|
+
#db;
|
|
541
|
+
constructor(config) {
|
|
542
|
+
super();
|
|
543
|
+
const client = resolveLanceConfig(config);
|
|
544
|
+
this.client = client;
|
|
545
|
+
this.#db = new LanceDB({ client });
|
|
546
|
+
}
|
|
547
|
+
async init() {
|
|
548
|
+
await this.#db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
|
|
549
|
+
await this.#db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
|
|
550
|
+
await this.#db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
|
|
551
|
+
await this.#db.alterTable({
|
|
552
|
+
tableName: storage.TABLE_MESSAGES,
|
|
553
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES],
|
|
554
|
+
ifNotExists: ["resourceId"]
|
|
583
555
|
});
|
|
584
|
-
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
585
556
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
const { thread_id, ...rest } = data;
|
|
591
|
-
return {
|
|
592
|
-
...rest,
|
|
593
|
-
threadId: thread_id,
|
|
594
|
-
content: typeof data.content === "string" ? (() => {
|
|
595
|
-
try {
|
|
596
|
-
return JSON.parse(data.content);
|
|
597
|
-
} catch {
|
|
598
|
-
return data.content;
|
|
599
|
-
}
|
|
600
|
-
})() : data.content,
|
|
601
|
-
createdAt: new Date(data.createdAt),
|
|
602
|
-
updatedAt: new Date(data.updatedAt)
|
|
603
|
-
};
|
|
557
|
+
async dangerouslyClearAll() {
|
|
558
|
+
await this.#db.clearTable({ tableName: storage.TABLE_THREADS });
|
|
559
|
+
await this.#db.clearTable({ tableName: storage.TABLE_MESSAGES });
|
|
560
|
+
await this.#db.clearTable({ tableName: storage.TABLE_RESOURCES });
|
|
604
561
|
}
|
|
605
|
-
async
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (!messages.length) {
|
|
609
|
-
return [];
|
|
562
|
+
async deleteMessages(messageIds) {
|
|
563
|
+
if (!messageIds || messageIds.length === 0) {
|
|
564
|
+
return;
|
|
610
565
|
}
|
|
611
|
-
|
|
612
|
-
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
566
|
+
this.logger.debug("Deleting messages", { count: messageIds.length });
|
|
613
567
|
try {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
if (
|
|
618
|
-
|
|
619
|
-
continue;
|
|
620
|
-
}
|
|
621
|
-
const existingMsg = this.parseMessageData(existingMessage);
|
|
622
|
-
const originalThreadId = existingMsg.threadId;
|
|
623
|
-
affectedThreadIds.add(originalThreadId);
|
|
624
|
-
const updatePayload = {};
|
|
625
|
-
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
626
|
-
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
627
|
-
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
628
|
-
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
629
|
-
updatePayload.thread_id = updates.threadId;
|
|
630
|
-
affectedThreadIds.add(updates.threadId);
|
|
631
|
-
}
|
|
632
|
-
if (updates.content) {
|
|
633
|
-
const existingContent = existingMsg.content;
|
|
634
|
-
let newContent = { ...existingContent };
|
|
635
|
-
if (updates.content.metadata !== void 0) {
|
|
636
|
-
newContent.metadata = {
|
|
637
|
-
...existingContent.metadata || {},
|
|
638
|
-
...updates.content.metadata || {}
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
if (updates.content.content !== void 0) {
|
|
642
|
-
newContent.content = updates.content.content;
|
|
643
|
-
}
|
|
644
|
-
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
645
|
-
newContent.parts = updates.content.parts;
|
|
646
|
-
}
|
|
647
|
-
updatePayload.content = JSON.stringify(newContent);
|
|
648
|
-
}
|
|
649
|
-
await this.operations.insert({ tableName: storage.TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
650
|
-
const updatedMessage = await this.operations.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
651
|
-
if (updatedMessage) {
|
|
652
|
-
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
568
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
569
|
+
for (const messageId of messageIds) {
|
|
570
|
+
const message = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id: messageId } });
|
|
571
|
+
if (message?.thread_id) {
|
|
572
|
+
threadIds.add(message.thread_id);
|
|
653
573
|
}
|
|
654
574
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
575
|
+
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
576
|
+
const idConditions = messageIds.map((id) => `id = '${this.escapeSql(id)}'`).join(" OR ");
|
|
577
|
+
await messagesTable.delete(idConditions);
|
|
578
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
579
|
+
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
580
|
+
for (const threadId of threadIds) {
|
|
581
|
+
const thread = await this.getThreadById({ threadId });
|
|
582
|
+
if (thread) {
|
|
583
|
+
const record = {
|
|
584
|
+
id: threadId,
|
|
585
|
+
resourceId: thread.resourceId,
|
|
586
|
+
title: thread.title,
|
|
587
|
+
metadata: JSON.stringify(thread.metadata),
|
|
588
|
+
createdAt: new Date(thread.createdAt).getTime(),
|
|
589
|
+
updatedAt: now
|
|
590
|
+
};
|
|
591
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
592
|
+
}
|
|
660
593
|
}
|
|
661
|
-
return updatedMessages;
|
|
662
594
|
} catch (error$1) {
|
|
663
595
|
throw new error.MastraError(
|
|
664
596
|
{
|
|
665
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
597
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_MESSAGES", "FAILED"),
|
|
666
598
|
domain: error.ErrorDomain.STORAGE,
|
|
667
599
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
668
|
-
details: { count:
|
|
600
|
+
details: { count: messageIds.length }
|
|
669
601
|
},
|
|
670
602
|
error$1
|
|
671
603
|
);
|
|
672
604
|
}
|
|
673
605
|
}
|
|
674
|
-
|
|
606
|
+
// Utility to escape single quotes in SQL strings
|
|
607
|
+
escapeSql(str) {
|
|
608
|
+
return str.replace(/'/g, "''");
|
|
609
|
+
}
|
|
610
|
+
async getThreadById({ threadId }) {
|
|
675
611
|
try {
|
|
676
|
-
const
|
|
677
|
-
if (!
|
|
612
|
+
const thread = await this.#db.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
|
|
613
|
+
if (!thread) {
|
|
678
614
|
return null;
|
|
679
615
|
}
|
|
680
|
-
let createdAt;
|
|
681
|
-
let updatedAt;
|
|
682
|
-
try {
|
|
683
|
-
if (resource.createdAt instanceof Date) {
|
|
684
|
-
createdAt = resource.createdAt;
|
|
685
|
-
} else if (typeof resource.createdAt === "string") {
|
|
686
|
-
createdAt = new Date(resource.createdAt);
|
|
687
|
-
} else if (typeof resource.createdAt === "number") {
|
|
688
|
-
createdAt = new Date(resource.createdAt);
|
|
689
|
-
} else {
|
|
690
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
691
|
-
}
|
|
692
|
-
if (isNaN(createdAt.getTime())) {
|
|
693
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
694
|
-
}
|
|
695
|
-
} catch {
|
|
696
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
697
|
-
}
|
|
698
|
-
try {
|
|
699
|
-
if (resource.updatedAt instanceof Date) {
|
|
700
|
-
updatedAt = resource.updatedAt;
|
|
701
|
-
} else if (typeof resource.updatedAt === "string") {
|
|
702
|
-
updatedAt = new Date(resource.updatedAt);
|
|
703
|
-
} else if (typeof resource.updatedAt === "number") {
|
|
704
|
-
updatedAt = new Date(resource.updatedAt);
|
|
705
|
-
} else {
|
|
706
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
707
|
-
}
|
|
708
|
-
if (isNaN(updatedAt.getTime())) {
|
|
709
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
710
|
-
}
|
|
711
|
-
} catch {
|
|
712
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
713
|
-
}
|
|
714
|
-
let workingMemory = resource.workingMemory;
|
|
715
|
-
if (workingMemory === null || workingMemory === void 0) {
|
|
716
|
-
workingMemory = void 0;
|
|
717
|
-
} else if (workingMemory === "") {
|
|
718
|
-
workingMemory = "";
|
|
719
|
-
} else if (typeof workingMemory === "object") {
|
|
720
|
-
workingMemory = JSON.stringify(workingMemory);
|
|
721
|
-
}
|
|
722
|
-
let metadata = resource.metadata;
|
|
723
|
-
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
724
|
-
metadata = void 0;
|
|
725
|
-
} else if (typeof metadata === "string") {
|
|
726
|
-
try {
|
|
727
|
-
metadata = JSON.parse(metadata);
|
|
728
|
-
} catch {
|
|
729
|
-
metadata = metadata;
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
616
|
return {
|
|
733
|
-
...
|
|
734
|
-
createdAt,
|
|
735
|
-
updatedAt
|
|
736
|
-
workingMemory,
|
|
737
|
-
metadata
|
|
617
|
+
...thread,
|
|
618
|
+
createdAt: new Date(thread.createdAt),
|
|
619
|
+
updatedAt: new Date(thread.updatedAt)
|
|
738
620
|
};
|
|
739
621
|
} catch (error$1) {
|
|
740
622
|
throw new error.MastraError(
|
|
741
623
|
{
|
|
742
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
624
|
+
id: storage.createStorageErrorId("LANCE", "GET_THREAD_BY_ID", "FAILED"),
|
|
743
625
|
domain: error.ErrorDomain.STORAGE,
|
|
744
626
|
category: error.ErrorCategory.THIRD_PARTY
|
|
745
627
|
},
|
|
@@ -747,23 +629,21 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
747
629
|
);
|
|
748
630
|
}
|
|
749
631
|
}
|
|
750
|
-
|
|
632
|
+
/**
|
|
633
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
634
|
+
* @param thread - The thread to save
|
|
635
|
+
* @returns The saved thread
|
|
636
|
+
*/
|
|
637
|
+
async saveThread({ thread }) {
|
|
751
638
|
try {
|
|
752
|
-
const record = {
|
|
753
|
-
|
|
754
|
-
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
755
|
-
createdAt: resource.createdAt.getTime(),
|
|
756
|
-
// Store as timestamp (milliseconds)
|
|
757
|
-
updatedAt: resource.updatedAt.getTime()
|
|
758
|
-
// Store as timestamp (milliseconds)
|
|
759
|
-
};
|
|
760
|
-
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
639
|
+
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
640
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
761
641
|
await table.add([record], { mode: "append" });
|
|
762
|
-
return
|
|
642
|
+
return thread;
|
|
763
643
|
} catch (error$1) {
|
|
764
644
|
throw new error.MastraError(
|
|
765
645
|
{
|
|
766
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
646
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_THREAD", "FAILED"),
|
|
767
647
|
domain: error.ErrorDomain.STORAGE,
|
|
768
648
|
category: error.ErrorCategory.THIRD_PARTY
|
|
769
649
|
},
|
|
@@ -771,44 +651,32 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
771
651
|
);
|
|
772
652
|
}
|
|
773
653
|
}
|
|
774
|
-
async
|
|
775
|
-
|
|
776
|
-
|
|
654
|
+
async updateThread({
|
|
655
|
+
id,
|
|
656
|
+
title,
|
|
777
657
|
metadata
|
|
778
658
|
}) {
|
|
779
|
-
const maxRetries =
|
|
780
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
781
|
-
try {
|
|
782
|
-
const
|
|
783
|
-
if (!
|
|
784
|
-
|
|
785
|
-
id: resourceId,
|
|
786
|
-
workingMemory,
|
|
787
|
-
metadata: metadata || {},
|
|
788
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
789
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
790
|
-
};
|
|
791
|
-
return this.saveResource({ resource: newResource });
|
|
659
|
+
const maxRetries = 5;
|
|
660
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
661
|
+
try {
|
|
662
|
+
const current = await this.getThreadById({ threadId: id });
|
|
663
|
+
if (!current) {
|
|
664
|
+
throw new Error(`Thread with id ${id} not found`);
|
|
792
665
|
}
|
|
793
|
-
const
|
|
794
|
-
...existingResource,
|
|
795
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
796
|
-
metadata: {
|
|
797
|
-
...existingResource.metadata,
|
|
798
|
-
...metadata
|
|
799
|
-
},
|
|
800
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
801
|
-
};
|
|
666
|
+
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
802
667
|
const record = {
|
|
803
|
-
id
|
|
804
|
-
|
|
805
|
-
metadata:
|
|
806
|
-
updatedAt:
|
|
807
|
-
// Store as timestamp (milliseconds)
|
|
668
|
+
id,
|
|
669
|
+
title,
|
|
670
|
+
metadata: JSON.stringify(mergedMetadata),
|
|
671
|
+
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
808
672
|
};
|
|
809
|
-
const table = await this.client.openTable(storage.
|
|
673
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
810
674
|
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
811
|
-
|
|
675
|
+
const updatedThread = await this.getThreadById({ threadId: id });
|
|
676
|
+
if (!updatedThread) {
|
|
677
|
+
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
678
|
+
}
|
|
679
|
+
return updatedThread;
|
|
812
680
|
} catch (error$1) {
|
|
813
681
|
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
814
682
|
const delay = Math.pow(2, attempt) * 10;
|
|
@@ -817,7 +685,7 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
817
685
|
}
|
|
818
686
|
throw new error.MastraError(
|
|
819
687
|
{
|
|
820
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
688
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
821
689
|
domain: error.ErrorDomain.STORAGE,
|
|
822
690
|
category: error.ErrorCategory.THIRD_PARTY
|
|
823
691
|
},
|
|
@@ -825,418 +693,630 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
|
825
693
|
);
|
|
826
694
|
}
|
|
827
695
|
}
|
|
828
|
-
throw new
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
837
|
-
getDefaultValue(type) {
|
|
838
|
-
switch (type) {
|
|
839
|
-
case "text":
|
|
840
|
-
return "''";
|
|
841
|
-
case "timestamp":
|
|
842
|
-
return "CURRENT_TIMESTAMP";
|
|
843
|
-
case "integer":
|
|
844
|
-
case "bigint":
|
|
845
|
-
return "0";
|
|
846
|
-
case "jsonb":
|
|
847
|
-
return "'{}'";
|
|
848
|
-
case "uuid":
|
|
849
|
-
return "''";
|
|
850
|
-
default:
|
|
851
|
-
return super.getDefaultValue(type);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
async hasColumn(tableName, columnName) {
|
|
855
|
-
const table = await this.client.openTable(tableName);
|
|
856
|
-
const schema = await table.schema();
|
|
857
|
-
return schema.fields.some((field) => field.name === columnName);
|
|
858
|
-
}
|
|
859
|
-
translateSchema(schema) {
|
|
860
|
-
const fields = Object.entries(schema).map(([name, column]) => {
|
|
861
|
-
let arrowType;
|
|
862
|
-
switch (column.type.toLowerCase()) {
|
|
863
|
-
case "text":
|
|
864
|
-
case "uuid":
|
|
865
|
-
arrowType = new apacheArrow.Utf8();
|
|
866
|
-
break;
|
|
867
|
-
case "int":
|
|
868
|
-
case "integer":
|
|
869
|
-
arrowType = new apacheArrow.Int32();
|
|
870
|
-
break;
|
|
871
|
-
case "bigint":
|
|
872
|
-
arrowType = new apacheArrow.Float64();
|
|
873
|
-
break;
|
|
874
|
-
case "float":
|
|
875
|
-
arrowType = new apacheArrow.Float32();
|
|
876
|
-
break;
|
|
877
|
-
case "jsonb":
|
|
878
|
-
case "json":
|
|
879
|
-
arrowType = new apacheArrow.Utf8();
|
|
880
|
-
break;
|
|
881
|
-
case "binary":
|
|
882
|
-
arrowType = new apacheArrow.Binary();
|
|
883
|
-
break;
|
|
884
|
-
case "timestamp":
|
|
885
|
-
arrowType = new apacheArrow.Float64();
|
|
886
|
-
break;
|
|
887
|
-
default:
|
|
888
|
-
arrowType = new apacheArrow.Utf8();
|
|
889
|
-
}
|
|
890
|
-
return new apacheArrow.Field(name, arrowType, column.nullable ?? true);
|
|
891
|
-
});
|
|
892
|
-
return new apacheArrow.Schema(fields);
|
|
696
|
+
throw new error.MastraError(
|
|
697
|
+
{
|
|
698
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
699
|
+
domain: error.ErrorDomain.STORAGE,
|
|
700
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
701
|
+
},
|
|
702
|
+
new Error("All retries exhausted")
|
|
703
|
+
);
|
|
893
704
|
}
|
|
894
|
-
async
|
|
895
|
-
tableName,
|
|
896
|
-
schema
|
|
897
|
-
}) {
|
|
705
|
+
async deleteThread({ threadId }) {
|
|
898
706
|
try {
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
throw new Error("tableName is required for createTable.");
|
|
904
|
-
}
|
|
905
|
-
if (!schema) {
|
|
906
|
-
throw new Error("schema is required for createTable.");
|
|
907
|
-
}
|
|
707
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
708
|
+
await table.delete(`id = '${threadId}'`);
|
|
709
|
+
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
710
|
+
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
908
711
|
} catch (error$1) {
|
|
909
712
|
throw new error.MastraError(
|
|
910
713
|
{
|
|
911
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
714
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_THREAD", "FAILED"),
|
|
912
715
|
domain: error.ErrorDomain.STORAGE,
|
|
913
|
-
category: error.ErrorCategory.
|
|
914
|
-
details: { tableName }
|
|
716
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
915
717
|
},
|
|
916
718
|
error$1
|
|
917
719
|
);
|
|
918
720
|
}
|
|
721
|
+
}
|
|
722
|
+
normalizeMessage(message) {
|
|
723
|
+
const { thread_id, ...rest } = message;
|
|
724
|
+
return {
|
|
725
|
+
...rest,
|
|
726
|
+
threadId: thread_id,
|
|
727
|
+
content: typeof message.content === "string" ? (() => {
|
|
728
|
+
try {
|
|
729
|
+
return JSON.parse(message.content);
|
|
730
|
+
} catch {
|
|
731
|
+
return message.content;
|
|
732
|
+
}
|
|
733
|
+
})() : message.content
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
async listMessagesById({ messageIds }) {
|
|
737
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
919
738
|
try {
|
|
920
|
-
const
|
|
921
|
-
|
|
739
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
740
|
+
const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
|
|
741
|
+
const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
|
|
742
|
+
const messages = processResultWithTypeConversion(
|
|
743
|
+
allRecords,
|
|
744
|
+
await getTableSchema({ tableName: storage.TABLE_MESSAGES, client: this.client })
|
|
745
|
+
);
|
|
746
|
+
const list = new agent.MessageList().add(
|
|
747
|
+
messages.map(this.normalizeMessage),
|
|
748
|
+
"memory"
|
|
749
|
+
);
|
|
750
|
+
return { messages: list.get.all.db() };
|
|
922
751
|
} catch (error$1) {
|
|
923
|
-
if (error$1.message?.includes("already exists")) {
|
|
924
|
-
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
752
|
throw new error.MastraError(
|
|
928
753
|
{
|
|
929
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
754
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
930
755
|
domain: error.ErrorDomain.STORAGE,
|
|
931
756
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
932
|
-
details: {
|
|
757
|
+
details: {
|
|
758
|
+
messageIds: JSON.stringify(messageIds)
|
|
759
|
+
}
|
|
933
760
|
},
|
|
934
761
|
error$1
|
|
935
762
|
);
|
|
936
763
|
}
|
|
937
764
|
}
|
|
938
|
-
async
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
}
|
|
943
|
-
if (!tableName) {
|
|
944
|
-
throw new Error("tableName is required for dropTable.");
|
|
945
|
-
}
|
|
946
|
-
} catch (validationError) {
|
|
765
|
+
async listMessages(args) {
|
|
766
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
767
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
768
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
947
769
|
throw new error.MastraError(
|
|
948
770
|
{
|
|
949
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
771
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
950
772
|
domain: error.ErrorDomain.STORAGE,
|
|
951
|
-
category: error.ErrorCategory.
|
|
952
|
-
|
|
953
|
-
details: { tableName }
|
|
773
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
774
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
954
775
|
},
|
|
955
|
-
|
|
776
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
956
777
|
);
|
|
957
778
|
}
|
|
779
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
780
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
958
781
|
try {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
782
|
+
if (page < 0) {
|
|
783
|
+
throw new error.MastraError(
|
|
784
|
+
{
|
|
785
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
786
|
+
domain: error.ErrorDomain.STORAGE,
|
|
787
|
+
category: error.ErrorCategory.USER,
|
|
788
|
+
details: { page }
|
|
789
|
+
},
|
|
790
|
+
new Error("page must be >= 0")
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
794
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
795
|
+
const threadCondition = threadIds.length === 1 ? `thread_id = '${this.escapeSql(threadIds[0])}'` : `thread_id IN (${threadIds.map((t) => `'${this.escapeSql(t)}'`).join(", ")})`;
|
|
796
|
+
const conditions = [threadCondition];
|
|
797
|
+
if (resourceId) {
|
|
798
|
+
conditions.push(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
799
|
+
}
|
|
800
|
+
if (filter?.dateRange?.start) {
|
|
801
|
+
const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
|
|
802
|
+
conditions.push(`\`createdAt\` >= ${startTime}`);
|
|
803
|
+
}
|
|
804
|
+
if (filter?.dateRange?.end) {
|
|
805
|
+
const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
|
|
806
|
+
conditions.push(`\`createdAt\` <= ${endTime}`);
|
|
807
|
+
}
|
|
808
|
+
const whereClause = conditions.join(" AND ");
|
|
809
|
+
const total = await table.countRows(whereClause);
|
|
810
|
+
const query = table.query().where(whereClause);
|
|
811
|
+
let allRecords = await query.toArray();
|
|
812
|
+
allRecords.sort((a, b) => {
|
|
813
|
+
const aValue = field === "createdAt" ? a.createdAt : a[field];
|
|
814
|
+
const bValue = field === "createdAt" ? b.createdAt : b[field];
|
|
815
|
+
if (aValue == null && bValue == null) return 0;
|
|
816
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
817
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
818
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
819
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
820
|
+
}
|
|
821
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
822
|
+
});
|
|
823
|
+
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
824
|
+
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
825
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
826
|
+
return {
|
|
827
|
+
messages: [],
|
|
828
|
+
total: 0,
|
|
829
|
+
page,
|
|
830
|
+
perPage: perPageForResponse,
|
|
831
|
+
hasMore: false
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
835
|
+
if (include && include.length > 0) {
|
|
836
|
+
const threadIds2 = [...new Set(include.map((item) => item.threadId || threadId))];
|
|
837
|
+
const allThreadMessages = [];
|
|
838
|
+
for (const tid of threadIds2) {
|
|
839
|
+
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
840
|
+
let threadRecords = await threadQuery.toArray();
|
|
841
|
+
allThreadMessages.push(...threadRecords);
|
|
842
|
+
}
|
|
843
|
+
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
844
|
+
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
845
|
+
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
846
|
+
for (const includeMsg of includedMessages) {
|
|
847
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
848
|
+
messages.push(includeMsg);
|
|
849
|
+
messageIds.add(includeMsg.id);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
964
852
|
}
|
|
965
|
-
|
|
853
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
854
|
+
let finalMessages = list.get.all.db();
|
|
855
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
856
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
857
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
858
|
+
if (aValue == null && bValue == null) return 0;
|
|
859
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
860
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
861
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
862
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
863
|
+
}
|
|
864
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
865
|
+
});
|
|
866
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
867
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
868
|
+
const fetchedAll = perPageInput === false || allThreadMessagesReturned;
|
|
869
|
+
const hasMore = !fetchedAll && offset + perPage < total;
|
|
870
|
+
return {
|
|
871
|
+
messages: finalMessages,
|
|
872
|
+
total,
|
|
873
|
+
page,
|
|
874
|
+
perPage: perPageForResponse,
|
|
875
|
+
hasMore
|
|
876
|
+
};
|
|
877
|
+
} catch (error$1) {
|
|
878
|
+
const mastraError = new error.MastraError(
|
|
966
879
|
{
|
|
967
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
880
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "FAILED"),
|
|
968
881
|
domain: error.ErrorDomain.STORAGE,
|
|
969
882
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
970
|
-
details: {
|
|
883
|
+
details: {
|
|
884
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
885
|
+
resourceId: resourceId ?? ""
|
|
886
|
+
}
|
|
971
887
|
},
|
|
972
888
|
error$1
|
|
973
889
|
);
|
|
890
|
+
this.logger?.error?.(mastraError.toString());
|
|
891
|
+
this.logger?.trackException?.(mastraError);
|
|
892
|
+
return {
|
|
893
|
+
messages: [],
|
|
894
|
+
total: 0,
|
|
895
|
+
page,
|
|
896
|
+
perPage: perPageForResponse,
|
|
897
|
+
hasMore: false
|
|
898
|
+
};
|
|
974
899
|
}
|
|
975
900
|
}
|
|
976
|
-
async
|
|
977
|
-
tableName,
|
|
978
|
-
schema,
|
|
979
|
-
ifNotExists
|
|
980
|
-
}) {
|
|
901
|
+
async saveMessages(args) {
|
|
981
902
|
try {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
if (!tableName) {
|
|
986
|
-
throw new Error("tableName is required for alterTable.");
|
|
903
|
+
const { messages } = args;
|
|
904
|
+
if (messages.length === 0) {
|
|
905
|
+
return { messages: [] };
|
|
987
906
|
}
|
|
988
|
-
|
|
989
|
-
|
|
907
|
+
const threadId = messages[0]?.threadId;
|
|
908
|
+
if (!threadId) {
|
|
909
|
+
throw new Error("Thread ID is required");
|
|
990
910
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
911
|
+
for (const message of messages) {
|
|
912
|
+
if (!message.id) {
|
|
913
|
+
throw new Error("Message ID is required");
|
|
914
|
+
}
|
|
915
|
+
if (!message.threadId) {
|
|
916
|
+
throw new Error("Thread ID is required for all messages");
|
|
917
|
+
}
|
|
918
|
+
if (message.resourceId === null || message.resourceId === void 0) {
|
|
919
|
+
throw new Error("Resource ID cannot be null or undefined");
|
|
920
|
+
}
|
|
921
|
+
if (!message.content) {
|
|
922
|
+
throw new Error("Message content is required");
|
|
923
|
+
}
|
|
994
924
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
{
|
|
998
|
-
id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "INVALID_ARGS"),
|
|
999
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1000
|
-
category: error.ErrorCategory.USER,
|
|
1001
|
-
text: validationError.message,
|
|
1002
|
-
details: { tableName }
|
|
1003
|
-
},
|
|
1004
|
-
validationError
|
|
1005
|
-
);
|
|
1006
|
-
}
|
|
1007
|
-
try {
|
|
1008
|
-
const table = await this.client.openTable(tableName);
|
|
1009
|
-
const currentSchema = await table.schema();
|
|
1010
|
-
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
1011
|
-
const typeMap = {
|
|
1012
|
-
text: "string",
|
|
1013
|
-
integer: "int",
|
|
1014
|
-
bigint: "bigint",
|
|
1015
|
-
timestamp: "timestamp",
|
|
1016
|
-
jsonb: "string",
|
|
1017
|
-
uuid: "string"
|
|
1018
|
-
};
|
|
1019
|
-
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
1020
|
-
const colDef = schema[col];
|
|
925
|
+
const transformedMessages = messages.map((message) => {
|
|
926
|
+
const { threadId: threadId2, type, ...rest } = message;
|
|
1021
927
|
return {
|
|
1022
|
-
|
|
1023
|
-
|
|
928
|
+
...rest,
|
|
929
|
+
thread_id: threadId2,
|
|
930
|
+
type: type ?? "v2",
|
|
931
|
+
content: JSON.stringify(message.content)
|
|
1024
932
|
};
|
|
1025
933
|
});
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
934
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
935
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
936
|
+
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
937
|
+
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
938
|
+
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
939
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
940
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
941
|
+
return { messages: list.get.all.db() };
|
|
1030
942
|
} catch (error$1) {
|
|
1031
943
|
throw new error.MastraError(
|
|
1032
944
|
{
|
|
1033
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
945
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_MESSAGES", "FAILED"),
|
|
1034
946
|
domain: error.ErrorDomain.STORAGE,
|
|
1035
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1036
|
-
details: { tableName }
|
|
947
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1037
948
|
},
|
|
1038
949
|
error$1
|
|
1039
950
|
);
|
|
1040
951
|
}
|
|
1041
952
|
}
|
|
1042
|
-
async
|
|
953
|
+
async listThreadsByResourceId(args) {
|
|
1043
954
|
try {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
955
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
956
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
957
|
+
if (page < 0) {
|
|
958
|
+
throw new error.MastraError(
|
|
959
|
+
{
|
|
960
|
+
id: storage.createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
961
|
+
domain: error.ErrorDomain.STORAGE,
|
|
962
|
+
category: error.ErrorCategory.USER,
|
|
963
|
+
details: { page }
|
|
964
|
+
},
|
|
965
|
+
new Error("page must be >= 0")
|
|
966
|
+
);
|
|
1049
967
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
968
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
969
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
970
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
971
|
+
const total = await table.countRows(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
972
|
+
const query = table.query().where(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
973
|
+
const records = await query.toArray();
|
|
974
|
+
records.sort((a, b) => {
|
|
975
|
+
const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
|
|
976
|
+
const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
|
|
977
|
+
if (aValue == null && bValue == null) return 0;
|
|
978
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
979
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
980
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
981
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
982
|
+
}
|
|
983
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
984
|
+
});
|
|
985
|
+
const paginatedRecords = records.slice(offset, offset + perPage);
|
|
986
|
+
const schema = await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client });
|
|
987
|
+
const threads = paginatedRecords.map(
|
|
988
|
+
(record) => processResultWithTypeConversion(record, schema)
|
|
1060
989
|
);
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
990
|
+
return {
|
|
991
|
+
threads,
|
|
992
|
+
total,
|
|
993
|
+
page,
|
|
994
|
+
perPage: perPageForResponse,
|
|
995
|
+
hasMore: offset + perPage < total
|
|
996
|
+
};
|
|
1065
997
|
} catch (error$1) {
|
|
1066
998
|
throw new error.MastraError(
|
|
1067
999
|
{
|
|
1068
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
1000
|
+
id: storage.createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
1069
1001
|
domain: error.ErrorDomain.STORAGE,
|
|
1070
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1071
|
-
details: { tableName }
|
|
1002
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1072
1003
|
},
|
|
1073
1004
|
error$1
|
|
1074
1005
|
);
|
|
1075
1006
|
}
|
|
1076
1007
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1008
|
+
/**
|
|
1009
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
1010
|
+
* @param records - The sorted array of records to process
|
|
1011
|
+
* @param include - The array of include specifications with context parameters
|
|
1012
|
+
* @returns The processed array with context messages included
|
|
1013
|
+
*/
|
|
1014
|
+
processMessagesWithContext(records, include) {
|
|
1015
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
1016
|
+
if (messagesWithContext.length === 0) {
|
|
1017
|
+
return records;
|
|
1018
|
+
}
|
|
1019
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1020
|
+
records.forEach((message, index) => {
|
|
1021
|
+
messageIndexMap.set(message.id, index);
|
|
1022
|
+
});
|
|
1023
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
1024
|
+
for (const item of messagesWithContext) {
|
|
1025
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
1026
|
+
if (messageIndex !== void 0) {
|
|
1027
|
+
if (item.withPreviousMessages) {
|
|
1028
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
1029
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
1030
|
+
additionalIndices.add(i);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
if (item.withNextMessages) {
|
|
1034
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
1035
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
1036
|
+
additionalIndices.add(i);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1084
1039
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1040
|
+
}
|
|
1041
|
+
if (additionalIndices.size === 0) {
|
|
1042
|
+
return records;
|
|
1043
|
+
}
|
|
1044
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1045
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
1046
|
+
records.forEach((record, index) => {
|
|
1047
|
+
if (originalMatchIds.has(record.id)) {
|
|
1048
|
+
allIndices.add(index);
|
|
1087
1049
|
}
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1050
|
+
});
|
|
1051
|
+
additionalIndices.forEach((index) => {
|
|
1052
|
+
allIndices.add(index);
|
|
1053
|
+
});
|
|
1054
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Parse message data from LanceDB record format to MastraDBMessage format
|
|
1058
|
+
*/
|
|
1059
|
+
parseMessageData(data) {
|
|
1060
|
+
const { thread_id, ...rest } = data;
|
|
1061
|
+
return {
|
|
1062
|
+
...rest,
|
|
1063
|
+
threadId: thread_id,
|
|
1064
|
+
content: typeof data.content === "string" ? (() => {
|
|
1065
|
+
try {
|
|
1066
|
+
return JSON.parse(data.content);
|
|
1067
|
+
} catch {
|
|
1068
|
+
return data.content;
|
|
1069
|
+
}
|
|
1070
|
+
})() : data.content,
|
|
1071
|
+
createdAt: new Date(data.createdAt),
|
|
1072
|
+
updatedAt: new Date(data.updatedAt)
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
async updateMessages(args) {
|
|
1076
|
+
const { messages } = args;
|
|
1077
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1078
|
+
if (!messages.length) {
|
|
1079
|
+
return [];
|
|
1099
1080
|
}
|
|
1081
|
+
const updatedMessages = [];
|
|
1082
|
+
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
1100
1083
|
try {
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1084
|
+
for (const updateData of messages) {
|
|
1085
|
+
const { id, ...updates } = updateData;
|
|
1086
|
+
const existingMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
1087
|
+
if (!existingMessage) {
|
|
1088
|
+
this.logger.warn("Message not found for update", { id });
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1091
|
+
const existingMsg = this.parseMessageData(existingMessage);
|
|
1092
|
+
const originalThreadId = existingMsg.threadId;
|
|
1093
|
+
affectedThreadIds.add(originalThreadId);
|
|
1094
|
+
const updatePayload = {};
|
|
1095
|
+
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
1096
|
+
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
1097
|
+
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
1098
|
+
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
1099
|
+
updatePayload.thread_id = updates.threadId;
|
|
1100
|
+
affectedThreadIds.add(updates.threadId);
|
|
1101
|
+
}
|
|
1102
|
+
if (updates.content) {
|
|
1103
|
+
const existingContent = existingMsg.content;
|
|
1104
|
+
let newContent = { ...existingContent };
|
|
1105
|
+
if (updates.content.metadata !== void 0) {
|
|
1106
|
+
newContent.metadata = {
|
|
1107
|
+
...existingContent.metadata || {},
|
|
1108
|
+
...updates.content.metadata || {}
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
if (updates.content.content !== void 0) {
|
|
1112
|
+
newContent.content = updates.content.content;
|
|
1113
|
+
}
|
|
1114
|
+
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
1115
|
+
newContent.parts = updates.content.parts;
|
|
1116
|
+
}
|
|
1117
|
+
updatePayload.content = JSON.stringify(newContent);
|
|
1118
|
+
}
|
|
1119
|
+
await this.#db.insert({ tableName: storage.TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
1120
|
+
const updatedMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
1121
|
+
if (updatedMessage) {
|
|
1122
|
+
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
1108
1123
|
}
|
|
1109
1124
|
}
|
|
1110
|
-
|
|
1125
|
+
for (const threadId of affectedThreadIds) {
|
|
1126
|
+
await this.#db.insert({
|
|
1127
|
+
tableName: storage.TABLE_THREADS,
|
|
1128
|
+
record: { id: threadId, updatedAt: Date.now() }
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
return updatedMessages;
|
|
1111
1132
|
} catch (error$1) {
|
|
1112
1133
|
throw new error.MastraError(
|
|
1113
1134
|
{
|
|
1114
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
1135
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_MESSAGES", "FAILED"),
|
|
1115
1136
|
domain: error.ErrorDomain.STORAGE,
|
|
1116
1137
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1117
|
-
details: {
|
|
1138
|
+
details: { count: messages.length }
|
|
1118
1139
|
},
|
|
1119
1140
|
error$1
|
|
1120
1141
|
);
|
|
1121
1142
|
}
|
|
1122
1143
|
}
|
|
1123
|
-
async
|
|
1144
|
+
async getResourceById({ resourceId }) {
|
|
1124
1145
|
try {
|
|
1125
|
-
|
|
1126
|
-
|
|
1146
|
+
const resource = await this.#db.load({ tableName: storage.TABLE_RESOURCES, keys: { id: resourceId } });
|
|
1147
|
+
if (!resource) {
|
|
1148
|
+
return null;
|
|
1127
1149
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1150
|
+
let createdAt;
|
|
1151
|
+
let updatedAt;
|
|
1152
|
+
try {
|
|
1153
|
+
if (resource.createdAt instanceof Date) {
|
|
1154
|
+
createdAt = resource.createdAt;
|
|
1155
|
+
} else if (typeof resource.createdAt === "string") {
|
|
1156
|
+
createdAt = new Date(resource.createdAt);
|
|
1157
|
+
} else if (typeof resource.createdAt === "number") {
|
|
1158
|
+
createdAt = new Date(resource.createdAt);
|
|
1159
|
+
} else {
|
|
1160
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1161
|
+
}
|
|
1162
|
+
if (isNaN(createdAt.getTime())) {
|
|
1163
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1164
|
+
}
|
|
1165
|
+
} catch {
|
|
1166
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1130
1167
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1168
|
+
try {
|
|
1169
|
+
if (resource.updatedAt instanceof Date) {
|
|
1170
|
+
updatedAt = resource.updatedAt;
|
|
1171
|
+
} else if (typeof resource.updatedAt === "string") {
|
|
1172
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1173
|
+
} else if (typeof resource.updatedAt === "number") {
|
|
1174
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1175
|
+
} else {
|
|
1176
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1177
|
+
}
|
|
1178
|
+
if (isNaN(updatedAt.getTime())) {
|
|
1179
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1180
|
+
}
|
|
1181
|
+
} catch {
|
|
1182
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1133
1183
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
const processedRecord = { ...record };
|
|
1151
|
-
for (const key in processedRecord) {
|
|
1152
|
-
if (processedRecord[key] == null) continue;
|
|
1153
|
-
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
1154
|
-
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
1155
|
-
}
|
|
1184
|
+
let workingMemory = resource.workingMemory;
|
|
1185
|
+
if (workingMemory === null || workingMemory === void 0) {
|
|
1186
|
+
workingMemory = void 0;
|
|
1187
|
+
} else if (workingMemory === "") {
|
|
1188
|
+
workingMemory = "";
|
|
1189
|
+
} else if (typeof workingMemory === "object") {
|
|
1190
|
+
workingMemory = JSON.stringify(workingMemory);
|
|
1191
|
+
}
|
|
1192
|
+
let metadata = resource.metadata;
|
|
1193
|
+
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
1194
|
+
metadata = void 0;
|
|
1195
|
+
} else if (typeof metadata === "string") {
|
|
1196
|
+
try {
|
|
1197
|
+
metadata = JSON.parse(metadata);
|
|
1198
|
+
} catch {
|
|
1199
|
+
metadata = metadata;
|
|
1156
1200
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1201
|
+
}
|
|
1202
|
+
return {
|
|
1203
|
+
...resource,
|
|
1204
|
+
createdAt,
|
|
1205
|
+
updatedAt,
|
|
1206
|
+
workingMemory,
|
|
1207
|
+
metadata
|
|
1208
|
+
};
|
|
1160
1209
|
} catch (error$1) {
|
|
1161
1210
|
throw new error.MastraError(
|
|
1162
1211
|
{
|
|
1163
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
1212
|
+
id: storage.createStorageErrorId("LANCE", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
1164
1213
|
domain: error.ErrorDomain.STORAGE,
|
|
1165
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1166
|
-
details: { tableName }
|
|
1214
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1167
1215
|
},
|
|
1168
1216
|
error$1
|
|
1169
1217
|
);
|
|
1170
1218
|
}
|
|
1171
1219
|
}
|
|
1172
|
-
async
|
|
1173
|
-
try {
|
|
1174
|
-
if (!this.client) {
|
|
1175
|
-
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1176
|
-
}
|
|
1177
|
-
if (!tableName) {
|
|
1178
|
-
throw new Error("tableName is required for load.");
|
|
1179
|
-
}
|
|
1180
|
-
if (!keys || Object.keys(keys).length === 0) {
|
|
1181
|
-
throw new Error("keys are required and cannot be empty for load.");
|
|
1182
|
-
}
|
|
1183
|
-
} catch (validationError) {
|
|
1184
|
-
throw new error.MastraError(
|
|
1185
|
-
{
|
|
1186
|
-
id: storage.createStorageErrorId("LANCE", "LOAD", "INVALID_ARGS"),
|
|
1187
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1188
|
-
category: error.ErrorCategory.USER,
|
|
1189
|
-
text: validationError.message,
|
|
1190
|
-
details: { tableName }
|
|
1191
|
-
},
|
|
1192
|
-
validationError
|
|
1193
|
-
);
|
|
1194
|
-
}
|
|
1220
|
+
async saveResource({ resource }) {
|
|
1195
1221
|
try {
|
|
1196
|
-
const
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
return `${quotedKey} IS NULL`;
|
|
1208
|
-
} else {
|
|
1209
|
-
return `${quotedKey} = ${value}`;
|
|
1210
|
-
}
|
|
1211
|
-
}).join(" AND ");
|
|
1212
|
-
this.logger.debug("where clause generated: " + filterConditions);
|
|
1213
|
-
query.where(filterConditions);
|
|
1214
|
-
}
|
|
1215
|
-
const result = await query.limit(1).toArray();
|
|
1216
|
-
if (result.length === 0) {
|
|
1217
|
-
this.logger.debug("No record found");
|
|
1218
|
-
return null;
|
|
1219
|
-
}
|
|
1220
|
-
return processResultWithTypeConversion(result[0], tableSchema);
|
|
1222
|
+
const record = {
|
|
1223
|
+
...resource,
|
|
1224
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
1225
|
+
createdAt: resource.createdAt.getTime(),
|
|
1226
|
+
// Store as timestamp (milliseconds)
|
|
1227
|
+
updatedAt: resource.updatedAt.getTime()
|
|
1228
|
+
// Store as timestamp (milliseconds)
|
|
1229
|
+
};
|
|
1230
|
+
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
1231
|
+
await table.add([record], { mode: "append" });
|
|
1232
|
+
return resource;
|
|
1221
1233
|
} catch (error$1) {
|
|
1222
|
-
if (error$1 instanceof error.MastraError) throw error$1;
|
|
1223
1234
|
throw new error.MastraError(
|
|
1224
1235
|
{
|
|
1225
|
-
id: storage.createStorageErrorId("LANCE", "
|
|
1236
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_RESOURCE", "FAILED"),
|
|
1226
1237
|
domain: error.ErrorDomain.STORAGE,
|
|
1227
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1228
|
-
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
1238
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1229
1239
|
},
|
|
1230
1240
|
error$1
|
|
1231
1241
|
);
|
|
1232
1242
|
}
|
|
1233
1243
|
}
|
|
1244
|
+
async updateResource({
|
|
1245
|
+
resourceId,
|
|
1246
|
+
workingMemory,
|
|
1247
|
+
metadata
|
|
1248
|
+
}) {
|
|
1249
|
+
const maxRetries = 3;
|
|
1250
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1251
|
+
try {
|
|
1252
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1253
|
+
if (!existingResource) {
|
|
1254
|
+
const newResource = {
|
|
1255
|
+
id: resourceId,
|
|
1256
|
+
workingMemory,
|
|
1257
|
+
metadata: metadata || {},
|
|
1258
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1259
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1260
|
+
};
|
|
1261
|
+
return this.saveResource({ resource: newResource });
|
|
1262
|
+
}
|
|
1263
|
+
const updatedResource = {
|
|
1264
|
+
...existingResource,
|
|
1265
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1266
|
+
metadata: {
|
|
1267
|
+
...existingResource.metadata,
|
|
1268
|
+
...metadata
|
|
1269
|
+
},
|
|
1270
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1271
|
+
};
|
|
1272
|
+
const record = {
|
|
1273
|
+
id: resourceId,
|
|
1274
|
+
workingMemory: updatedResource.workingMemory || "",
|
|
1275
|
+
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
1276
|
+
updatedAt: updatedResource.updatedAt.getTime()
|
|
1277
|
+
// Store as timestamp (milliseconds)
|
|
1278
|
+
};
|
|
1279
|
+
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
1280
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1281
|
+
return updatedResource;
|
|
1282
|
+
} catch (error$1) {
|
|
1283
|
+
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
1284
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
1285
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
throw new error.MastraError(
|
|
1289
|
+
{
|
|
1290
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_RESOURCE", "FAILED"),
|
|
1291
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1292
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1293
|
+
},
|
|
1294
|
+
error$1
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
throw new Error("Unexpected end of retry loop");
|
|
1299
|
+
}
|
|
1234
1300
|
};
|
|
1235
1301
|
var StoreScoresLance = class extends storage.ScoresStorage {
|
|
1236
1302
|
client;
|
|
1237
|
-
|
|
1303
|
+
#db;
|
|
1304
|
+
constructor(config) {
|
|
1238
1305
|
super();
|
|
1306
|
+
const client = resolveLanceConfig(config);
|
|
1239
1307
|
this.client = client;
|
|
1308
|
+
this.#db = new LanceDB({ client });
|
|
1309
|
+
}
|
|
1310
|
+
async init() {
|
|
1311
|
+
await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.SCORERS_SCHEMA });
|
|
1312
|
+
await this.#db.alterTable({
|
|
1313
|
+
tableName: storage.TABLE_SCORERS,
|
|
1314
|
+
schema: storage.SCORERS_SCHEMA,
|
|
1315
|
+
ifNotExists: ["spanId", "requestContext"]
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
async dangerouslyClearAll() {
|
|
1319
|
+
await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
|
|
1240
1320
|
}
|
|
1241
1321
|
async saveScore(score) {
|
|
1242
1322
|
let validatedScore;
|
|
@@ -1250,7 +1330,7 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1250
1330
|
domain: error.ErrorDomain.STORAGE,
|
|
1251
1331
|
category: error.ErrorCategory.USER,
|
|
1252
1332
|
details: {
|
|
1253
|
-
scorer: score.scorer?.id ?? "unknown",
|
|
1333
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
1254
1334
|
entityId: score.entityId ?? "unknown",
|
|
1255
1335
|
entityType: score.entityType ?? "unknown",
|
|
1256
1336
|
traceId: score.traceId ?? "",
|
|
@@ -1520,6 +1600,9 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1520
1600
|
}
|
|
1521
1601
|
}
|
|
1522
1602
|
};
|
|
1603
|
+
function escapeSql(str) {
|
|
1604
|
+
return str.replace(/'/g, "''");
|
|
1605
|
+
}
|
|
1523
1606
|
function parseWorkflowRun(row) {
|
|
1524
1607
|
let parsedSnapshot = row.snapshot;
|
|
1525
1608
|
if (typeof parsedSnapshot === "string") {
|
|
@@ -1540,42 +1623,88 @@ function parseWorkflowRun(row) {
|
|
|
1540
1623
|
}
|
|
1541
1624
|
var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
1542
1625
|
client;
|
|
1543
|
-
|
|
1626
|
+
#db;
|
|
1627
|
+
constructor(config) {
|
|
1544
1628
|
super();
|
|
1629
|
+
const client = resolveLanceConfig(config);
|
|
1545
1630
|
this.client = client;
|
|
1631
|
+
this.#db = new LanceDB({ client });
|
|
1632
|
+
}
|
|
1633
|
+
async init() {
|
|
1634
|
+
const schema = storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
1635
|
+
await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema });
|
|
1636
|
+
await this.#db.alterTable({
|
|
1637
|
+
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1638
|
+
schema,
|
|
1639
|
+
ifNotExists: ["resourceId"]
|
|
1640
|
+
});
|
|
1546
1641
|
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1642
|
+
async dangerouslyClearAll() {
|
|
1643
|
+
await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
1644
|
+
}
|
|
1645
|
+
async updateWorkflowResults({
|
|
1646
|
+
workflowName,
|
|
1647
|
+
runId,
|
|
1648
|
+
stepId,
|
|
1649
|
+
result,
|
|
1650
|
+
requestContext
|
|
1553
1651
|
}) {
|
|
1554
|
-
|
|
1652
|
+
let snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
1653
|
+
if (!snapshot) {
|
|
1654
|
+
snapshot = {
|
|
1655
|
+
context: {},
|
|
1656
|
+
activePaths: [],
|
|
1657
|
+
timestamp: Date.now(),
|
|
1658
|
+
suspendedPaths: {},
|
|
1659
|
+
activeStepsPath: {},
|
|
1660
|
+
resumeLabels: {},
|
|
1661
|
+
serializedStepGraph: [],
|
|
1662
|
+
status: "pending",
|
|
1663
|
+
value: {},
|
|
1664
|
+
waitingPaths: {},
|
|
1665
|
+
runId,
|
|
1666
|
+
requestContext: {}
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
snapshot.context[stepId] = result;
|
|
1670
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
1671
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
1672
|
+
return snapshot.context;
|
|
1555
1673
|
}
|
|
1556
|
-
updateWorkflowState({
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1674
|
+
async updateWorkflowState({
|
|
1675
|
+
workflowName,
|
|
1676
|
+
runId,
|
|
1677
|
+
opts
|
|
1560
1678
|
}) {
|
|
1561
|
-
|
|
1679
|
+
const snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
1680
|
+
if (!snapshot) {
|
|
1681
|
+
return void 0;
|
|
1682
|
+
}
|
|
1683
|
+
if (!snapshot.context) {
|
|
1684
|
+
throw new Error(`Snapshot not found for runId ${runId}`);
|
|
1685
|
+
}
|
|
1686
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
1687
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
|
|
1688
|
+
return updatedSnapshot;
|
|
1562
1689
|
}
|
|
1563
1690
|
async persistWorkflowSnapshot({
|
|
1564
1691
|
workflowName,
|
|
1565
1692
|
runId,
|
|
1566
1693
|
resourceId,
|
|
1567
|
-
snapshot
|
|
1694
|
+
snapshot,
|
|
1695
|
+
createdAt,
|
|
1696
|
+
updatedAt
|
|
1568
1697
|
}) {
|
|
1569
1698
|
try {
|
|
1570
1699
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1571
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1700
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1572
1701
|
const records = await query.toArray();
|
|
1573
|
-
let
|
|
1574
|
-
const now = Date.now();
|
|
1702
|
+
let createdAtValue;
|
|
1703
|
+
const now = createdAt?.getTime() ?? Date.now();
|
|
1575
1704
|
if (records.length > 0) {
|
|
1576
|
-
|
|
1705
|
+
createdAtValue = records[0].createdAt ?? now;
|
|
1577
1706
|
} else {
|
|
1578
|
-
|
|
1707
|
+
createdAtValue = now;
|
|
1579
1708
|
}
|
|
1580
1709
|
const { status, value, ...rest } = snapshot;
|
|
1581
1710
|
const record = {
|
|
@@ -1584,8 +1713,8 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1584
1713
|
resourceId,
|
|
1585
1714
|
snapshot: JSON.stringify({ status, value, ...rest }),
|
|
1586
1715
|
// this is to ensure status is always just before value, for when querying the db by status
|
|
1587
|
-
createdAt,
|
|
1588
|
-
updatedAt: now
|
|
1716
|
+
createdAt: createdAtValue,
|
|
1717
|
+
updatedAt: updatedAt ?? now
|
|
1589
1718
|
};
|
|
1590
1719
|
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1591
1720
|
} catch (error$1) {
|
|
@@ -1606,7 +1735,7 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1606
1735
|
}) {
|
|
1607
1736
|
try {
|
|
1608
1737
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1609
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1738
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1610
1739
|
const records = await query.toArray();
|
|
1611
1740
|
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1612
1741
|
} catch (error$1) {
|
|
@@ -1624,9 +1753,9 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1624
1753
|
async getWorkflowRunById(args) {
|
|
1625
1754
|
try {
|
|
1626
1755
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1627
|
-
let whereClause = `run_id = '${args.runId}'`;
|
|
1756
|
+
let whereClause = `run_id = '${escapeSql(args.runId)}'`;
|
|
1628
1757
|
if (args.workflowName) {
|
|
1629
|
-
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
1758
|
+
whereClause += ` AND workflow_name = '${escapeSql(args.workflowName)}'`;
|
|
1630
1759
|
}
|
|
1631
1760
|
const query = table.query().where(whereClause);
|
|
1632
1761
|
const records = await query.toArray();
|
|
@@ -1648,7 +1777,7 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1648
1777
|
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
1649
1778
|
try {
|
|
1650
1779
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1651
|
-
const whereClause = `run_id = '${runId
|
|
1780
|
+
const whereClause = `run_id = '${escapeSql(runId)}' AND workflow_name = '${escapeSql(workflowName)}'`;
|
|
1652
1781
|
await table.delete(whereClause);
|
|
1653
1782
|
} catch (error$1) {
|
|
1654
1783
|
throw new error.MastraError(
|
|
@@ -1668,14 +1797,14 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1668
1797
|
let query = table.query();
|
|
1669
1798
|
const conditions = [];
|
|
1670
1799
|
if (args?.workflowName) {
|
|
1671
|
-
conditions.push(`workflow_name = '${args.workflowName
|
|
1800
|
+
conditions.push(`workflow_name = '${escapeSql(args.workflowName)}'`);
|
|
1672
1801
|
}
|
|
1673
1802
|
if (args?.status) {
|
|
1674
1803
|
const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
1675
1804
|
conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
|
|
1676
1805
|
}
|
|
1677
1806
|
if (args?.resourceId) {
|
|
1678
|
-
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1807
|
+
conditions.push(`\`resourceId\` = '${escapeSql(args.resourceId)}'`);
|
|
1679
1808
|
}
|
|
1680
1809
|
if (args?.fromDate instanceof Date) {
|
|
1681
1810
|
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
@@ -1764,12 +1893,10 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
|
|
|
1764
1893
|
const instance = new _LanceStorage(id, name, storageOptions?.disableInit);
|
|
1765
1894
|
try {
|
|
1766
1895
|
instance.lanceClient = await lancedb.connect(uri, connectionOptions);
|
|
1767
|
-
const operations = new StoreOperationsLance({ client: instance.lanceClient });
|
|
1768
1896
|
instance.stores = {
|
|
1769
|
-
operations: new StoreOperationsLance({ client: instance.lanceClient }),
|
|
1770
1897
|
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1771
1898
|
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1772
|
-
memory: new StoreMemoryLance({ client: instance.lanceClient
|
|
1899
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient })
|
|
1773
1900
|
};
|
|
1774
1901
|
return instance;
|
|
1775
1902
|
} catch (e) {
|
|
@@ -1786,221 +1913,43 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
|
|
|
1786
1913
|
}
|
|
1787
1914
|
}
|
|
1788
1915
|
/**
|
|
1789
|
-
*
|
|
1790
|
-
*
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
}
|
|
1808
|
-
async dropTable({ tableName }) {
|
|
1809
|
-
return this.stores.operations.dropTable({ tableName });
|
|
1810
|
-
}
|
|
1811
|
-
async alterTable({
|
|
1812
|
-
tableName,
|
|
1813
|
-
schema,
|
|
1814
|
-
ifNotExists
|
|
1815
|
-
}) {
|
|
1816
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
1817
|
-
}
|
|
1818
|
-
async clearTable({ tableName }) {
|
|
1819
|
-
return this.stores.operations.clearTable({ tableName });
|
|
1820
|
-
}
|
|
1821
|
-
async insert({ tableName, record }) {
|
|
1822
|
-
return this.stores.operations.insert({ tableName, record });
|
|
1823
|
-
}
|
|
1824
|
-
async batchInsert({ tableName, records }) {
|
|
1825
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
1826
|
-
}
|
|
1827
|
-
async load({ tableName, keys }) {
|
|
1828
|
-
return this.stores.operations.load({ tableName, keys });
|
|
1829
|
-
}
|
|
1830
|
-
async getThreadById({ threadId }) {
|
|
1831
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
1832
|
-
}
|
|
1833
|
-
/**
|
|
1834
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
1835
|
-
* @param thread - The thread to save
|
|
1836
|
-
* @returns The saved thread
|
|
1916
|
+
* Creates a new instance of LanceStorage from a pre-configured LanceDB connection.
|
|
1917
|
+
* Use this when you need to configure the connection before initialization.
|
|
1918
|
+
*
|
|
1919
|
+
* @param id The unique identifier for this storage instance
|
|
1920
|
+
* @param name The name for this storage instance
|
|
1921
|
+
* @param client Pre-configured LanceDB connection
|
|
1922
|
+
* @param options Storage options including disableInit
|
|
1923
|
+
*
|
|
1924
|
+
* @example
|
|
1925
|
+
* ```typescript
|
|
1926
|
+
* import { connect } from '@lancedb/lancedb';
|
|
1927
|
+
*
|
|
1928
|
+
* const client = await connect('/path/to/db', {
|
|
1929
|
+
* // Custom connection options
|
|
1930
|
+
* });
|
|
1931
|
+
*
|
|
1932
|
+
* const store = LanceStorage.fromClient('my-id', 'MyStorage', client);
|
|
1933
|
+
* ```
|
|
1837
1934
|
*/
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
}) {
|
|
1846
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
1847
|
-
}
|
|
1848
|
-
async deleteThread({ threadId }) {
|
|
1849
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
1850
|
-
}
|
|
1851
|
-
get supports() {
|
|
1852
|
-
return {
|
|
1853
|
-
selectByIncludeResourceScope: true,
|
|
1854
|
-
resourceWorkingMemory: true,
|
|
1855
|
-
hasColumn: true,
|
|
1856
|
-
createTable: true,
|
|
1857
|
-
deleteMessages: false,
|
|
1858
|
-
listScoresBySpan: true
|
|
1935
|
+
static fromClient(id, name, client, options) {
|
|
1936
|
+
const instance = new _LanceStorage(id, name, options?.disableInit);
|
|
1937
|
+
instance.lanceClient = client;
|
|
1938
|
+
instance.stores = {
|
|
1939
|
+
workflows: new StoreWorkflowsLance({ client }),
|
|
1940
|
+
scores: new StoreScoresLance({ client }),
|
|
1941
|
+
memory: new StoreMemoryLance({ client })
|
|
1859
1942
|
};
|
|
1860
|
-
|
|
1861
|
-
async getResourceById({ resourceId }) {
|
|
1862
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
1863
|
-
}
|
|
1864
|
-
async saveResource({ resource }) {
|
|
1865
|
-
return this.stores.memory.saveResource({ resource });
|
|
1866
|
-
}
|
|
1867
|
-
async updateResource({
|
|
1868
|
-
resourceId,
|
|
1869
|
-
workingMemory,
|
|
1870
|
-
metadata
|
|
1871
|
-
}) {
|
|
1872
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
1943
|
+
return instance;
|
|
1873
1944
|
}
|
|
1874
1945
|
/**
|
|
1875
|
-
*
|
|
1876
|
-
*
|
|
1877
|
-
*
|
|
1878
|
-
* @returns The processed array with context messages included
|
|
1946
|
+
* @internal
|
|
1947
|
+
* Private constructor to enforce using the create factory method.
|
|
1948
|
+
* Note: stores is initialized in create() after the lanceClient is connected.
|
|
1879
1949
|
*/
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
return records;
|
|
1884
|
-
}
|
|
1885
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1886
|
-
records.forEach((message, index) => {
|
|
1887
|
-
messageIndexMap.set(message.id, index);
|
|
1888
|
-
});
|
|
1889
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
1890
|
-
for (const item of messagesWithContext) {
|
|
1891
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
1892
|
-
if (messageIndex !== void 0) {
|
|
1893
|
-
if (item.withPreviousMessages) {
|
|
1894
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
1895
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
1896
|
-
additionalIndices.add(i);
|
|
1897
|
-
}
|
|
1898
|
-
}
|
|
1899
|
-
if (item.withNextMessages) {
|
|
1900
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
1901
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
1902
|
-
additionalIndices.add(i);
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
if (additionalIndices.size === 0) {
|
|
1908
|
-
return records;
|
|
1909
|
-
}
|
|
1910
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1911
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
1912
|
-
records.forEach((record, index) => {
|
|
1913
|
-
if (originalMatchIds.has(record.id)) {
|
|
1914
|
-
allIndices.add(index);
|
|
1915
|
-
}
|
|
1916
|
-
});
|
|
1917
|
-
additionalIndices.forEach((index) => {
|
|
1918
|
-
allIndices.add(index);
|
|
1919
|
-
});
|
|
1920
|
-
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
1921
|
-
}
|
|
1922
|
-
async listMessagesById({ messageIds }) {
|
|
1923
|
-
return this.stores.memory.listMessagesById({ messageIds });
|
|
1924
|
-
}
|
|
1925
|
-
async saveMessages(args) {
|
|
1926
|
-
return this.stores.memory.saveMessages(args);
|
|
1927
|
-
}
|
|
1928
|
-
async updateMessages(_args) {
|
|
1929
|
-
return this.stores.memory.updateMessages(_args);
|
|
1930
|
-
}
|
|
1931
|
-
async listWorkflowRuns(args) {
|
|
1932
|
-
return this.stores.workflows.listWorkflowRuns(args);
|
|
1933
|
-
}
|
|
1934
|
-
async getWorkflowRunById(args) {
|
|
1935
|
-
return this.stores.workflows.getWorkflowRunById(args);
|
|
1936
|
-
}
|
|
1937
|
-
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
1938
|
-
return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
|
|
1939
|
-
}
|
|
1940
|
-
async updateWorkflowResults({
|
|
1941
|
-
workflowName,
|
|
1942
|
-
runId,
|
|
1943
|
-
stepId,
|
|
1944
|
-
result,
|
|
1945
|
-
requestContext
|
|
1946
|
-
}) {
|
|
1947
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
1948
|
-
}
|
|
1949
|
-
async updateWorkflowState({
|
|
1950
|
-
workflowName,
|
|
1951
|
-
runId,
|
|
1952
|
-
opts
|
|
1953
|
-
}) {
|
|
1954
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
1955
|
-
}
|
|
1956
|
-
async persistWorkflowSnapshot({
|
|
1957
|
-
workflowName,
|
|
1958
|
-
runId,
|
|
1959
|
-
resourceId,
|
|
1960
|
-
snapshot
|
|
1961
|
-
}) {
|
|
1962
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
1963
|
-
}
|
|
1964
|
-
async loadWorkflowSnapshot({
|
|
1965
|
-
workflowName,
|
|
1966
|
-
runId
|
|
1967
|
-
}) {
|
|
1968
|
-
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
1969
|
-
}
|
|
1970
|
-
async getScoreById({ id: _id }) {
|
|
1971
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
1972
|
-
}
|
|
1973
|
-
async listScoresByScorerId({
|
|
1974
|
-
scorerId,
|
|
1975
|
-
source,
|
|
1976
|
-
entityId,
|
|
1977
|
-
entityType,
|
|
1978
|
-
pagination
|
|
1979
|
-
}) {
|
|
1980
|
-
return this.stores.scores.listScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
|
|
1981
|
-
}
|
|
1982
|
-
async saveScore(score) {
|
|
1983
|
-
return this.stores.scores.saveScore(score);
|
|
1984
|
-
}
|
|
1985
|
-
async listScoresByRunId({
|
|
1986
|
-
runId,
|
|
1987
|
-
pagination
|
|
1988
|
-
}) {
|
|
1989
|
-
return this.stores.scores.listScoresByRunId({ runId, pagination });
|
|
1990
|
-
}
|
|
1991
|
-
async listScoresByEntityId({
|
|
1992
|
-
entityId,
|
|
1993
|
-
entityType,
|
|
1994
|
-
pagination
|
|
1995
|
-
}) {
|
|
1996
|
-
return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
|
|
1997
|
-
}
|
|
1998
|
-
async listScoresBySpan({
|
|
1999
|
-
traceId,
|
|
2000
|
-
spanId,
|
|
2001
|
-
pagination
|
|
2002
|
-
}) {
|
|
2003
|
-
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
1950
|
+
constructor(id, name, disableInit) {
|
|
1951
|
+
super({ id, name, disableInit });
|
|
1952
|
+
this.stores = {};
|
|
2004
1953
|
}
|
|
2005
1954
|
};
|
|
2006
1955
|
var LanceFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
@@ -3225,5 +3174,8 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3225
3174
|
|
|
3226
3175
|
exports.LanceStorage = LanceStorage;
|
|
3227
3176
|
exports.LanceVectorStore = LanceVectorStore;
|
|
3177
|
+
exports.StoreMemoryLance = StoreMemoryLance;
|
|
3178
|
+
exports.StoreScoresLance = StoreScoresLance;
|
|
3179
|
+
exports.StoreWorkflowsLance = StoreWorkflowsLance;
|
|
3228
3180
|
//# sourceMappingURL=index.cjs.map
|
|
3229
3181
|
//# sourceMappingURL=index.cjs.map
|