@mastra/lance 0.0.0-share-agent-metadata-with-cloud-20250718123411 → 0.0.0-span-scorring-test-20251124132129
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 +948 -2
- package/README.md +64 -7
- package/dist/index.cjs +1657 -695
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1658 -696
- package/dist/index.js.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +79 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +40 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +50 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +10 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +50 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +211 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/vector/filter.d.ts +41 -0
- package/dist/vector/filter.d.ts.map +1 -0
- package/dist/vector/index.d.ts +88 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/types.d.ts +15 -0
- package/dist/vector/types.d.ts.map +1 -0
- package/package.json +31 -12
- package/dist/_tsup-dts-rollup.d.cts +0 -409
- package/dist/_tsup-dts-rollup.d.ts +0 -409
- package/dist/index.d.cts +0 -2
- package/eslint.config.js +0 -6
- package/src/index.ts +0 -2
- package/src/storage/index.test.ts +0 -1336
- package/src/storage/index.ts +0 -1447
- package/src/vector/filter.test.ts +0 -295
- package/src/vector/filter.ts +0 -443
- package/src/vector/index.test.ts +0 -1493
- package/src/vector/index.ts +0 -941
- package/src/vector/types.ts +0 -16
- package/tsconfig.json +0 -5
- package/vitest.config.ts +0 -11
package/dist/index.js
CHANGED
|
@@ -1,110 +1,857 @@
|
|
|
1
1
|
import { connect, Index } from '@lancedb/lancedb';
|
|
2
|
-
import { MessageList } from '@mastra/core/agent';
|
|
3
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
4
|
-
import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES,
|
|
3
|
+
import { MastraStorage, StoreOperations, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, normalizePerPage, calculatePagination, TABLE_RESOURCES, ScoresStorage, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ensureDate } from '@mastra/core/storage';
|
|
4
|
+
import { MessageList } from '@mastra/core/agent';
|
|
5
5
|
import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
|
|
6
|
+
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
6
7
|
import { MastraVector } from '@mastra/core/vector';
|
|
7
8
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
8
9
|
|
|
9
10
|
// src/storage/index.ts
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
function getPrimaryKeys(tableName) {
|
|
12
|
+
let primaryId = ["id"];
|
|
13
|
+
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
14
|
+
primaryId = ["workflow_name", "run_id"];
|
|
15
|
+
}
|
|
16
|
+
return primaryId;
|
|
17
|
+
}
|
|
18
|
+
function validateKeyTypes(keys, tableSchema) {
|
|
19
|
+
const fieldTypes = new Map(
|
|
20
|
+
tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
|
|
21
|
+
);
|
|
22
|
+
for (const [key, value] of Object.entries(keys)) {
|
|
23
|
+
const fieldType = fieldTypes.get(key);
|
|
24
|
+
if (!fieldType) {
|
|
25
|
+
throw new Error(`Field '${key}' does not exist in table schema`);
|
|
26
|
+
}
|
|
27
|
+
if (value !== null) {
|
|
28
|
+
if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
|
|
29
|
+
throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
|
|
30
|
+
}
|
|
31
|
+
if (fieldType.includes("utf8") && typeof value !== "string") {
|
|
32
|
+
throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
|
|
33
|
+
}
|
|
34
|
+
if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
|
|
35
|
+
throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function processResultWithTypeConversion(rawResult, tableSchema) {
|
|
41
|
+
const fieldTypeMap = /* @__PURE__ */ new Map();
|
|
42
|
+
tableSchema.fields.forEach((field) => {
|
|
43
|
+
const fieldName = field.name;
|
|
44
|
+
const fieldTypeStr = field.type.toString().toLowerCase();
|
|
45
|
+
fieldTypeMap.set(fieldName, fieldTypeStr);
|
|
46
|
+
});
|
|
47
|
+
if (Array.isArray(rawResult)) {
|
|
48
|
+
return rawResult.map((item) => processResultWithTypeConversion(item, tableSchema));
|
|
49
|
+
}
|
|
50
|
+
const processedResult = { ...rawResult };
|
|
51
|
+
for (const key in processedResult) {
|
|
52
|
+
const fieldTypeStr = fieldTypeMap.get(key);
|
|
53
|
+
if (!fieldTypeStr) continue;
|
|
54
|
+
if (typeof processedResult[key] === "string") {
|
|
55
|
+
if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
|
|
56
|
+
if (!isNaN(Number(processedResult[key]))) {
|
|
57
|
+
processedResult[key] = Number(processedResult[key]);
|
|
58
|
+
}
|
|
59
|
+
} else if (fieldTypeStr.includes("int64")) {
|
|
60
|
+
processedResult[key] = Number(processedResult[key]);
|
|
61
|
+
} else if (fieldTypeStr.includes("utf8") && key !== "id") {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = JSON.parse(processedResult[key]);
|
|
64
|
+
if (typeof parsed === "object") {
|
|
65
|
+
processedResult[key] = JSON.parse(processedResult[key]);
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} else if (typeof processedResult[key] === "bigint") {
|
|
71
|
+
processedResult[key] = Number(processedResult[key]);
|
|
72
|
+
} else if (fieldTypeStr.includes("float64") && ["createdAt", "updatedAt"].includes(key)) {
|
|
73
|
+
processedResult[key] = new Date(processedResult[key]);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return processedResult;
|
|
77
|
+
}
|
|
78
|
+
async function getTableSchema({
|
|
79
|
+
tableName,
|
|
80
|
+
client
|
|
81
|
+
}) {
|
|
82
|
+
try {
|
|
83
|
+
if (!client) {
|
|
84
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
85
|
+
}
|
|
86
|
+
if (!tableName) {
|
|
87
|
+
throw new Error("tableName is required for getTableSchema.");
|
|
88
|
+
}
|
|
89
|
+
} catch (validationError) {
|
|
90
|
+
throw new MastraError(
|
|
91
|
+
{
|
|
92
|
+
id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS",
|
|
93
|
+
domain: ErrorDomain.STORAGE,
|
|
94
|
+
category: ErrorCategory.USER,
|
|
95
|
+
text: validationError.message,
|
|
96
|
+
details: { tableName }
|
|
97
|
+
},
|
|
98
|
+
validationError
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const table = await client.openTable(tableName);
|
|
103
|
+
const rawSchema = await table.schema();
|
|
104
|
+
const fields = rawSchema.fields;
|
|
105
|
+
return {
|
|
106
|
+
fields,
|
|
107
|
+
metadata: /* @__PURE__ */ new Map(),
|
|
108
|
+
get names() {
|
|
109
|
+
return fields.map((field) => field.name);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new MastraError(
|
|
114
|
+
{
|
|
115
|
+
id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED",
|
|
116
|
+
domain: ErrorDomain.STORAGE,
|
|
117
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
118
|
+
details: { tableName }
|
|
119
|
+
},
|
|
120
|
+
error
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/storage/domains/memory/index.ts
|
|
126
|
+
var StoreMemoryLance = class extends MemoryStorage {
|
|
127
|
+
client;
|
|
128
|
+
operations;
|
|
129
|
+
constructor({ client, operations }) {
|
|
130
|
+
super();
|
|
131
|
+
this.client = client;
|
|
132
|
+
this.operations = operations;
|
|
133
|
+
}
|
|
134
|
+
// Utility to escape single quotes in SQL strings
|
|
135
|
+
escapeSql(str) {
|
|
136
|
+
return str.replace(/'/g, "''");
|
|
137
|
+
}
|
|
138
|
+
async getThreadById({ threadId }) {
|
|
139
|
+
try {
|
|
140
|
+
const thread = await this.operations.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
|
|
141
|
+
if (!thread) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
...thread,
|
|
146
|
+
createdAt: new Date(thread.createdAt),
|
|
147
|
+
updatedAt: new Date(thread.updatedAt)
|
|
148
|
+
};
|
|
149
|
+
} catch (error) {
|
|
150
|
+
throw new MastraError(
|
|
151
|
+
{
|
|
152
|
+
id: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
|
|
153
|
+
domain: ErrorDomain.STORAGE,
|
|
154
|
+
category: ErrorCategory.THIRD_PARTY
|
|
155
|
+
},
|
|
156
|
+
error
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
12
160
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param
|
|
15
|
-
* @
|
|
16
|
-
*
|
|
17
|
-
* Usage:
|
|
18
|
-
*
|
|
19
|
-
* Connect to a local database
|
|
20
|
-
* ```ts
|
|
21
|
-
* const store = await LanceStorage.create('/path/to/db');
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* Connect to a LanceDB cloud database
|
|
25
|
-
* ```ts
|
|
26
|
-
* const store = await LanceStorage.create('db://host:port');
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* Connect to a cloud database
|
|
30
|
-
* ```ts
|
|
31
|
-
* const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
32
|
-
* ```
|
|
161
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
162
|
+
* @param thread - The thread to save
|
|
163
|
+
* @returns The saved thread
|
|
33
164
|
*/
|
|
34
|
-
|
|
35
|
-
const instance = new _LanceStorage(name);
|
|
165
|
+
async saveThread({ thread }) {
|
|
36
166
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
167
|
+
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
168
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
169
|
+
await table.add([record], { mode: "append" });
|
|
170
|
+
return thread;
|
|
171
|
+
} catch (error) {
|
|
40
172
|
throw new MastraError(
|
|
41
173
|
{
|
|
42
|
-
id: "
|
|
174
|
+
id: "LANCE_STORE_SAVE_THREAD_FAILED",
|
|
175
|
+
domain: ErrorDomain.STORAGE,
|
|
176
|
+
category: ErrorCategory.THIRD_PARTY
|
|
177
|
+
},
|
|
178
|
+
error
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async updateThread({
|
|
183
|
+
id,
|
|
184
|
+
title,
|
|
185
|
+
metadata
|
|
186
|
+
}) {
|
|
187
|
+
const maxRetries = 5;
|
|
188
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
189
|
+
try {
|
|
190
|
+
const current = await this.getThreadById({ threadId: id });
|
|
191
|
+
if (!current) {
|
|
192
|
+
throw new Error(`Thread with id ${id} not found`);
|
|
193
|
+
}
|
|
194
|
+
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
195
|
+
const record = {
|
|
196
|
+
id,
|
|
197
|
+
title,
|
|
198
|
+
metadata: JSON.stringify(mergedMetadata),
|
|
199
|
+
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
200
|
+
};
|
|
201
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
202
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
203
|
+
const updatedThread = await this.getThreadById({ threadId: id });
|
|
204
|
+
if (!updatedThread) {
|
|
205
|
+
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
206
|
+
}
|
|
207
|
+
return updatedThread;
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
210
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
211
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
throw new MastraError(
|
|
215
|
+
{
|
|
216
|
+
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
217
|
+
domain: ErrorDomain.STORAGE,
|
|
218
|
+
category: ErrorCategory.THIRD_PARTY
|
|
219
|
+
},
|
|
220
|
+
error
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
throw new MastraError(
|
|
225
|
+
{
|
|
226
|
+
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
227
|
+
domain: ErrorDomain.STORAGE,
|
|
228
|
+
category: ErrorCategory.THIRD_PARTY
|
|
229
|
+
},
|
|
230
|
+
new Error("All retries exhausted")
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
async deleteThread({ threadId }) {
|
|
234
|
+
try {
|
|
235
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
236
|
+
await table.delete(`id = '${threadId}'`);
|
|
237
|
+
const messagesTable = await this.client.openTable(TABLE_MESSAGES);
|
|
238
|
+
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
throw new MastraError(
|
|
241
|
+
{
|
|
242
|
+
id: "LANCE_STORE_DELETE_THREAD_FAILED",
|
|
243
|
+
domain: ErrorDomain.STORAGE,
|
|
244
|
+
category: ErrorCategory.THIRD_PARTY
|
|
245
|
+
},
|
|
246
|
+
error
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
normalizeMessage(message) {
|
|
251
|
+
const { thread_id, ...rest } = message;
|
|
252
|
+
return {
|
|
253
|
+
...rest,
|
|
254
|
+
threadId: thread_id,
|
|
255
|
+
content: typeof message.content === "string" ? (() => {
|
|
256
|
+
try {
|
|
257
|
+
return JSON.parse(message.content);
|
|
258
|
+
} catch {
|
|
259
|
+
return message.content;
|
|
260
|
+
}
|
|
261
|
+
})() : message.content
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
async listMessagesById({ messageIds }) {
|
|
265
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
266
|
+
try {
|
|
267
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
268
|
+
const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
|
|
269
|
+
const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
|
|
270
|
+
const messages = processResultWithTypeConversion(
|
|
271
|
+
allRecords,
|
|
272
|
+
await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
|
|
273
|
+
);
|
|
274
|
+
const list = new MessageList().add(
|
|
275
|
+
messages.map(this.normalizeMessage),
|
|
276
|
+
"memory"
|
|
277
|
+
);
|
|
278
|
+
return { messages: list.get.all.db() };
|
|
279
|
+
} catch (error) {
|
|
280
|
+
throw new MastraError(
|
|
281
|
+
{
|
|
282
|
+
id: "LANCE_STORE_LIST_MESSAGES_BY_ID_FAILED",
|
|
43
283
|
domain: ErrorDomain.STORAGE,
|
|
44
284
|
category: ErrorCategory.THIRD_PARTY,
|
|
45
|
-
|
|
46
|
-
|
|
285
|
+
details: {
|
|
286
|
+
messageIds: JSON.stringify(messageIds)
|
|
287
|
+
}
|
|
47
288
|
},
|
|
48
|
-
|
|
289
|
+
error
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
async listMessages(args) {
|
|
294
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
295
|
+
if (!threadId.trim()) {
|
|
296
|
+
throw new MastraError(
|
|
297
|
+
{
|
|
298
|
+
id: "STORAGE_LANCE_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
299
|
+
domain: ErrorDomain.STORAGE,
|
|
300
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
301
|
+
details: { threadId }
|
|
302
|
+
},
|
|
303
|
+
new Error("threadId must be a non-empty string")
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
const perPage = normalizePerPage(perPageInput, 40);
|
|
307
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
308
|
+
try {
|
|
309
|
+
if (page < 0) {
|
|
310
|
+
throw new MastraError(
|
|
311
|
+
{
|
|
312
|
+
id: "STORAGE_LANCE_LIST_MESSAGES_INVALID_PAGE",
|
|
313
|
+
domain: ErrorDomain.STORAGE,
|
|
314
|
+
category: ErrorCategory.USER,
|
|
315
|
+
details: { page }
|
|
316
|
+
},
|
|
317
|
+
new Error("page must be >= 0")
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
321
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
322
|
+
const conditions = [`thread_id = '${this.escapeSql(threadId)}'`];
|
|
323
|
+
if (resourceId) {
|
|
324
|
+
conditions.push(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
325
|
+
}
|
|
326
|
+
if (filter?.dateRange?.start) {
|
|
327
|
+
const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
|
|
328
|
+
conditions.push(`\`createdAt\` >= ${startTime}`);
|
|
329
|
+
}
|
|
330
|
+
if (filter?.dateRange?.end) {
|
|
331
|
+
const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
|
|
332
|
+
conditions.push(`\`createdAt\` <= ${endTime}`);
|
|
333
|
+
}
|
|
334
|
+
const whereClause = conditions.join(" AND ");
|
|
335
|
+
const total = await table.countRows(whereClause);
|
|
336
|
+
const query = table.query().where(whereClause);
|
|
337
|
+
let allRecords = await query.toArray();
|
|
338
|
+
allRecords.sort((a, b) => {
|
|
339
|
+
const aValue = field === "createdAt" ? a.createdAt : a[field];
|
|
340
|
+
const bValue = field === "createdAt" ? b.createdAt : b[field];
|
|
341
|
+
if (aValue == null && bValue == null) return 0;
|
|
342
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
343
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
344
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
345
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
346
|
+
}
|
|
347
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
348
|
+
});
|
|
349
|
+
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
350
|
+
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
351
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
352
|
+
return {
|
|
353
|
+
messages: [],
|
|
354
|
+
total: 0,
|
|
355
|
+
page,
|
|
356
|
+
perPage: perPageForResponse,
|
|
357
|
+
hasMore: false
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
361
|
+
if (include && include.length > 0) {
|
|
362
|
+
const threadIds = [...new Set(include.map((item) => item.threadId || threadId))];
|
|
363
|
+
const allThreadMessages = [];
|
|
364
|
+
for (const tid of threadIds) {
|
|
365
|
+
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
366
|
+
let threadRecords = await threadQuery.toArray();
|
|
367
|
+
allThreadMessages.push(...threadRecords);
|
|
368
|
+
}
|
|
369
|
+
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
370
|
+
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
371
|
+
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
372
|
+
for (const includeMsg of includedMessages) {
|
|
373
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
374
|
+
messages.push(includeMsg);
|
|
375
|
+
messageIds.add(includeMsg.id);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const list = new MessageList().add(messages, "memory");
|
|
380
|
+
let finalMessages = list.get.all.db();
|
|
381
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
382
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
383
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
384
|
+
if (aValue == null && bValue == null) return 0;
|
|
385
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
386
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
387
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
388
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
389
|
+
}
|
|
390
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
391
|
+
});
|
|
392
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
393
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
394
|
+
const fetchedAll = perPageInput === false || allThreadMessagesReturned;
|
|
395
|
+
const hasMore = !fetchedAll && offset + perPage < total;
|
|
396
|
+
return {
|
|
397
|
+
messages: finalMessages,
|
|
398
|
+
total,
|
|
399
|
+
page,
|
|
400
|
+
perPage: perPageForResponse,
|
|
401
|
+
hasMore
|
|
402
|
+
};
|
|
403
|
+
} catch (error) {
|
|
404
|
+
const mastraError = new MastraError(
|
|
405
|
+
{
|
|
406
|
+
id: "LANCE_STORE_LIST_MESSAGES_FAILED",
|
|
407
|
+
domain: ErrorDomain.STORAGE,
|
|
408
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
409
|
+
details: {
|
|
410
|
+
threadId,
|
|
411
|
+
resourceId: resourceId ?? ""
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
error
|
|
415
|
+
);
|
|
416
|
+
this.logger?.error?.(mastraError.toString());
|
|
417
|
+
this.logger?.trackException?.(mastraError);
|
|
418
|
+
return {
|
|
419
|
+
messages: [],
|
|
420
|
+
total: 0,
|
|
421
|
+
page,
|
|
422
|
+
perPage: perPageForResponse,
|
|
423
|
+
hasMore: false
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async saveMessages(args) {
|
|
428
|
+
try {
|
|
429
|
+
const { messages } = args;
|
|
430
|
+
if (messages.length === 0) {
|
|
431
|
+
return { messages: [] };
|
|
432
|
+
}
|
|
433
|
+
const threadId = messages[0]?.threadId;
|
|
434
|
+
if (!threadId) {
|
|
435
|
+
throw new Error("Thread ID is required");
|
|
436
|
+
}
|
|
437
|
+
for (const message of messages) {
|
|
438
|
+
if (!message.id) {
|
|
439
|
+
throw new Error("Message ID is required");
|
|
440
|
+
}
|
|
441
|
+
if (!message.threadId) {
|
|
442
|
+
throw new Error("Thread ID is required for all messages");
|
|
443
|
+
}
|
|
444
|
+
if (message.resourceId === null || message.resourceId === void 0) {
|
|
445
|
+
throw new Error("Resource ID cannot be null or undefined");
|
|
446
|
+
}
|
|
447
|
+
if (!message.content) {
|
|
448
|
+
throw new Error("Message content is required");
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
const transformedMessages = messages.map((message) => {
|
|
452
|
+
const { threadId: threadId2, type, ...rest } = message;
|
|
453
|
+
return {
|
|
454
|
+
...rest,
|
|
455
|
+
thread_id: threadId2,
|
|
456
|
+
type: type ?? "v2",
|
|
457
|
+
content: JSON.stringify(message.content)
|
|
458
|
+
};
|
|
459
|
+
});
|
|
460
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
461
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
462
|
+
const threadsTable = await this.client.openTable(TABLE_THREADS);
|
|
463
|
+
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
464
|
+
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
465
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
466
|
+
const list = new MessageList().add(messages, "memory");
|
|
467
|
+
return { messages: list.get.all.db() };
|
|
468
|
+
} catch (error) {
|
|
469
|
+
throw new MastraError(
|
|
470
|
+
{
|
|
471
|
+
id: "LANCE_STORE_SAVE_MESSAGES_FAILED",
|
|
472
|
+
domain: ErrorDomain.STORAGE,
|
|
473
|
+
category: ErrorCategory.THIRD_PARTY
|
|
474
|
+
},
|
|
475
|
+
error
|
|
49
476
|
);
|
|
50
477
|
}
|
|
51
478
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
479
|
+
async listThreadsByResourceId(args) {
|
|
480
|
+
try {
|
|
481
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
482
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
483
|
+
if (page < 0) {
|
|
484
|
+
throw new MastraError(
|
|
485
|
+
{
|
|
486
|
+
id: "STORAGE_LANCE_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
|
|
487
|
+
domain: ErrorDomain.STORAGE,
|
|
488
|
+
category: ErrorCategory.USER,
|
|
489
|
+
details: { page }
|
|
490
|
+
},
|
|
491
|
+
new Error("page must be >= 0")
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
495
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
496
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
497
|
+
const total = await table.countRows(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
498
|
+
const query = table.query().where(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
499
|
+
const records = await query.toArray();
|
|
500
|
+
records.sort((a, b) => {
|
|
501
|
+
const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
|
|
502
|
+
const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
|
|
503
|
+
if (aValue == null && bValue == null) return 0;
|
|
504
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
505
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
506
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
507
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
508
|
+
}
|
|
509
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
510
|
+
});
|
|
511
|
+
const paginatedRecords = records.slice(offset, offset + perPage);
|
|
512
|
+
const schema = await getTableSchema({ tableName: TABLE_THREADS, client: this.client });
|
|
513
|
+
const threads = paginatedRecords.map(
|
|
514
|
+
(record) => processResultWithTypeConversion(record, schema)
|
|
515
|
+
);
|
|
516
|
+
return {
|
|
517
|
+
threads,
|
|
518
|
+
total,
|
|
519
|
+
page,
|
|
520
|
+
perPage: perPageForResponse,
|
|
521
|
+
hasMore: offset + perPage < total
|
|
522
|
+
};
|
|
523
|
+
} catch (error) {
|
|
524
|
+
throw new MastraError(
|
|
525
|
+
{
|
|
526
|
+
id: "LANCE_STORE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
|
|
527
|
+
domain: ErrorDomain.STORAGE,
|
|
528
|
+
category: ErrorCategory.THIRD_PARTY
|
|
529
|
+
},
|
|
530
|
+
error
|
|
531
|
+
);
|
|
58
532
|
}
|
|
59
|
-
return primaryId;
|
|
60
533
|
}
|
|
61
534
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
535
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
536
|
+
* @param records - The sorted array of records to process
|
|
537
|
+
* @param include - The array of include specifications with context parameters
|
|
538
|
+
* @returns The processed array with context messages included
|
|
539
|
+
*/
|
|
540
|
+
processMessagesWithContext(records, include) {
|
|
541
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
542
|
+
if (messagesWithContext.length === 0) {
|
|
543
|
+
return records;
|
|
544
|
+
}
|
|
545
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
546
|
+
records.forEach((message, index) => {
|
|
547
|
+
messageIndexMap.set(message.id, index);
|
|
548
|
+
});
|
|
549
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
550
|
+
for (const item of messagesWithContext) {
|
|
551
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
552
|
+
if (messageIndex !== void 0) {
|
|
553
|
+
if (item.withPreviousMessages) {
|
|
554
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
555
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
556
|
+
additionalIndices.add(i);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (item.withNextMessages) {
|
|
560
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
561
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
562
|
+
additionalIndices.add(i);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (additionalIndices.size === 0) {
|
|
568
|
+
return records;
|
|
569
|
+
}
|
|
570
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
571
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
572
|
+
records.forEach((record, index) => {
|
|
573
|
+
if (originalMatchIds.has(record.id)) {
|
|
574
|
+
allIndices.add(index);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
additionalIndices.forEach((index) => {
|
|
578
|
+
allIndices.add(index);
|
|
579
|
+
});
|
|
580
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Parse message data from LanceDB record format to MastraDBMessage format
|
|
64
584
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
585
|
+
parseMessageData(data) {
|
|
586
|
+
const { thread_id, ...rest } = data;
|
|
587
|
+
return {
|
|
588
|
+
...rest,
|
|
589
|
+
threadId: thread_id,
|
|
590
|
+
content: typeof data.content === "string" ? (() => {
|
|
591
|
+
try {
|
|
592
|
+
return JSON.parse(data.content);
|
|
593
|
+
} catch {
|
|
594
|
+
return data.content;
|
|
595
|
+
}
|
|
596
|
+
})() : data.content,
|
|
597
|
+
createdAt: new Date(data.createdAt),
|
|
598
|
+
updatedAt: new Date(data.updatedAt)
|
|
599
|
+
};
|
|
67
600
|
}
|
|
68
|
-
async
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
601
|
+
async updateMessages(args) {
|
|
602
|
+
const { messages } = args;
|
|
603
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
604
|
+
if (!messages.length) {
|
|
605
|
+
return [];
|
|
606
|
+
}
|
|
607
|
+
const updatedMessages = [];
|
|
608
|
+
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
72
609
|
try {
|
|
73
|
-
|
|
74
|
-
|
|
610
|
+
for (const updateData of messages) {
|
|
611
|
+
const { id, ...updates } = updateData;
|
|
612
|
+
const existingMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
|
|
613
|
+
if (!existingMessage) {
|
|
614
|
+
this.logger.warn("Message not found for update", { id });
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
const existingMsg = this.parseMessageData(existingMessage);
|
|
618
|
+
const originalThreadId = existingMsg.threadId;
|
|
619
|
+
affectedThreadIds.add(originalThreadId);
|
|
620
|
+
const updatePayload = {};
|
|
621
|
+
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
622
|
+
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
623
|
+
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
624
|
+
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
625
|
+
updatePayload.thread_id = updates.threadId;
|
|
626
|
+
affectedThreadIds.add(updates.threadId);
|
|
627
|
+
}
|
|
628
|
+
if (updates.content) {
|
|
629
|
+
const existingContent = existingMsg.content;
|
|
630
|
+
let newContent = { ...existingContent };
|
|
631
|
+
if (updates.content.metadata !== void 0) {
|
|
632
|
+
newContent.metadata = {
|
|
633
|
+
...existingContent.metadata || {},
|
|
634
|
+
...updates.content.metadata || {}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
if (updates.content.content !== void 0) {
|
|
638
|
+
newContent.content = updates.content.content;
|
|
639
|
+
}
|
|
640
|
+
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
641
|
+
newContent.parts = updates.content.parts;
|
|
642
|
+
}
|
|
643
|
+
updatePayload.content = JSON.stringify(newContent);
|
|
644
|
+
}
|
|
645
|
+
await this.operations.insert({ tableName: TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
646
|
+
const updatedMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
|
|
647
|
+
if (updatedMessage) {
|
|
648
|
+
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
649
|
+
}
|
|
75
650
|
}
|
|
76
|
-
|
|
77
|
-
|
|
651
|
+
for (const threadId of affectedThreadIds) {
|
|
652
|
+
await this.operations.insert({
|
|
653
|
+
tableName: TABLE_THREADS,
|
|
654
|
+
record: { id: threadId, updatedAt: Date.now() }
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
return updatedMessages;
|
|
658
|
+
} catch (error) {
|
|
659
|
+
throw new MastraError(
|
|
660
|
+
{
|
|
661
|
+
id: "LANCE_STORE_UPDATE_MESSAGES_FAILED",
|
|
662
|
+
domain: ErrorDomain.STORAGE,
|
|
663
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
664
|
+
details: { count: messages.length }
|
|
665
|
+
},
|
|
666
|
+
error
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
async getResourceById({ resourceId }) {
|
|
671
|
+
try {
|
|
672
|
+
const resource = await this.operations.load({ tableName: TABLE_RESOURCES, keys: { id: resourceId } });
|
|
673
|
+
if (!resource) {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
let createdAt;
|
|
677
|
+
let updatedAt;
|
|
678
|
+
try {
|
|
679
|
+
if (resource.createdAt instanceof Date) {
|
|
680
|
+
createdAt = resource.createdAt;
|
|
681
|
+
} else if (typeof resource.createdAt === "string") {
|
|
682
|
+
createdAt = new Date(resource.createdAt);
|
|
683
|
+
} else if (typeof resource.createdAt === "number") {
|
|
684
|
+
createdAt = new Date(resource.createdAt);
|
|
685
|
+
} else {
|
|
686
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
687
|
+
}
|
|
688
|
+
if (isNaN(createdAt.getTime())) {
|
|
689
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
690
|
+
}
|
|
691
|
+
} catch {
|
|
692
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
78
693
|
}
|
|
79
|
-
|
|
80
|
-
|
|
694
|
+
try {
|
|
695
|
+
if (resource.updatedAt instanceof Date) {
|
|
696
|
+
updatedAt = resource.updatedAt;
|
|
697
|
+
} else if (typeof resource.updatedAt === "string") {
|
|
698
|
+
updatedAt = new Date(resource.updatedAt);
|
|
699
|
+
} else if (typeof resource.updatedAt === "number") {
|
|
700
|
+
updatedAt = new Date(resource.updatedAt);
|
|
701
|
+
} else {
|
|
702
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
703
|
+
}
|
|
704
|
+
if (isNaN(updatedAt.getTime())) {
|
|
705
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
706
|
+
}
|
|
707
|
+
} catch {
|
|
708
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
709
|
+
}
|
|
710
|
+
let workingMemory = resource.workingMemory;
|
|
711
|
+
if (workingMemory === null || workingMemory === void 0) {
|
|
712
|
+
workingMemory = void 0;
|
|
713
|
+
} else if (workingMemory === "") {
|
|
714
|
+
workingMemory = "";
|
|
715
|
+
} else if (typeof workingMemory === "object") {
|
|
716
|
+
workingMemory = JSON.stringify(workingMemory);
|
|
717
|
+
}
|
|
718
|
+
let metadata = resource.metadata;
|
|
719
|
+
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
720
|
+
metadata = void 0;
|
|
721
|
+
} else if (typeof metadata === "string") {
|
|
722
|
+
try {
|
|
723
|
+
metadata = JSON.parse(metadata);
|
|
724
|
+
} catch {
|
|
725
|
+
metadata = metadata;
|
|
726
|
+
}
|
|
81
727
|
}
|
|
728
|
+
return {
|
|
729
|
+
...resource,
|
|
730
|
+
createdAt,
|
|
731
|
+
updatedAt,
|
|
732
|
+
workingMemory,
|
|
733
|
+
metadata
|
|
734
|
+
};
|
|
82
735
|
} catch (error) {
|
|
83
736
|
throw new MastraError(
|
|
84
737
|
{
|
|
85
|
-
id: "
|
|
738
|
+
id: "LANCE_STORE_GET_RESOURCE_BY_ID_FAILED",
|
|
86
739
|
domain: ErrorDomain.STORAGE,
|
|
87
|
-
category: ErrorCategory.
|
|
88
|
-
details: { tableName }
|
|
740
|
+
category: ErrorCategory.THIRD_PARTY
|
|
89
741
|
},
|
|
90
742
|
error
|
|
91
743
|
);
|
|
92
744
|
}
|
|
745
|
+
}
|
|
746
|
+
async saveResource({ resource }) {
|
|
93
747
|
try {
|
|
94
|
-
const
|
|
95
|
-
|
|
748
|
+
const record = {
|
|
749
|
+
...resource,
|
|
750
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
751
|
+
createdAt: resource.createdAt.getTime(),
|
|
752
|
+
// Store as timestamp (milliseconds)
|
|
753
|
+
updatedAt: resource.updatedAt.getTime()
|
|
754
|
+
// Store as timestamp (milliseconds)
|
|
755
|
+
};
|
|
756
|
+
const table = await this.client.openTable(TABLE_RESOURCES);
|
|
757
|
+
await table.add([record], { mode: "append" });
|
|
758
|
+
return resource;
|
|
96
759
|
} catch (error) {
|
|
97
760
|
throw new MastraError(
|
|
98
761
|
{
|
|
99
|
-
id: "
|
|
762
|
+
id: "LANCE_STORE_SAVE_RESOURCE_FAILED",
|
|
100
763
|
domain: ErrorDomain.STORAGE,
|
|
101
|
-
category: ErrorCategory.THIRD_PARTY
|
|
102
|
-
details: { tableName }
|
|
764
|
+
category: ErrorCategory.THIRD_PARTY
|
|
103
765
|
},
|
|
104
766
|
error
|
|
105
767
|
);
|
|
106
768
|
}
|
|
107
769
|
}
|
|
770
|
+
async updateResource({
|
|
771
|
+
resourceId,
|
|
772
|
+
workingMemory,
|
|
773
|
+
metadata
|
|
774
|
+
}) {
|
|
775
|
+
const maxRetries = 3;
|
|
776
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
777
|
+
try {
|
|
778
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
779
|
+
if (!existingResource) {
|
|
780
|
+
const newResource = {
|
|
781
|
+
id: resourceId,
|
|
782
|
+
workingMemory,
|
|
783
|
+
metadata: metadata || {},
|
|
784
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
785
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
786
|
+
};
|
|
787
|
+
return this.saveResource({ resource: newResource });
|
|
788
|
+
}
|
|
789
|
+
const updatedResource = {
|
|
790
|
+
...existingResource,
|
|
791
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
792
|
+
metadata: {
|
|
793
|
+
...existingResource.metadata,
|
|
794
|
+
...metadata
|
|
795
|
+
},
|
|
796
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
797
|
+
};
|
|
798
|
+
const record = {
|
|
799
|
+
id: resourceId,
|
|
800
|
+
workingMemory: updatedResource.workingMemory || "",
|
|
801
|
+
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
802
|
+
updatedAt: updatedResource.updatedAt.getTime()
|
|
803
|
+
// Store as timestamp (milliseconds)
|
|
804
|
+
};
|
|
805
|
+
const table = await this.client.openTable(TABLE_RESOURCES);
|
|
806
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
807
|
+
return updatedResource;
|
|
808
|
+
} catch (error) {
|
|
809
|
+
if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
810
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
811
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
throw new MastraError(
|
|
815
|
+
{
|
|
816
|
+
id: "LANCE_STORE_UPDATE_RESOURCE_FAILED",
|
|
817
|
+
domain: ErrorDomain.STORAGE,
|
|
818
|
+
category: ErrorCategory.THIRD_PARTY
|
|
819
|
+
},
|
|
820
|
+
error
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
throw new Error("Unexpected end of retry loop");
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
var StoreOperationsLance = class extends StoreOperations {
|
|
828
|
+
client;
|
|
829
|
+
constructor({ client }) {
|
|
830
|
+
super();
|
|
831
|
+
this.client = client;
|
|
832
|
+
}
|
|
833
|
+
getDefaultValue(type) {
|
|
834
|
+
switch (type) {
|
|
835
|
+
case "text":
|
|
836
|
+
return "''";
|
|
837
|
+
case "timestamp":
|
|
838
|
+
return "CURRENT_TIMESTAMP";
|
|
839
|
+
case "integer":
|
|
840
|
+
case "bigint":
|
|
841
|
+
return "0";
|
|
842
|
+
case "jsonb":
|
|
843
|
+
return "'{}'";
|
|
844
|
+
case "uuid":
|
|
845
|
+
return "''";
|
|
846
|
+
default:
|
|
847
|
+
return super.getDefaultValue(type);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
async hasColumn(tableName, columnName) {
|
|
851
|
+
const table = await this.client.openTable(tableName);
|
|
852
|
+
const schema = await table.schema();
|
|
853
|
+
return schema.fields.some((field) => field.name === columnName);
|
|
854
|
+
}
|
|
108
855
|
translateSchema(schema) {
|
|
109
856
|
const fields = Object.entries(schema).map(([name, column]) => {
|
|
110
857
|
let arrowType;
|
|
@@ -140,40 +887,42 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
140
887
|
});
|
|
141
888
|
return new Schema(fields);
|
|
142
889
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
async dropTable(tableName) {
|
|
890
|
+
async createTable({
|
|
891
|
+
tableName,
|
|
892
|
+
schema
|
|
893
|
+
}) {
|
|
148
894
|
try {
|
|
149
|
-
if (!this.
|
|
895
|
+
if (!this.client) {
|
|
150
896
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
151
897
|
}
|
|
152
898
|
if (!tableName) {
|
|
153
|
-
throw new Error("tableName is required for
|
|
899
|
+
throw new Error("tableName is required for createTable.");
|
|
154
900
|
}
|
|
155
|
-
|
|
901
|
+
if (!schema) {
|
|
902
|
+
throw new Error("schema is required for createTable.");
|
|
903
|
+
}
|
|
904
|
+
} catch (error) {
|
|
156
905
|
throw new MastraError(
|
|
157
906
|
{
|
|
158
|
-
id: "
|
|
907
|
+
id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
|
|
159
908
|
domain: ErrorDomain.STORAGE,
|
|
160
909
|
category: ErrorCategory.USER,
|
|
161
|
-
text: validationError.message,
|
|
162
910
|
details: { tableName }
|
|
163
911
|
},
|
|
164
|
-
|
|
912
|
+
error
|
|
165
913
|
);
|
|
166
914
|
}
|
|
167
915
|
try {
|
|
168
|
-
|
|
916
|
+
const arrowSchema = this.translateSchema(schema);
|
|
917
|
+
await this.client.createEmptyTable(tableName, arrowSchema);
|
|
169
918
|
} catch (error) {
|
|
170
|
-
if (error.
|
|
171
|
-
this.logger.debug(`Table '${tableName}'
|
|
919
|
+
if (error.message?.includes("already exists")) {
|
|
920
|
+
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
172
921
|
return;
|
|
173
922
|
}
|
|
174
923
|
throw new MastraError(
|
|
175
924
|
{
|
|
176
|
-
id: "
|
|
925
|
+
id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
|
|
177
926
|
domain: ErrorDomain.STORAGE,
|
|
178
927
|
category: ErrorCategory.THIRD_PARTY,
|
|
179
928
|
details: { tableName }
|
|
@@ -182,23 +931,18 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
182
931
|
);
|
|
183
932
|
}
|
|
184
933
|
}
|
|
185
|
-
|
|
186
|
-
* Get table schema
|
|
187
|
-
* @param tableName Name of the table
|
|
188
|
-
* @returns Table schema
|
|
189
|
-
*/
|
|
190
|
-
async getTableSchema(tableName) {
|
|
934
|
+
async dropTable({ tableName }) {
|
|
191
935
|
try {
|
|
192
|
-
if (!this.
|
|
936
|
+
if (!this.client) {
|
|
193
937
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
194
938
|
}
|
|
195
939
|
if (!tableName) {
|
|
196
|
-
throw new Error("tableName is required for
|
|
940
|
+
throw new Error("tableName is required for dropTable.");
|
|
197
941
|
}
|
|
198
942
|
} catch (validationError) {
|
|
199
943
|
throw new MastraError(
|
|
200
944
|
{
|
|
201
|
-
id: "
|
|
945
|
+
id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
|
|
202
946
|
domain: ErrorDomain.STORAGE,
|
|
203
947
|
category: ErrorCategory.USER,
|
|
204
948
|
text: validationError.message,
|
|
@@ -208,20 +952,15 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
208
952
|
);
|
|
209
953
|
}
|
|
210
954
|
try {
|
|
211
|
-
|
|
212
|
-
const rawSchema = await table.schema();
|
|
213
|
-
const fields = rawSchema.fields;
|
|
214
|
-
return {
|
|
215
|
-
fields,
|
|
216
|
-
metadata: /* @__PURE__ */ new Map(),
|
|
217
|
-
get names() {
|
|
218
|
-
return fields.map((field) => field.name);
|
|
219
|
-
}
|
|
220
|
-
};
|
|
955
|
+
await this.client.dropTable(tableName);
|
|
221
956
|
} catch (error) {
|
|
957
|
+
if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
|
|
958
|
+
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
222
961
|
throw new MastraError(
|
|
223
962
|
{
|
|
224
|
-
id: "
|
|
963
|
+
id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
|
|
225
964
|
domain: ErrorDomain.STORAGE,
|
|
226
965
|
category: ErrorCategory.THIRD_PARTY,
|
|
227
966
|
details: { tableName }
|
|
@@ -230,36 +969,13 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
230
969
|
);
|
|
231
970
|
}
|
|
232
971
|
}
|
|
233
|
-
getDefaultValue(type) {
|
|
234
|
-
switch (type) {
|
|
235
|
-
case "text":
|
|
236
|
-
return "''";
|
|
237
|
-
case "timestamp":
|
|
238
|
-
return "CURRENT_TIMESTAMP";
|
|
239
|
-
case "integer":
|
|
240
|
-
case "bigint":
|
|
241
|
-
return "0";
|
|
242
|
-
case "jsonb":
|
|
243
|
-
return "'{}'";
|
|
244
|
-
case "uuid":
|
|
245
|
-
return "''";
|
|
246
|
-
default:
|
|
247
|
-
return super.getDefaultValue(type);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Alters table schema to add columns if they don't exist
|
|
252
|
-
* @param tableName Name of the table
|
|
253
|
-
* @param schema Schema of the table
|
|
254
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
255
|
-
*/
|
|
256
972
|
async alterTable({
|
|
257
973
|
tableName,
|
|
258
974
|
schema,
|
|
259
975
|
ifNotExists
|
|
260
976
|
}) {
|
|
261
977
|
try {
|
|
262
|
-
if (!this.
|
|
978
|
+
if (!this.client) {
|
|
263
979
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
264
980
|
}
|
|
265
981
|
if (!tableName) {
|
|
@@ -285,7 +1001,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
285
1001
|
);
|
|
286
1002
|
}
|
|
287
1003
|
try {
|
|
288
|
-
const table = await this.
|
|
1004
|
+
const table = await this.client.openTable(tableName);
|
|
289
1005
|
const currentSchema = await table.schema();
|
|
290
1006
|
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
291
1007
|
const typeMap = {
|
|
@@ -321,7 +1037,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
321
1037
|
}
|
|
322
1038
|
async clearTable({ tableName }) {
|
|
323
1039
|
try {
|
|
324
|
-
if (!this.
|
|
1040
|
+
if (!this.client) {
|
|
325
1041
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
326
1042
|
}
|
|
327
1043
|
if (!tableName) {
|
|
@@ -340,7 +1056,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
340
1056
|
);
|
|
341
1057
|
}
|
|
342
1058
|
try {
|
|
343
|
-
const table = await this.
|
|
1059
|
+
const table = await this.client.openTable(tableName);
|
|
344
1060
|
await table.delete("1=1");
|
|
345
1061
|
} catch (error) {
|
|
346
1062
|
throw new MastraError(
|
|
@@ -354,14 +1070,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
354
1070
|
);
|
|
355
1071
|
}
|
|
356
1072
|
}
|
|
357
|
-
/**
|
|
358
|
-
* Insert a single record into a table. This function overwrites the existing record if it exists. Use this function for inserting records into tables with custom schemas.
|
|
359
|
-
* @param tableName The name of the table to insert into.
|
|
360
|
-
* @param record The record to insert.
|
|
361
|
-
*/
|
|
362
1073
|
async insert({ tableName, record }) {
|
|
363
1074
|
try {
|
|
364
|
-
if (!this.
|
|
1075
|
+
if (!this.client) {
|
|
365
1076
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
366
1077
|
}
|
|
367
1078
|
if (!tableName) {
|
|
@@ -383,8 +1094,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
383
1094
|
);
|
|
384
1095
|
}
|
|
385
1096
|
try {
|
|
386
|
-
const table = await this.
|
|
387
|
-
const primaryId =
|
|
1097
|
+
const table = await this.client.openTable(tableName);
|
|
1098
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
388
1099
|
const processedRecord = { ...record };
|
|
389
1100
|
for (const key in processedRecord) {
|
|
390
1101
|
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
@@ -392,6 +1103,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
392
1103
|
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
393
1104
|
}
|
|
394
1105
|
}
|
|
1106
|
+
console.info(await table.schema());
|
|
395
1107
|
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
396
1108
|
} catch (error) {
|
|
397
1109
|
throw new MastraError(
|
|
@@ -405,14 +1117,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
405
1117
|
);
|
|
406
1118
|
}
|
|
407
1119
|
}
|
|
408
|
-
/**
|
|
409
|
-
* Insert multiple records into a table. This function overwrites the existing records if they exist. Use this function for inserting records into tables with custom schemas.
|
|
410
|
-
* @param tableName The name of the table to insert into.
|
|
411
|
-
* @param records The records to insert.
|
|
412
|
-
*/
|
|
413
1120
|
async batchInsert({ tableName, records }) {
|
|
414
1121
|
try {
|
|
415
|
-
if (!this.
|
|
1122
|
+
if (!this.client) {
|
|
416
1123
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
417
1124
|
}
|
|
418
1125
|
if (!tableName) {
|
|
@@ -434,8 +1141,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
434
1141
|
);
|
|
435
1142
|
}
|
|
436
1143
|
try {
|
|
437
|
-
const table = await this.
|
|
438
|
-
const primaryId =
|
|
1144
|
+
const table = await this.client.openTable(tableName);
|
|
1145
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
439
1146
|
const processedRecords = records.map((record) => {
|
|
440
1147
|
const processedRecord = { ...record };
|
|
441
1148
|
for (const key in processedRecord) {
|
|
@@ -459,16 +1166,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
459
1166
|
);
|
|
460
1167
|
}
|
|
461
1168
|
}
|
|
462
|
-
/**
|
|
463
|
-
* Load a record from the database by its key(s)
|
|
464
|
-
* @param tableName The name of the table to query
|
|
465
|
-
* @param keys Record of key-value pairs to use for lookup
|
|
466
|
-
* @throws Error if invalid types are provided for keys
|
|
467
|
-
* @returns The loaded record with proper type conversions, or null if not found
|
|
468
|
-
*/
|
|
469
1169
|
async load({ tableName, keys }) {
|
|
470
1170
|
try {
|
|
471
|
-
if (!this.
|
|
1171
|
+
if (!this.client) {
|
|
472
1172
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
473
1173
|
}
|
|
474
1174
|
if (!tableName) {
|
|
@@ -490,11 +1190,11 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
490
1190
|
);
|
|
491
1191
|
}
|
|
492
1192
|
try {
|
|
493
|
-
const table = await this.
|
|
494
|
-
const tableSchema = await
|
|
1193
|
+
const table = await this.client.openTable(tableName);
|
|
1194
|
+
const tableSchema = await getTableSchema({ tableName, client: this.client });
|
|
495
1195
|
const query = table.query();
|
|
496
1196
|
if (Object.keys(keys).length > 0) {
|
|
497
|
-
|
|
1197
|
+
validateKeyTypes(keys, tableSchema);
|
|
498
1198
|
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
499
1199
|
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
500
1200
|
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
@@ -514,7 +1214,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
514
1214
|
this.logger.debug("No record found");
|
|
515
1215
|
return null;
|
|
516
1216
|
}
|
|
517
|
-
return
|
|
1217
|
+
return processResultWithTypeConversion(result[0], tableSchema);
|
|
518
1218
|
} catch (error) {
|
|
519
1219
|
if (error instanceof MastraError) throw error;
|
|
520
1220
|
throw new MastraError(
|
|
@@ -528,634 +1228,729 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
528
1228
|
);
|
|
529
1229
|
}
|
|
530
1230
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
validateKeyTypes(keys, tableSchema) {
|
|
538
|
-
const fieldTypes = new Map(
|
|
539
|
-
tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
|
|
540
|
-
);
|
|
541
|
-
for (const [key, value] of Object.entries(keys)) {
|
|
542
|
-
const fieldType = fieldTypes.get(key);
|
|
543
|
-
if (!fieldType) {
|
|
544
|
-
throw new Error(`Field '${key}' does not exist in table schema`);
|
|
545
|
-
}
|
|
546
|
-
if (value !== null) {
|
|
547
|
-
if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
|
|
548
|
-
throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
|
|
549
|
-
}
|
|
550
|
-
if (fieldType.includes("utf8") && typeof value !== "string") {
|
|
551
|
-
throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
|
|
552
|
-
}
|
|
553
|
-
if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
|
|
554
|
-
throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Process a database result with appropriate type conversions based on the table schema
|
|
561
|
-
* @param rawResult The raw result object from the database
|
|
562
|
-
* @param tableSchema The schema of the table containing type information
|
|
563
|
-
* @returns Processed result with correct data types
|
|
564
|
-
*/
|
|
565
|
-
processResultWithTypeConversion(rawResult, tableSchema) {
|
|
566
|
-
const fieldTypeMap = /* @__PURE__ */ new Map();
|
|
567
|
-
tableSchema.fields.forEach((field) => {
|
|
568
|
-
const fieldName = field.name;
|
|
569
|
-
const fieldTypeStr = field.type.toString().toLowerCase();
|
|
570
|
-
fieldTypeMap.set(fieldName, fieldTypeStr);
|
|
571
|
-
});
|
|
572
|
-
if (Array.isArray(rawResult)) {
|
|
573
|
-
return rawResult.map((item) => this.processResultWithTypeConversion(item, tableSchema));
|
|
574
|
-
}
|
|
575
|
-
const processedResult = { ...rawResult };
|
|
576
|
-
for (const key in processedResult) {
|
|
577
|
-
const fieldTypeStr = fieldTypeMap.get(key);
|
|
578
|
-
if (!fieldTypeStr) continue;
|
|
579
|
-
if (typeof processedResult[key] === "string") {
|
|
580
|
-
if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
|
|
581
|
-
if (!isNaN(Number(processedResult[key]))) {
|
|
582
|
-
processedResult[key] = Number(processedResult[key]);
|
|
583
|
-
}
|
|
584
|
-
} else if (fieldTypeStr.includes("int64")) {
|
|
585
|
-
processedResult[key] = Number(processedResult[key]);
|
|
586
|
-
} else if (fieldTypeStr.includes("utf8")) {
|
|
587
|
-
try {
|
|
588
|
-
processedResult[key] = JSON.parse(processedResult[key]);
|
|
589
|
-
} catch (e) {
|
|
590
|
-
this.logger.debug(`Failed to parse JSON for key ${key}: ${e}`);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
} else if (typeof processedResult[key] === "bigint") {
|
|
594
|
-
processedResult[key] = Number(processedResult[key]);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return processedResult;
|
|
598
|
-
}
|
|
599
|
-
getThreadById({ threadId }) {
|
|
600
|
-
try {
|
|
601
|
-
return this.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
|
|
602
|
-
} catch (error) {
|
|
603
|
-
throw new MastraError(
|
|
604
|
-
{
|
|
605
|
-
id: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
|
|
606
|
-
domain: ErrorDomain.STORAGE,
|
|
607
|
-
category: ErrorCategory.THIRD_PARTY
|
|
608
|
-
},
|
|
609
|
-
error
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
async getThreadsByResourceId({ resourceId }) {
|
|
614
|
-
try {
|
|
615
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
616
|
-
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
617
|
-
const records = await query.toArray();
|
|
618
|
-
return this.processResultWithTypeConversion(
|
|
619
|
-
records,
|
|
620
|
-
await this.getTableSchema(TABLE_THREADS)
|
|
621
|
-
);
|
|
622
|
-
} catch (error) {
|
|
623
|
-
throw new MastraError(
|
|
624
|
-
{
|
|
625
|
-
id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
626
|
-
domain: ErrorDomain.STORAGE,
|
|
627
|
-
category: ErrorCategory.THIRD_PARTY
|
|
628
|
-
},
|
|
629
|
-
error
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
635
|
-
* @param thread - The thread to save
|
|
636
|
-
* @returns The saved thread
|
|
637
|
-
*/
|
|
638
|
-
async saveThread({ thread }) {
|
|
639
|
-
try {
|
|
640
|
-
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
641
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
642
|
-
await table.add([record], { mode: "append" });
|
|
643
|
-
return thread;
|
|
644
|
-
} catch (error) {
|
|
645
|
-
throw new MastraError(
|
|
646
|
-
{
|
|
647
|
-
id: "LANCE_STORE_SAVE_THREAD_FAILED",
|
|
648
|
-
domain: ErrorDomain.STORAGE,
|
|
649
|
-
category: ErrorCategory.THIRD_PARTY
|
|
650
|
-
},
|
|
651
|
-
error
|
|
652
|
-
);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
async updateThread({
|
|
656
|
-
id,
|
|
657
|
-
title,
|
|
658
|
-
metadata
|
|
659
|
-
}) {
|
|
660
|
-
try {
|
|
661
|
-
const record = { id, title, metadata: JSON.stringify(metadata) };
|
|
662
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
663
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
664
|
-
const query = table.query().where(`id = '${id}'`);
|
|
665
|
-
const records = await query.toArray();
|
|
666
|
-
return this.processResultWithTypeConversion(
|
|
667
|
-
records[0],
|
|
668
|
-
await this.getTableSchema(TABLE_THREADS)
|
|
669
|
-
);
|
|
670
|
-
} catch (error) {
|
|
671
|
-
throw new MastraError(
|
|
672
|
-
{
|
|
673
|
-
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
674
|
-
domain: ErrorDomain.STORAGE,
|
|
675
|
-
category: ErrorCategory.THIRD_PARTY
|
|
676
|
-
},
|
|
677
|
-
error
|
|
678
|
-
);
|
|
679
|
-
}
|
|
1231
|
+
};
|
|
1232
|
+
var StoreScoresLance = class extends ScoresStorage {
|
|
1233
|
+
client;
|
|
1234
|
+
constructor({ client }) {
|
|
1235
|
+
super();
|
|
1236
|
+
this.client = client;
|
|
680
1237
|
}
|
|
681
|
-
async
|
|
1238
|
+
async saveScore(score) {
|
|
1239
|
+
let validatedScore;
|
|
682
1240
|
try {
|
|
683
|
-
|
|
684
|
-
await table.delete(`id = '${threadId}'`);
|
|
1241
|
+
validatedScore = saveScorePayloadSchema.parse(score);
|
|
685
1242
|
} catch (error) {
|
|
686
1243
|
throw new MastraError(
|
|
687
1244
|
{
|
|
688
|
-
id: "
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
return records;
|
|
706
|
-
}
|
|
707
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
708
|
-
records.forEach((message, index) => {
|
|
709
|
-
messageIndexMap.set(message.id, index);
|
|
710
|
-
});
|
|
711
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
712
|
-
for (const item of messagesWithContext) {
|
|
713
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
714
|
-
if (messageIndex !== void 0) {
|
|
715
|
-
if (item.withPreviousMessages) {
|
|
716
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
717
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
718
|
-
additionalIndices.add(i);
|
|
719
|
-
}
|
|
1245
|
+
id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
|
|
1246
|
+
text: "Failed to save score in LanceStorage",
|
|
1247
|
+
domain: ErrorDomain.STORAGE,
|
|
1248
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1249
|
+
},
|
|
1250
|
+
error
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
try {
|
|
1254
|
+
const id = crypto.randomUUID();
|
|
1255
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1256
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1257
|
+
const allowedFields = new Set(schema.fields.map((f) => f.name));
|
|
1258
|
+
const filteredScore = {};
|
|
1259
|
+
Object.keys(validatedScore).forEach((key) => {
|
|
1260
|
+
if (allowedFields.has(key)) {
|
|
1261
|
+
filteredScore[key] = score[key];
|
|
720
1262
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
}
|
|
1263
|
+
});
|
|
1264
|
+
for (const key in filteredScore) {
|
|
1265
|
+
if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
|
|
1266
|
+
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
726
1267
|
}
|
|
727
1268
|
}
|
|
1269
|
+
filteredScore.id = id;
|
|
1270
|
+
await table.add([filteredScore], { mode: "append" });
|
|
1271
|
+
return { score };
|
|
1272
|
+
} catch (error) {
|
|
1273
|
+
throw new MastraError(
|
|
1274
|
+
{
|
|
1275
|
+
id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
|
|
1276
|
+
text: "Failed to save score in LanceStorage",
|
|
1277
|
+
domain: ErrorDomain.STORAGE,
|
|
1278
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1279
|
+
details: { error: error?.message }
|
|
1280
|
+
},
|
|
1281
|
+
error
|
|
1282
|
+
);
|
|
728
1283
|
}
|
|
729
|
-
if (additionalIndices.size === 0) {
|
|
730
|
-
return records;
|
|
731
|
-
}
|
|
732
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
733
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
734
|
-
records.forEach((record, index) => {
|
|
735
|
-
if (originalMatchIds.has(record.id)) {
|
|
736
|
-
allIndices.add(index);
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
additionalIndices.forEach((index) => {
|
|
740
|
-
allIndices.add(index);
|
|
741
|
-
});
|
|
742
|
-
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
743
1284
|
}
|
|
744
|
-
async
|
|
745
|
-
threadId,
|
|
746
|
-
resourceId,
|
|
747
|
-
selectBy,
|
|
748
|
-
format,
|
|
749
|
-
threadConfig
|
|
750
|
-
}) {
|
|
1285
|
+
async getScoreById({ id }) {
|
|
751
1286
|
try {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
const
|
|
757
|
-
|
|
758
|
-
if (selectBy) {
|
|
759
|
-
if (selectBy.include && selectBy.include.length > 0) {
|
|
760
|
-
const includeIds = selectBy.include.map((item) => item.id);
|
|
761
|
-
const includeClause = includeIds.map((id) => `\`id\` = '${id}'`).join(" OR ");
|
|
762
|
-
query = query.where(`(\`threadId\` = '${threadId}' OR (${includeClause}))`);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
let records = await query.toArray();
|
|
766
|
-
records.sort((a, b) => {
|
|
767
|
-
const dateA = new Date(a.createdAt).getTime();
|
|
768
|
-
const dateB = new Date(b.createdAt).getTime();
|
|
769
|
-
return dateA - dateB;
|
|
770
|
-
});
|
|
771
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
772
|
-
records = this.processMessagesWithContext(records, selectBy.include);
|
|
773
|
-
}
|
|
774
|
-
if (limit !== Number.MAX_SAFE_INTEGER) {
|
|
775
|
-
records = records.slice(-limit);
|
|
776
|
-
}
|
|
777
|
-
const messages = this.processResultWithTypeConversion(records, await this.getTableSchema(TABLE_MESSAGES));
|
|
778
|
-
const normalized = messages.map((msg) => ({
|
|
779
|
-
...msg,
|
|
780
|
-
content: typeof msg.content === "string" ? (() => {
|
|
781
|
-
try {
|
|
782
|
-
return JSON.parse(msg.content);
|
|
783
|
-
} catch {
|
|
784
|
-
return msg.content;
|
|
785
|
-
}
|
|
786
|
-
})() : msg.content
|
|
787
|
-
}));
|
|
788
|
-
const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
|
|
789
|
-
if (format === "v2") return list.get.all.v2();
|
|
790
|
-
return list.get.all.v1();
|
|
1287
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1288
|
+
const query = table.query().where(`id = '${id}'`).limit(1);
|
|
1289
|
+
const records = await query.toArray();
|
|
1290
|
+
if (records.length === 0) return null;
|
|
1291
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1292
|
+
return processResultWithTypeConversion(records[0], schema);
|
|
791
1293
|
} catch (error) {
|
|
792
1294
|
throw new MastraError(
|
|
793
1295
|
{
|
|
794
|
-
id: "
|
|
1296
|
+
id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
|
|
1297
|
+
text: "Failed to get score by id in LanceStorage",
|
|
795
1298
|
domain: ErrorDomain.STORAGE,
|
|
796
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1299
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1300
|
+
details: { error: error?.message }
|
|
797
1301
|
},
|
|
798
1302
|
error
|
|
799
1303
|
);
|
|
800
1304
|
}
|
|
801
1305
|
}
|
|
802
|
-
async
|
|
1306
|
+
async listScoresByScorerId({
|
|
1307
|
+
scorerId,
|
|
1308
|
+
pagination,
|
|
1309
|
+
entityId,
|
|
1310
|
+
entityType,
|
|
1311
|
+
source
|
|
1312
|
+
}) {
|
|
803
1313
|
try {
|
|
804
|
-
const {
|
|
805
|
-
|
|
806
|
-
|
|
1314
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1315
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1316
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1317
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1318
|
+
let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1319
|
+
if (source) {
|
|
1320
|
+
query = query.where(`\`source\` = '${source}'`);
|
|
807
1321
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
throw new Error("Thread ID is required");
|
|
1322
|
+
if (entityId) {
|
|
1323
|
+
query = query.where(`\`entityId\` = '${entityId}'`);
|
|
811
1324
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
})
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
if (
|
|
820
|
-
|
|
1325
|
+
if (entityType) {
|
|
1326
|
+
query = query.where(`\`entityType\` = '${entityType}'`);
|
|
1327
|
+
}
|
|
1328
|
+
let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1329
|
+
if (source) {
|
|
1330
|
+
totalQuery = totalQuery.where(`\`source\` = '${source}'`);
|
|
1331
|
+
}
|
|
1332
|
+
if (entityId) {
|
|
1333
|
+
totalQuery = totalQuery.where(`\`entityId\` = '${entityId}'`);
|
|
1334
|
+
}
|
|
1335
|
+
if (entityType) {
|
|
1336
|
+
totalQuery = totalQuery.where(`\`entityType\` = '${entityType}'`);
|
|
1337
|
+
}
|
|
1338
|
+
const allRecords = await totalQuery.toArray();
|
|
1339
|
+
const total = allRecords.length;
|
|
1340
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1341
|
+
if (perPageInput !== false) {
|
|
1342
|
+
query = query.limit(perPage);
|
|
1343
|
+
if (start > 0) query = query.offset(start);
|
|
1344
|
+
}
|
|
1345
|
+
const records = await query.toArray();
|
|
1346
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1347
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1348
|
+
return {
|
|
1349
|
+
pagination: {
|
|
1350
|
+
page,
|
|
1351
|
+
perPage: perPageForResponse,
|
|
1352
|
+
total,
|
|
1353
|
+
hasMore: end < total
|
|
1354
|
+
},
|
|
1355
|
+
scores
|
|
1356
|
+
};
|
|
821
1357
|
} catch (error) {
|
|
822
1358
|
throw new MastraError(
|
|
823
1359
|
{
|
|
824
|
-
id: "
|
|
1360
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
1361
|
+
text: "Failed to get scores by scorerId in LanceStorage",
|
|
825
1362
|
domain: ErrorDomain.STORAGE,
|
|
826
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1363
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1364
|
+
details: { error: error?.message }
|
|
827
1365
|
},
|
|
828
1366
|
error
|
|
829
1367
|
);
|
|
830
1368
|
}
|
|
831
1369
|
}
|
|
832
|
-
async
|
|
1370
|
+
async listScoresByRunId({
|
|
1371
|
+
runId,
|
|
1372
|
+
pagination
|
|
1373
|
+
}) {
|
|
833
1374
|
try {
|
|
834
|
-
const
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1375
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1376
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1377
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1378
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1379
|
+
const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
|
|
1380
|
+
const total = allRecords.length;
|
|
1381
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1382
|
+
let query = table.query().where(`\`runId\` = '${runId}'`);
|
|
1383
|
+
if (perPageInput !== false) {
|
|
1384
|
+
query = query.limit(perPage);
|
|
1385
|
+
if (start > 0) query = query.offset(start);
|
|
1386
|
+
}
|
|
1387
|
+
const records = await query.toArray();
|
|
1388
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1389
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1390
|
+
return {
|
|
1391
|
+
pagination: {
|
|
1392
|
+
page,
|
|
1393
|
+
perPage: perPageForResponse,
|
|
1394
|
+
total,
|
|
1395
|
+
hasMore: end < total
|
|
1396
|
+
},
|
|
1397
|
+
scores
|
|
842
1398
|
};
|
|
843
|
-
await table.add([record], { mode: "append" });
|
|
844
|
-
return trace;
|
|
845
1399
|
} catch (error) {
|
|
846
1400
|
throw new MastraError(
|
|
847
1401
|
{
|
|
848
|
-
id: "
|
|
1402
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1403
|
+
text: "Failed to get scores by runId in LanceStorage",
|
|
849
1404
|
domain: ErrorDomain.STORAGE,
|
|
850
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1405
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1406
|
+
details: { error: error?.message }
|
|
851
1407
|
},
|
|
852
1408
|
error
|
|
853
1409
|
);
|
|
854
1410
|
}
|
|
855
1411
|
}
|
|
856
|
-
async
|
|
1412
|
+
async listScoresByEntityId({
|
|
1413
|
+
entityId,
|
|
1414
|
+
entityType,
|
|
1415
|
+
pagination
|
|
1416
|
+
}) {
|
|
857
1417
|
try {
|
|
858
|
-
const
|
|
859
|
-
const
|
|
1418
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1419
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1420
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1421
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1422
|
+
const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
|
|
1423
|
+
const total = allRecords.length;
|
|
1424
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1425
|
+
let query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`);
|
|
1426
|
+
if (perPageInput !== false) {
|
|
1427
|
+
query = query.limit(perPage);
|
|
1428
|
+
if (start > 0) query = query.offset(start);
|
|
1429
|
+
}
|
|
860
1430
|
const records = await query.toArray();
|
|
861
|
-
|
|
1431
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1432
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1433
|
+
return {
|
|
1434
|
+
pagination: {
|
|
1435
|
+
page,
|
|
1436
|
+
perPage: perPageForResponse,
|
|
1437
|
+
total,
|
|
1438
|
+
hasMore: end < total
|
|
1439
|
+
},
|
|
1440
|
+
scores
|
|
1441
|
+
};
|
|
862
1442
|
} catch (error) {
|
|
863
1443
|
throw new MastraError(
|
|
864
1444
|
{
|
|
865
|
-
id: "
|
|
1445
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1446
|
+
text: "Failed to get scores by entityId and entityType in LanceStorage",
|
|
866
1447
|
domain: ErrorDomain.STORAGE,
|
|
867
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1448
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1449
|
+
details: { error: error?.message }
|
|
868
1450
|
},
|
|
869
1451
|
error
|
|
870
1452
|
);
|
|
871
1453
|
}
|
|
872
1454
|
}
|
|
873
|
-
async
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
perPage = 10,
|
|
878
|
-
attributes
|
|
1455
|
+
async listScoresBySpan({
|
|
1456
|
+
traceId,
|
|
1457
|
+
spanId,
|
|
1458
|
+
pagination
|
|
879
1459
|
}) {
|
|
880
1460
|
try {
|
|
881
|
-
const
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
}
|
|
889
|
-
if (
|
|
890
|
-
query
|
|
891
|
-
|
|
892
|
-
const offset = (page - 1) * perPage;
|
|
893
|
-
query.limit(perPage);
|
|
894
|
-
if (offset > 0) {
|
|
895
|
-
query.offset(offset);
|
|
1461
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1462
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1463
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1464
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1465
|
+
const allRecords = await table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).toArray();
|
|
1466
|
+
const total = allRecords.length;
|
|
1467
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1468
|
+
let query = table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`);
|
|
1469
|
+
if (perPageInput !== false) {
|
|
1470
|
+
query = query.limit(perPage);
|
|
1471
|
+
if (start > 0) query = query.offset(start);
|
|
896
1472
|
}
|
|
897
1473
|
const records = await query.toArray();
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
};
|
|
910
|
-
});
|
|
1474
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1475
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1476
|
+
return {
|
|
1477
|
+
pagination: {
|
|
1478
|
+
page,
|
|
1479
|
+
perPage: perPageForResponse,
|
|
1480
|
+
total,
|
|
1481
|
+
hasMore: end < total
|
|
1482
|
+
},
|
|
1483
|
+
scores
|
|
1484
|
+
};
|
|
911
1485
|
} catch (error) {
|
|
912
1486
|
throw new MastraError(
|
|
913
1487
|
{
|
|
914
|
-
id: "
|
|
1488
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_SPAN_FAILED",
|
|
1489
|
+
text: "Failed to get scores by traceId and spanId in LanceStorage",
|
|
915
1490
|
domain: ErrorDomain.STORAGE,
|
|
916
1491
|
category: ErrorCategory.THIRD_PARTY,
|
|
917
|
-
details: {
|
|
1492
|
+
details: { error: error?.message }
|
|
918
1493
|
},
|
|
919
1494
|
error
|
|
920
1495
|
);
|
|
921
1496
|
}
|
|
922
1497
|
}
|
|
923
|
-
|
|
1498
|
+
};
|
|
1499
|
+
function parseWorkflowRun(row) {
|
|
1500
|
+
let parsedSnapshot = row.snapshot;
|
|
1501
|
+
if (typeof parsedSnapshot === "string") {
|
|
1502
|
+
try {
|
|
1503
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1504
|
+
} catch (e) {
|
|
1505
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
return {
|
|
1509
|
+
workflowName: row.workflow_name,
|
|
1510
|
+
runId: row.run_id,
|
|
1511
|
+
snapshot: parsedSnapshot,
|
|
1512
|
+
createdAt: ensureDate(row.createdAt),
|
|
1513
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
1514
|
+
resourceId: row.resourceId
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
1518
|
+
client;
|
|
1519
|
+
constructor({ client }) {
|
|
1520
|
+
super();
|
|
1521
|
+
this.client = client;
|
|
1522
|
+
}
|
|
1523
|
+
updateWorkflowResults({
|
|
1524
|
+
// workflowName,
|
|
1525
|
+
// runId,
|
|
1526
|
+
// stepId,
|
|
1527
|
+
// result,
|
|
1528
|
+
// requestContext,
|
|
1529
|
+
}) {
|
|
1530
|
+
throw new Error("Method not implemented.");
|
|
1531
|
+
}
|
|
1532
|
+
updateWorkflowState({
|
|
1533
|
+
// workflowName,
|
|
1534
|
+
// runId,
|
|
1535
|
+
// opts,
|
|
1536
|
+
}) {
|
|
1537
|
+
throw new Error("Method not implemented.");
|
|
1538
|
+
}
|
|
1539
|
+
async persistWorkflowSnapshot({
|
|
1540
|
+
workflowName,
|
|
1541
|
+
runId,
|
|
1542
|
+
resourceId,
|
|
1543
|
+
snapshot
|
|
1544
|
+
}) {
|
|
924
1545
|
try {
|
|
925
|
-
const table = await this.
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1546
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1547
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1548
|
+
const records = await query.toArray();
|
|
1549
|
+
let createdAt;
|
|
1550
|
+
const now = Date.now();
|
|
1551
|
+
if (records.length > 0) {
|
|
1552
|
+
createdAt = records[0].createdAt ?? now;
|
|
1553
|
+
} else {
|
|
1554
|
+
createdAt = now;
|
|
1555
|
+
}
|
|
1556
|
+
const { status, value, ...rest } = snapshot;
|
|
1557
|
+
const record = {
|
|
1558
|
+
workflow_name: workflowName,
|
|
1559
|
+
run_id: runId,
|
|
1560
|
+
resourceId,
|
|
1561
|
+
snapshot: JSON.stringify({ status, value, ...rest }),
|
|
1562
|
+
// this is to ensure status is always just before value, for when querying the db by status
|
|
1563
|
+
createdAt,
|
|
1564
|
+
updatedAt: now
|
|
1565
|
+
};
|
|
1566
|
+
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
940
1567
|
} catch (error) {
|
|
941
1568
|
throw new MastraError(
|
|
942
1569
|
{
|
|
943
|
-
id: "
|
|
1570
|
+
id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
944
1571
|
domain: ErrorDomain.STORAGE,
|
|
945
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1572
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1573
|
+
details: { workflowName, runId }
|
|
946
1574
|
},
|
|
947
1575
|
error
|
|
948
1576
|
);
|
|
949
1577
|
}
|
|
950
1578
|
}
|
|
951
|
-
async
|
|
1579
|
+
async loadWorkflowSnapshot({
|
|
1580
|
+
workflowName,
|
|
1581
|
+
runId
|
|
1582
|
+
}) {
|
|
952
1583
|
try {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}
|
|
956
|
-
const table = await this.lanceClient.openTable(TABLE_EVALS);
|
|
957
|
-
const query = table.query().where(`agent_name = '${agentName}'`);
|
|
1584
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1585
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
958
1586
|
const records = await query.toArray();
|
|
959
|
-
return records.
|
|
960
|
-
return {
|
|
961
|
-
id: record.id,
|
|
962
|
-
input: record.input,
|
|
963
|
-
output: record.output,
|
|
964
|
-
agentName: record.agent_name,
|
|
965
|
-
metricName: record.metric_name,
|
|
966
|
-
result: JSON.parse(record.result),
|
|
967
|
-
instructions: record.instructions,
|
|
968
|
-
testInfo: JSON.parse(record.test_info),
|
|
969
|
-
globalRunId: record.global_run_id,
|
|
970
|
-
runId: record.run_id,
|
|
971
|
-
createdAt: new Date(record.created_at).toString()
|
|
972
|
-
};
|
|
973
|
-
});
|
|
1587
|
+
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
974
1588
|
} catch (error) {
|
|
975
1589
|
throw new MastraError(
|
|
976
1590
|
{
|
|
977
|
-
id: "
|
|
1591
|
+
id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
978
1592
|
domain: ErrorDomain.STORAGE,
|
|
979
1593
|
category: ErrorCategory.THIRD_PARTY,
|
|
980
|
-
details: {
|
|
1594
|
+
details: { workflowName, runId }
|
|
981
1595
|
},
|
|
982
1596
|
error
|
|
983
1597
|
);
|
|
984
1598
|
}
|
|
985
1599
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1600
|
+
async getWorkflowRunById(args) {
|
|
1601
|
+
try {
|
|
1602
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1603
|
+
let whereClause = `run_id = '${args.runId}'`;
|
|
1604
|
+
if (args.workflowName) {
|
|
1605
|
+
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
993
1606
|
}
|
|
1607
|
+
const query = table.query().where(whereClause);
|
|
1608
|
+
const records = await query.toArray();
|
|
1609
|
+
if (records.length === 0) return null;
|
|
1610
|
+
const record = records[0];
|
|
1611
|
+
return parseWorkflowRun(record);
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
throw new MastraError(
|
|
1614
|
+
{
|
|
1615
|
+
id: "LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
1616
|
+
domain: ErrorDomain.STORAGE,
|
|
1617
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1618
|
+
details: { runId: args.runId, workflowName: args.workflowName ?? "" }
|
|
1619
|
+
},
|
|
1620
|
+
error
|
|
1621
|
+
);
|
|
994
1622
|
}
|
|
995
|
-
return {
|
|
996
|
-
workflowName: row.workflow_name,
|
|
997
|
-
runId: row.run_id,
|
|
998
|
-
snapshot: parsedSnapshot,
|
|
999
|
-
createdAt: this.ensureDate(row.createdAt),
|
|
1000
|
-
updatedAt: this.ensureDate(row.updatedAt),
|
|
1001
|
-
resourceId: row.resourceId
|
|
1002
|
-
};
|
|
1003
1623
|
}
|
|
1004
|
-
async
|
|
1624
|
+
async listWorkflowRuns(args) {
|
|
1005
1625
|
try {
|
|
1006
|
-
const table = await this.
|
|
1007
|
-
|
|
1626
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1627
|
+
let query = table.query();
|
|
1628
|
+
const conditions = [];
|
|
1008
1629
|
if (args?.workflowName) {
|
|
1009
|
-
|
|
1630
|
+
conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
|
|
1631
|
+
}
|
|
1632
|
+
if (args?.status) {
|
|
1633
|
+
const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
1634
|
+
conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
|
|
1010
1635
|
}
|
|
1011
|
-
if (args?.
|
|
1012
|
-
|
|
1636
|
+
if (args?.resourceId) {
|
|
1637
|
+
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1013
1638
|
}
|
|
1014
|
-
if (args?.
|
|
1015
|
-
|
|
1639
|
+
if (args?.fromDate instanceof Date) {
|
|
1640
|
+
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1016
1641
|
}
|
|
1017
|
-
if (args?.
|
|
1018
|
-
|
|
1642
|
+
if (args?.toDate instanceof Date) {
|
|
1643
|
+
conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1019
1644
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1645
|
+
let total = 0;
|
|
1646
|
+
if (conditions.length > 0) {
|
|
1647
|
+
query = query.where(conditions.join(" AND "));
|
|
1648
|
+
total = await table.countRows(conditions.join(" AND "));
|
|
1649
|
+
} else {
|
|
1650
|
+
total = await table.countRows();
|
|
1651
|
+
}
|
|
1652
|
+
if (args?.perPage !== void 0 && args?.page !== void 0) {
|
|
1653
|
+
const normalizedPerPage = normalizePerPage(args.perPage, Number.MAX_SAFE_INTEGER);
|
|
1654
|
+
if (args.page < 0 || !Number.isInteger(args.page)) {
|
|
1655
|
+
throw new MastraError(
|
|
1656
|
+
{
|
|
1657
|
+
id: "LANCE_STORE_INVALID_PAGINATION_PARAMS",
|
|
1658
|
+
domain: ErrorDomain.STORAGE,
|
|
1659
|
+
category: ErrorCategory.USER,
|
|
1660
|
+
details: { page: args.page, perPage: args.perPage }
|
|
1661
|
+
},
|
|
1662
|
+
new Error(`Invalid pagination parameters: page=${args.page}, perPage=${args.perPage}`)
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
const offset = args.page * normalizedPerPage;
|
|
1666
|
+
query.limit(normalizedPerPage);
|
|
1667
|
+
query.offset(offset);
|
|
1022
1668
|
}
|
|
1023
1669
|
const records = await query.toArray();
|
|
1024
1670
|
return {
|
|
1025
|
-
runs: records.map((record) =>
|
|
1026
|
-
total: records.length
|
|
1671
|
+
runs: records.map((record) => parseWorkflowRun(record)),
|
|
1672
|
+
total: total || records.length
|
|
1027
1673
|
};
|
|
1028
1674
|
} catch (error) {
|
|
1029
1675
|
throw new MastraError(
|
|
1030
1676
|
{
|
|
1031
|
-
id: "
|
|
1677
|
+
id: "LANCE_STORE_LIST_WORKFLOW_RUNS_FAILED",
|
|
1032
1678
|
domain: ErrorDomain.STORAGE,
|
|
1033
1679
|
category: ErrorCategory.THIRD_PARTY,
|
|
1034
|
-
details: {
|
|
1680
|
+
details: { resourceId: args?.resourceId ?? "", workflowName: args?.workflowName ?? "" }
|
|
1035
1681
|
},
|
|
1036
1682
|
error
|
|
1037
1683
|
);
|
|
1038
1684
|
}
|
|
1039
1685
|
}
|
|
1686
|
+
};
|
|
1687
|
+
|
|
1688
|
+
// src/storage/index.ts
|
|
1689
|
+
var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
1690
|
+
stores;
|
|
1691
|
+
lanceClient;
|
|
1692
|
+
/**
|
|
1693
|
+
* Creates a new instance of LanceStorage
|
|
1694
|
+
* @param id The unique identifier for this storage instance
|
|
1695
|
+
* @param name The name for this storage instance
|
|
1696
|
+
* @param uri The URI to connect to LanceDB
|
|
1697
|
+
* @param options connection options
|
|
1698
|
+
*
|
|
1699
|
+
* Usage:
|
|
1700
|
+
*
|
|
1701
|
+
* Connect to a local database
|
|
1702
|
+
* ```ts
|
|
1703
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db');
|
|
1704
|
+
* ```
|
|
1705
|
+
*
|
|
1706
|
+
* Connect to a LanceDB cloud database
|
|
1707
|
+
* ```ts
|
|
1708
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', 'db://host:port');
|
|
1709
|
+
* ```
|
|
1710
|
+
*
|
|
1711
|
+
* Connect to a cloud database
|
|
1712
|
+
* ```ts
|
|
1713
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', 's3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
1714
|
+
* ```
|
|
1715
|
+
*/
|
|
1716
|
+
static async create(id, name, uri, options) {
|
|
1717
|
+
const instance = new _LanceStorage(id, name);
|
|
1718
|
+
try {
|
|
1719
|
+
instance.lanceClient = await connect(uri, options);
|
|
1720
|
+
const operations = new StoreOperationsLance({ client: instance.lanceClient });
|
|
1721
|
+
instance.stores = {
|
|
1722
|
+
operations: new StoreOperationsLance({ client: instance.lanceClient }),
|
|
1723
|
+
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1724
|
+
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1725
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient, operations })
|
|
1726
|
+
};
|
|
1727
|
+
return instance;
|
|
1728
|
+
} catch (e) {
|
|
1729
|
+
throw new MastraError(
|
|
1730
|
+
{
|
|
1731
|
+
id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
|
|
1732
|
+
domain: ErrorDomain.STORAGE,
|
|
1733
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1734
|
+
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1735
|
+
details: { uri, optionsProvided: !!options }
|
|
1736
|
+
},
|
|
1737
|
+
e
|
|
1738
|
+
);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* @internal
|
|
1743
|
+
* Private constructor to enforce using the create factory method
|
|
1744
|
+
*/
|
|
1745
|
+
constructor(id, name) {
|
|
1746
|
+
super({ id, name });
|
|
1747
|
+
const operations = new StoreOperationsLance({ client: this.lanceClient });
|
|
1748
|
+
this.stores = {
|
|
1749
|
+
operations: new StoreOperationsLance({ client: this.lanceClient }),
|
|
1750
|
+
workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
|
|
1751
|
+
scores: new StoreScoresLance({ client: this.lanceClient }),
|
|
1752
|
+
memory: new StoreMemoryLance({ client: this.lanceClient, operations })
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
async createTable({
|
|
1756
|
+
tableName,
|
|
1757
|
+
schema
|
|
1758
|
+
}) {
|
|
1759
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
1760
|
+
}
|
|
1761
|
+
async dropTable({ tableName }) {
|
|
1762
|
+
return this.stores.operations.dropTable({ tableName });
|
|
1763
|
+
}
|
|
1764
|
+
async alterTable({
|
|
1765
|
+
tableName,
|
|
1766
|
+
schema,
|
|
1767
|
+
ifNotExists
|
|
1768
|
+
}) {
|
|
1769
|
+
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
1770
|
+
}
|
|
1771
|
+
async clearTable({ tableName }) {
|
|
1772
|
+
return this.stores.operations.clearTable({ tableName });
|
|
1773
|
+
}
|
|
1774
|
+
async insert({ tableName, record }) {
|
|
1775
|
+
return this.stores.operations.insert({ tableName, record });
|
|
1776
|
+
}
|
|
1777
|
+
async batchInsert({ tableName, records }) {
|
|
1778
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
1779
|
+
}
|
|
1780
|
+
async load({ tableName, keys }) {
|
|
1781
|
+
return this.stores.operations.load({ tableName, keys });
|
|
1782
|
+
}
|
|
1783
|
+
async getThreadById({ threadId }) {
|
|
1784
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
1788
|
+
* @param thread - The thread to save
|
|
1789
|
+
* @returns The saved thread
|
|
1790
|
+
*/
|
|
1791
|
+
async saveThread({ thread }) {
|
|
1792
|
+
return this.stores.memory.saveThread({ thread });
|
|
1793
|
+
}
|
|
1794
|
+
async updateThread({
|
|
1795
|
+
id,
|
|
1796
|
+
title,
|
|
1797
|
+
metadata
|
|
1798
|
+
}) {
|
|
1799
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
1800
|
+
}
|
|
1801
|
+
async deleteThread({ threadId }) {
|
|
1802
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
1803
|
+
}
|
|
1804
|
+
get supports() {
|
|
1805
|
+
return {
|
|
1806
|
+
selectByIncludeResourceScope: true,
|
|
1807
|
+
resourceWorkingMemory: true,
|
|
1808
|
+
hasColumn: true,
|
|
1809
|
+
createTable: true,
|
|
1810
|
+
deleteMessages: false,
|
|
1811
|
+
listScoresBySpan: true
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
async getResourceById({ resourceId }) {
|
|
1815
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
1816
|
+
}
|
|
1817
|
+
async saveResource({ resource }) {
|
|
1818
|
+
return this.stores.memory.saveResource({ resource });
|
|
1819
|
+
}
|
|
1820
|
+
async updateResource({
|
|
1821
|
+
resourceId,
|
|
1822
|
+
workingMemory,
|
|
1823
|
+
metadata
|
|
1824
|
+
}) {
|
|
1825
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
1826
|
+
}
|
|
1040
1827
|
/**
|
|
1041
|
-
*
|
|
1042
|
-
* @param
|
|
1043
|
-
* @
|
|
1828
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
1829
|
+
* @param records - The sorted array of records to process
|
|
1830
|
+
* @param include - The array of include specifications with context parameters
|
|
1831
|
+
* @returns The processed array with context messages included
|
|
1044
1832
|
*/
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1833
|
+
processMessagesWithContext(records, include) {
|
|
1834
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
1835
|
+
if (messagesWithContext.length === 0) {
|
|
1836
|
+
return records;
|
|
1837
|
+
}
|
|
1838
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1839
|
+
records.forEach((message, index) => {
|
|
1840
|
+
messageIndexMap.set(message.id, index);
|
|
1841
|
+
});
|
|
1842
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
1843
|
+
for (const item of messagesWithContext) {
|
|
1844
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
1845
|
+
if (messageIndex !== void 0) {
|
|
1846
|
+
if (item.withPreviousMessages) {
|
|
1847
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
1848
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
1849
|
+
additionalIndices.add(i);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
if (item.withNextMessages) {
|
|
1853
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
1854
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
1855
|
+
additionalIndices.add(i);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1051
1858
|
}
|
|
1052
|
-
const query = table.query().where(whereClause);
|
|
1053
|
-
const records = await query.toArray();
|
|
1054
|
-
if (records.length === 0) return null;
|
|
1055
|
-
const record = records[0];
|
|
1056
|
-
return this.parseWorkflowRun(record);
|
|
1057
|
-
} catch (error) {
|
|
1058
|
-
throw new MastraError(
|
|
1059
|
-
{
|
|
1060
|
-
id: "LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
1061
|
-
domain: ErrorDomain.STORAGE,
|
|
1062
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1063
|
-
details: { runId: args.runId, workflowName: args.workflowName ?? "" }
|
|
1064
|
-
},
|
|
1065
|
-
error
|
|
1066
|
-
);
|
|
1067
1859
|
}
|
|
1860
|
+
if (additionalIndices.size === 0) {
|
|
1861
|
+
return records;
|
|
1862
|
+
}
|
|
1863
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1864
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
1865
|
+
records.forEach((record, index) => {
|
|
1866
|
+
if (originalMatchIds.has(record.id)) {
|
|
1867
|
+
allIndices.add(index);
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
additionalIndices.forEach((index) => {
|
|
1871
|
+
allIndices.add(index);
|
|
1872
|
+
});
|
|
1873
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
1874
|
+
}
|
|
1875
|
+
async listMessagesById({ messageIds }) {
|
|
1876
|
+
return this.stores.memory.listMessagesById({ messageIds });
|
|
1877
|
+
}
|
|
1878
|
+
async saveMessages(args) {
|
|
1879
|
+
return this.stores.memory.saveMessages(args);
|
|
1880
|
+
}
|
|
1881
|
+
async updateMessages(_args) {
|
|
1882
|
+
return this.stores.memory.updateMessages(_args);
|
|
1883
|
+
}
|
|
1884
|
+
async listWorkflowRuns(args) {
|
|
1885
|
+
return this.stores.workflows.listWorkflowRuns(args);
|
|
1886
|
+
}
|
|
1887
|
+
async getWorkflowRunById(args) {
|
|
1888
|
+
return this.stores.workflows.getWorkflowRunById(args);
|
|
1889
|
+
}
|
|
1890
|
+
async updateWorkflowResults({
|
|
1891
|
+
workflowName,
|
|
1892
|
+
runId,
|
|
1893
|
+
stepId,
|
|
1894
|
+
result,
|
|
1895
|
+
requestContext
|
|
1896
|
+
}) {
|
|
1897
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
1898
|
+
}
|
|
1899
|
+
async updateWorkflowState({
|
|
1900
|
+
workflowName,
|
|
1901
|
+
runId,
|
|
1902
|
+
opts
|
|
1903
|
+
}) {
|
|
1904
|
+
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
1068
1905
|
}
|
|
1069
1906
|
async persistWorkflowSnapshot({
|
|
1070
1907
|
workflowName,
|
|
1071
1908
|
runId,
|
|
1909
|
+
resourceId,
|
|
1072
1910
|
snapshot
|
|
1073
1911
|
}) {
|
|
1074
|
-
|
|
1075
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1076
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1077
|
-
const records = await query.toArray();
|
|
1078
|
-
let createdAt;
|
|
1079
|
-
const now = Date.now();
|
|
1080
|
-
if (records.length > 0) {
|
|
1081
|
-
createdAt = records[0].createdAt ?? now;
|
|
1082
|
-
} else {
|
|
1083
|
-
createdAt = now;
|
|
1084
|
-
}
|
|
1085
|
-
const record = {
|
|
1086
|
-
workflow_name: workflowName,
|
|
1087
|
-
run_id: runId,
|
|
1088
|
-
snapshot: JSON.stringify(snapshot),
|
|
1089
|
-
createdAt,
|
|
1090
|
-
updatedAt: now
|
|
1091
|
-
};
|
|
1092
|
-
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1093
|
-
} catch (error) {
|
|
1094
|
-
throw new MastraError(
|
|
1095
|
-
{
|
|
1096
|
-
id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
1097
|
-
domain: ErrorDomain.STORAGE,
|
|
1098
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1099
|
-
details: { workflowName, runId }
|
|
1100
|
-
},
|
|
1101
|
-
error
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1912
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
1104
1913
|
}
|
|
1105
1914
|
async loadWorkflowSnapshot({
|
|
1106
1915
|
workflowName,
|
|
1107
1916
|
runId
|
|
1108
1917
|
}) {
|
|
1109
|
-
|
|
1110
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1111
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1112
|
-
const records = await query.toArray();
|
|
1113
|
-
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1114
|
-
} catch (error) {
|
|
1115
|
-
throw new MastraError(
|
|
1116
|
-
{
|
|
1117
|
-
id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
1118
|
-
domain: ErrorDomain.STORAGE,
|
|
1119
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1120
|
-
details: { workflowName, runId }
|
|
1121
|
-
},
|
|
1122
|
-
error
|
|
1123
|
-
);
|
|
1124
|
-
}
|
|
1918
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
1125
1919
|
}
|
|
1126
|
-
async
|
|
1127
|
-
|
|
1128
|
-
{
|
|
1129
|
-
id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
1130
|
-
domain: ErrorDomain.STORAGE,
|
|
1131
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1132
|
-
},
|
|
1133
|
-
"Method not implemented."
|
|
1134
|
-
);
|
|
1920
|
+
async getScoreById({ id: _id }) {
|
|
1921
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
1135
1922
|
}
|
|
1136
|
-
async
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
);
|
|
1923
|
+
async listScoresByScorerId({
|
|
1924
|
+
scorerId,
|
|
1925
|
+
source,
|
|
1926
|
+
entityId,
|
|
1927
|
+
entityType,
|
|
1928
|
+
pagination
|
|
1929
|
+
}) {
|
|
1930
|
+
return this.stores.scores.listScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
|
|
1145
1931
|
}
|
|
1146
|
-
async
|
|
1147
|
-
|
|
1148
|
-
{
|
|
1149
|
-
id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
|
|
1150
|
-
domain: ErrorDomain.STORAGE,
|
|
1151
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1152
|
-
},
|
|
1153
|
-
"Method not implemented."
|
|
1154
|
-
);
|
|
1932
|
+
async saveScore(_score) {
|
|
1933
|
+
return this.stores.scores.saveScore(_score);
|
|
1155
1934
|
}
|
|
1156
|
-
async
|
|
1157
|
-
|
|
1158
|
-
|
|
1935
|
+
async listScoresByRunId({
|
|
1936
|
+
runId,
|
|
1937
|
+
pagination
|
|
1938
|
+
}) {
|
|
1939
|
+
return this.stores.scores.listScoresByRunId({ runId, pagination });
|
|
1940
|
+
}
|
|
1941
|
+
async listScoresByEntityId({
|
|
1942
|
+
entityId,
|
|
1943
|
+
entityType,
|
|
1944
|
+
pagination
|
|
1945
|
+
}) {
|
|
1946
|
+
return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
|
|
1947
|
+
}
|
|
1948
|
+
async listScoresBySpan({
|
|
1949
|
+
traceId,
|
|
1950
|
+
spanId,
|
|
1951
|
+
pagination
|
|
1952
|
+
}) {
|
|
1953
|
+
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
1159
1954
|
}
|
|
1160
1955
|
};
|
|
1161
1956
|
var LanceFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -1504,7 +2299,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1504
2299
|
* ```
|
|
1505
2300
|
*/
|
|
1506
2301
|
static async create(uri, options) {
|
|
1507
|
-
const instance = new _LanceVectorStore();
|
|
2302
|
+
const instance = new _LanceVectorStore(options?.id || crypto.randomUUID());
|
|
1508
2303
|
try {
|
|
1509
2304
|
instance.lanceClient = await connect(uri, options);
|
|
1510
2305
|
return instance;
|
|
@@ -1524,8 +2319,8 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1524
2319
|
* @internal
|
|
1525
2320
|
* Private constructor to enforce using the create factory method
|
|
1526
2321
|
*/
|
|
1527
|
-
constructor() {
|
|
1528
|
-
super();
|
|
2322
|
+
constructor(id) {
|
|
2323
|
+
super({ id });
|
|
1529
2324
|
}
|
|
1530
2325
|
close() {
|
|
1531
2326
|
if (this.lanceClient) {
|
|
@@ -2048,7 +2843,44 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2048
2843
|
);
|
|
2049
2844
|
}
|
|
2050
2845
|
}
|
|
2051
|
-
async updateVector(
|
|
2846
|
+
async updateVector(params) {
|
|
2847
|
+
const { indexName, update } = params;
|
|
2848
|
+
if ("id" in params && "filter" in params && params.id && params.filter) {
|
|
2849
|
+
throw new MastraError({
|
|
2850
|
+
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
|
|
2851
|
+
domain: ErrorDomain.STORAGE,
|
|
2852
|
+
category: ErrorCategory.USER,
|
|
2853
|
+
text: "id and filter are mutually exclusive",
|
|
2854
|
+
details: { indexName }
|
|
2855
|
+
});
|
|
2856
|
+
}
|
|
2857
|
+
if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
|
|
2858
|
+
throw new MastraError({
|
|
2859
|
+
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
|
|
2860
|
+
domain: ErrorDomain.STORAGE,
|
|
2861
|
+
category: ErrorCategory.USER,
|
|
2862
|
+
text: "Either id or filter must be provided",
|
|
2863
|
+
details: { indexName }
|
|
2864
|
+
});
|
|
2865
|
+
}
|
|
2866
|
+
if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
|
|
2867
|
+
throw new MastraError({
|
|
2868
|
+
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
|
|
2869
|
+
domain: ErrorDomain.STORAGE,
|
|
2870
|
+
category: ErrorCategory.USER,
|
|
2871
|
+
text: "Cannot update with empty filter",
|
|
2872
|
+
details: { indexName }
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
if (!update.vector && !update.metadata) {
|
|
2876
|
+
throw new MastraError({
|
|
2877
|
+
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
|
|
2878
|
+
domain: ErrorDomain.STORAGE,
|
|
2879
|
+
category: ErrorCategory.USER,
|
|
2880
|
+
text: "No updates provided",
|
|
2881
|
+
details: { indexName }
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2052
2884
|
try {
|
|
2053
2885
|
if (!this.lanceClient) {
|
|
2054
2886
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
@@ -2056,21 +2888,6 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2056
2888
|
if (!indexName) {
|
|
2057
2889
|
throw new Error("indexName is required");
|
|
2058
2890
|
}
|
|
2059
|
-
if (!id) {
|
|
2060
|
-
throw new Error("id is required");
|
|
2061
|
-
}
|
|
2062
|
-
} catch (err) {
|
|
2063
|
-
throw new MastraError(
|
|
2064
|
-
{
|
|
2065
|
-
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
|
|
2066
|
-
domain: ErrorDomain.STORAGE,
|
|
2067
|
-
category: ErrorCategory.USER,
|
|
2068
|
-
details: { indexName, id }
|
|
2069
|
-
},
|
|
2070
|
-
err
|
|
2071
|
-
);
|
|
2072
|
-
}
|
|
2073
|
-
try {
|
|
2074
2891
|
const tables = await this.lanceClient.tableNames();
|
|
2075
2892
|
for (const tableName of tables) {
|
|
2076
2893
|
this.logger.debug("Checking table:" + tableName);
|
|
@@ -2080,39 +2897,66 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2080
2897
|
const hasColumn = schema.fields.some((field) => field.name === indexName);
|
|
2081
2898
|
if (hasColumn) {
|
|
2082
2899
|
this.logger.debug(`Found column ${indexName} in table ${tableName}`);
|
|
2083
|
-
|
|
2084
|
-
if (
|
|
2085
|
-
|
|
2900
|
+
let whereClause;
|
|
2901
|
+
if ("id" in params && params.id) {
|
|
2902
|
+
whereClause = `id = '${params.id}'`;
|
|
2903
|
+
} else if ("filter" in params && params.filter) {
|
|
2904
|
+
const translator = new LanceFilterTranslator();
|
|
2905
|
+
const processFilterKeys = (filter) => {
|
|
2906
|
+
const processedFilter = {};
|
|
2907
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
2908
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
2909
|
+
Object.entries(value).forEach(([nestedKey, nestedValue]) => {
|
|
2910
|
+
processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
|
|
2911
|
+
});
|
|
2912
|
+
} else {
|
|
2913
|
+
processedFilter[`metadata_${key}`] = value;
|
|
2914
|
+
}
|
|
2915
|
+
});
|
|
2916
|
+
return processedFilter;
|
|
2917
|
+
};
|
|
2918
|
+
const prefixedFilter = processFilterKeys(params.filter);
|
|
2919
|
+
whereClause = translator.translate(prefixedFilter) || "";
|
|
2920
|
+
if (!whereClause) {
|
|
2921
|
+
throw new Error("Failed to translate filter to SQL");
|
|
2922
|
+
}
|
|
2923
|
+
} else {
|
|
2924
|
+
throw new Error("Either id or filter must be provided");
|
|
2086
2925
|
}
|
|
2087
|
-
const
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2926
|
+
const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
|
|
2927
|
+
if (existingRecords.length === 0) {
|
|
2928
|
+
this.logger.info(`No records found matching criteria in table ${tableName}`);
|
|
2929
|
+
return;
|
|
2930
|
+
}
|
|
2931
|
+
const updatedRecords = existingRecords.map((record) => {
|
|
2932
|
+
const rowData = {};
|
|
2933
|
+
Object.entries(record).forEach(([key, value]) => {
|
|
2934
|
+
if (key !== "_distance") {
|
|
2935
|
+
if (key === indexName) {
|
|
2936
|
+
if (update.vector) {
|
|
2937
|
+
rowData[key] = update.vector;
|
|
2098
2938
|
} else {
|
|
2099
|
-
|
|
2939
|
+
if (Array.isArray(value)) {
|
|
2940
|
+
rowData[key] = [...value];
|
|
2941
|
+
} else if (typeof value === "object" && value !== null) {
|
|
2942
|
+
rowData[key] = Array.from(value);
|
|
2943
|
+
} else {
|
|
2944
|
+
rowData[key] = value;
|
|
2945
|
+
}
|
|
2100
2946
|
}
|
|
2947
|
+
} else {
|
|
2948
|
+
rowData[key] = value;
|
|
2101
2949
|
}
|
|
2102
|
-
} else {
|
|
2103
|
-
rowData[key] = value;
|
|
2104
2950
|
}
|
|
2951
|
+
});
|
|
2952
|
+
if (update.metadata) {
|
|
2953
|
+
Object.entries(update.metadata).forEach(([key, value]) => {
|
|
2954
|
+
rowData[`metadata_${key}`] = value;
|
|
2955
|
+
});
|
|
2105
2956
|
}
|
|
2957
|
+
return rowData;
|
|
2106
2958
|
});
|
|
2107
|
-
|
|
2108
|
-
rowData[indexName] = update.vector;
|
|
2109
|
-
}
|
|
2110
|
-
if (update.metadata) {
|
|
2111
|
-
Object.entries(update.metadata).forEach(([key, value]) => {
|
|
2112
|
-
rowData[`metadata_${key}`] = value;
|
|
2113
|
-
});
|
|
2114
|
-
}
|
|
2115
|
-
await table.add([rowData], { mode: "overwrite" });
|
|
2959
|
+
await table.add(updatedRecords, { mode: "overwrite" });
|
|
2116
2960
|
return;
|
|
2117
2961
|
}
|
|
2118
2962
|
} catch (err) {
|
|
@@ -2122,12 +2966,19 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2122
2966
|
}
|
|
2123
2967
|
throw new Error(`No table found with column/index '${indexName}'`);
|
|
2124
2968
|
} catch (error) {
|
|
2969
|
+
if (error instanceof MastraError) throw error;
|
|
2125
2970
|
throw new MastraError(
|
|
2126
2971
|
{
|
|
2127
2972
|
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
|
|
2128
2973
|
domain: ErrorDomain.STORAGE,
|
|
2129
2974
|
category: ErrorCategory.THIRD_PARTY,
|
|
2130
|
-
details: {
|
|
2975
|
+
details: {
|
|
2976
|
+
indexName,
|
|
2977
|
+
..."id" in params && params.id && { id: params.id },
|
|
2978
|
+
..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
|
|
2979
|
+
hasVector: !!update.vector,
|
|
2980
|
+
hasMetadata: !!update.metadata
|
|
2981
|
+
}
|
|
2131
2982
|
},
|
|
2132
2983
|
error
|
|
2133
2984
|
);
|
|
@@ -2150,7 +3001,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2150
3001
|
id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
|
|
2151
3002
|
domain: ErrorDomain.STORAGE,
|
|
2152
3003
|
category: ErrorCategory.USER,
|
|
2153
|
-
details: {
|
|
3004
|
+
details: {
|
|
3005
|
+
indexName,
|
|
3006
|
+
...id && { id }
|
|
3007
|
+
}
|
|
2154
3008
|
},
|
|
2155
3009
|
err
|
|
2156
3010
|
);
|
|
@@ -2180,7 +3034,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2180
3034
|
id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
|
|
2181
3035
|
domain: ErrorDomain.STORAGE,
|
|
2182
3036
|
category: ErrorCategory.THIRD_PARTY,
|
|
2183
|
-
details: {
|
|
3037
|
+
details: {
|
|
3038
|
+
indexName,
|
|
3039
|
+
...id && { id }
|
|
3040
|
+
}
|
|
2184
3041
|
},
|
|
2185
3042
|
error
|
|
2186
3043
|
);
|
|
@@ -2211,6 +3068,111 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2211
3068
|
});
|
|
2212
3069
|
return result;
|
|
2213
3070
|
}
|
|
3071
|
+
async deleteVectors({ indexName, filter, ids }) {
|
|
3072
|
+
if (ids && filter) {
|
|
3073
|
+
throw new MastraError({
|
|
3074
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
|
|
3075
|
+
domain: ErrorDomain.STORAGE,
|
|
3076
|
+
category: ErrorCategory.USER,
|
|
3077
|
+
text: "ids and filter are mutually exclusive",
|
|
3078
|
+
details: { indexName }
|
|
3079
|
+
});
|
|
3080
|
+
}
|
|
3081
|
+
if (!ids && !filter) {
|
|
3082
|
+
throw new MastraError({
|
|
3083
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
|
|
3084
|
+
domain: ErrorDomain.STORAGE,
|
|
3085
|
+
category: ErrorCategory.USER,
|
|
3086
|
+
text: "Either filter or ids must be provided",
|
|
3087
|
+
details: { indexName }
|
|
3088
|
+
});
|
|
3089
|
+
}
|
|
3090
|
+
if (ids && ids.length === 0) {
|
|
3091
|
+
throw new MastraError({
|
|
3092
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
|
|
3093
|
+
domain: ErrorDomain.STORAGE,
|
|
3094
|
+
category: ErrorCategory.USER,
|
|
3095
|
+
text: "Cannot delete with empty ids array",
|
|
3096
|
+
details: { indexName }
|
|
3097
|
+
});
|
|
3098
|
+
}
|
|
3099
|
+
if (filter && Object.keys(filter).length === 0) {
|
|
3100
|
+
throw new MastraError({
|
|
3101
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
|
|
3102
|
+
domain: ErrorDomain.STORAGE,
|
|
3103
|
+
category: ErrorCategory.USER,
|
|
3104
|
+
text: "Cannot delete with empty filter",
|
|
3105
|
+
details: { indexName }
|
|
3106
|
+
});
|
|
3107
|
+
}
|
|
3108
|
+
try {
|
|
3109
|
+
if (!this.lanceClient) {
|
|
3110
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
3111
|
+
}
|
|
3112
|
+
if (!indexName) {
|
|
3113
|
+
throw new Error("indexName is required");
|
|
3114
|
+
}
|
|
3115
|
+
const tables = await this.lanceClient.tableNames();
|
|
3116
|
+
for (const tableName of tables) {
|
|
3117
|
+
this.logger.debug("Checking table:" + tableName);
|
|
3118
|
+
const table = await this.lanceClient.openTable(tableName);
|
|
3119
|
+
try {
|
|
3120
|
+
const schema = await table.schema();
|
|
3121
|
+
const hasColumn = schema.fields.some((field) => field.name === indexName);
|
|
3122
|
+
if (hasColumn) {
|
|
3123
|
+
this.logger.debug(`Found column ${indexName} in table ${tableName}`);
|
|
3124
|
+
if (ids) {
|
|
3125
|
+
const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
|
|
3126
|
+
await table.delete(idsConditions);
|
|
3127
|
+
} else if (filter) {
|
|
3128
|
+
const translator = new LanceFilterTranslator();
|
|
3129
|
+
const processFilterKeys = (filter2) => {
|
|
3130
|
+
const processedFilter = {};
|
|
3131
|
+
Object.entries(filter2).forEach(([key, value]) => {
|
|
3132
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3133
|
+
Object.entries(value).forEach(([nestedKey, nestedValue]) => {
|
|
3134
|
+
processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
|
|
3135
|
+
});
|
|
3136
|
+
} else {
|
|
3137
|
+
processedFilter[`metadata_${key}`] = value;
|
|
3138
|
+
}
|
|
3139
|
+
});
|
|
3140
|
+
return processedFilter;
|
|
3141
|
+
};
|
|
3142
|
+
const prefixedFilter = processFilterKeys(filter);
|
|
3143
|
+
const whereClause = translator.translate(prefixedFilter);
|
|
3144
|
+
if (!whereClause) {
|
|
3145
|
+
throw new Error("Failed to translate filter to SQL");
|
|
3146
|
+
}
|
|
3147
|
+
await table.delete(whereClause);
|
|
3148
|
+
}
|
|
3149
|
+
return;
|
|
3150
|
+
}
|
|
3151
|
+
} catch (err) {
|
|
3152
|
+
this.logger.error(`Error checking schema for table ${tableName}:` + err);
|
|
3153
|
+
continue;
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
throw new Error(`No table found with column/index '${indexName}'`);
|
|
3157
|
+
} catch (error) {
|
|
3158
|
+
if (error instanceof MastraError) throw error;
|
|
3159
|
+
throw new MastraError(
|
|
3160
|
+
{
|
|
3161
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_FAILED",
|
|
3162
|
+
domain: ErrorDomain.STORAGE,
|
|
3163
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3164
|
+
details: {
|
|
3165
|
+
indexName,
|
|
3166
|
+
...filter && { filter: JSON.stringify(filter) },
|
|
3167
|
+
...ids && { idsCount: ids.length }
|
|
3168
|
+
}
|
|
3169
|
+
},
|
|
3170
|
+
error
|
|
3171
|
+
);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
2214
3174
|
};
|
|
2215
3175
|
|
|
2216
3176
|
export { LanceStorage, LanceVectorStore };
|
|
3177
|
+
//# sourceMappingURL=index.js.map
|
|
3178
|
+
//# sourceMappingURL=index.js.map
|