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