@mastra/lance 0.0.0-working-memory-per-user-20250620163010 → 0.0.0-zod-v4-compat-part-2-20250822105954
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 +170 -3
- package/LICENSE.md +11 -42
- package/dist/index.cjs +2321 -695
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2286 -660
- package/dist/index.js.map +1 -0
- package/dist/storage/domains/legacy-evals/index.d.ts +25 -0
- package/dist/storage/domains/legacy-evals/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +94 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +40 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +39 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/traces/index.d.ts +34 -0
- package/dist/storage/domains/traces/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +10 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +38 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +233 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/vector/filter.d.ts +41 -0
- package/dist/vector/filter.d.ts.map +1 -0
- package/dist/vector/index.d.ts +85 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/types.d.ts +15 -0
- package/dist/vector/types.d.ts.map +1 -0
- package/package.json +9 -9
- package/src/storage/domains/legacy-evals/index.ts +156 -0
- package/src/storage/domains/memory/index.ts +947 -0
- package/src/storage/domains/operations/index.ts +489 -0
- package/src/storage/domains/scores/index.ts +221 -0
- package/src/storage/domains/traces/index.ts +212 -0
- package/src/storage/domains/utils.ts +158 -0
- package/src/storage/domains/workflows/index.ts +207 -0
- package/src/storage/index.test.ts +6 -1262
- package/src/storage/index.ts +168 -755
- package/src/vector/filter.test.ts +3 -3
- package/src/vector/filter.ts +24 -4
- package/src/vector/index.test.ts +3 -3
- package/src/vector/index.ts +320 -79
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +1 -1
- package/tsup.config.ts +22 -0
- package/dist/_tsup-dts-rollup.d.cts +0 -395
- package/dist/_tsup-dts-rollup.d.ts +0 -395
- package/dist/index.d.cts +0 -2
package/dist/index.js
CHANGED
|
@@ -1,12 +1,1877 @@
|
|
|
1
1
|
import { connect, Index } from '@lancedb/lancedb';
|
|
2
|
+
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
+
import { MastraStorage, StoreOperations, LegacyEvalsStorage, TABLE_EVALS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, resolveMessageLimit, TABLE_RESOURCES, ScoresStorage, TABLE_SCORERS, TracesStorage, TABLE_TRACES, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ensureDate } from '@mastra/core/storage';
|
|
2
4
|
import { MessageList } from '@mastra/core/agent';
|
|
3
|
-
import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_EVALS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
|
|
4
5
|
import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
|
|
5
6
|
import { MastraVector } from '@mastra/core/vector';
|
|
6
7
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
7
8
|
|
|
9
|
+
// 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
|
+
function getPrimaryKeys(tableName) {
|
|
125
|
+
let primaryId = ["id"];
|
|
126
|
+
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
127
|
+
primaryId = ["workflow_name", "run_id"];
|
|
128
|
+
} else if (tableName === TABLE_EVALS) {
|
|
129
|
+
primaryId = ["agent_name", "metric_name", "run_id"];
|
|
130
|
+
}
|
|
131
|
+
return primaryId;
|
|
132
|
+
}
|
|
133
|
+
function validateKeyTypes(keys, tableSchema) {
|
|
134
|
+
const fieldTypes = new Map(
|
|
135
|
+
tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
|
|
136
|
+
);
|
|
137
|
+
for (const [key, value] of Object.entries(keys)) {
|
|
138
|
+
const fieldType = fieldTypes.get(key);
|
|
139
|
+
if (!fieldType) {
|
|
140
|
+
throw new Error(`Field '${key}' does not exist in table schema`);
|
|
141
|
+
}
|
|
142
|
+
if (value !== null) {
|
|
143
|
+
if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
|
|
144
|
+
throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
|
|
145
|
+
}
|
|
146
|
+
if (fieldType.includes("utf8") && typeof value !== "string") {
|
|
147
|
+
throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
|
|
148
|
+
}
|
|
149
|
+
if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
|
|
150
|
+
throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function processResultWithTypeConversion(rawResult, tableSchema) {
|
|
156
|
+
const fieldTypeMap = /* @__PURE__ */ new Map();
|
|
157
|
+
tableSchema.fields.forEach((field) => {
|
|
158
|
+
const fieldName = field.name;
|
|
159
|
+
const fieldTypeStr = field.type.toString().toLowerCase();
|
|
160
|
+
fieldTypeMap.set(fieldName, fieldTypeStr);
|
|
161
|
+
});
|
|
162
|
+
if (Array.isArray(rawResult)) {
|
|
163
|
+
return rawResult.map((item) => processResultWithTypeConversion(item, tableSchema));
|
|
164
|
+
}
|
|
165
|
+
const processedResult = { ...rawResult };
|
|
166
|
+
for (const key in processedResult) {
|
|
167
|
+
const fieldTypeStr = fieldTypeMap.get(key);
|
|
168
|
+
if (!fieldTypeStr) continue;
|
|
169
|
+
if (typeof processedResult[key] === "string") {
|
|
170
|
+
if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
|
|
171
|
+
if (!isNaN(Number(processedResult[key]))) {
|
|
172
|
+
processedResult[key] = Number(processedResult[key]);
|
|
173
|
+
}
|
|
174
|
+
} else if (fieldTypeStr.includes("int64")) {
|
|
175
|
+
processedResult[key] = Number(processedResult[key]);
|
|
176
|
+
} else if (fieldTypeStr.includes("utf8") && key !== "id") {
|
|
177
|
+
try {
|
|
178
|
+
const parsed = JSON.parse(processedResult[key]);
|
|
179
|
+
if (typeof parsed === "object") {
|
|
180
|
+
processedResult[key] = JSON.parse(processedResult[key]);
|
|
181
|
+
}
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} else if (typeof processedResult[key] === "bigint") {
|
|
186
|
+
processedResult[key] = Number(processedResult[key]);
|
|
187
|
+
} else if (fieldTypeStr.includes("float64") && ["createdAt", "updatedAt"].includes(key)) {
|
|
188
|
+
processedResult[key] = new Date(processedResult[key]);
|
|
189
|
+
}
|
|
190
|
+
console.log(key, "processedResult", processedResult);
|
|
191
|
+
}
|
|
192
|
+
return processedResult;
|
|
193
|
+
}
|
|
194
|
+
async function getTableSchema({
|
|
195
|
+
tableName,
|
|
196
|
+
client
|
|
197
|
+
}) {
|
|
198
|
+
try {
|
|
199
|
+
if (!client) {
|
|
200
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
201
|
+
}
|
|
202
|
+
if (!tableName) {
|
|
203
|
+
throw new Error("tableName is required for getTableSchema.");
|
|
204
|
+
}
|
|
205
|
+
} catch (validationError) {
|
|
206
|
+
throw new MastraError(
|
|
207
|
+
{
|
|
208
|
+
id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS",
|
|
209
|
+
domain: ErrorDomain.STORAGE,
|
|
210
|
+
category: ErrorCategory.USER,
|
|
211
|
+
text: validationError.message,
|
|
212
|
+
details: { tableName }
|
|
213
|
+
},
|
|
214
|
+
validationError
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const table = await client.openTable(tableName);
|
|
219
|
+
const rawSchema = await table.schema();
|
|
220
|
+
const fields = rawSchema.fields;
|
|
221
|
+
return {
|
|
222
|
+
fields,
|
|
223
|
+
metadata: /* @__PURE__ */ new Map(),
|
|
224
|
+
get names() {
|
|
225
|
+
return fields.map((field) => field.name);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
} catch (error) {
|
|
229
|
+
throw new MastraError(
|
|
230
|
+
{
|
|
231
|
+
id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED",
|
|
232
|
+
domain: ErrorDomain.STORAGE,
|
|
233
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
234
|
+
details: { tableName }
|
|
235
|
+
},
|
|
236
|
+
error
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/storage/domains/memory/index.ts
|
|
242
|
+
var StoreMemoryLance = class extends MemoryStorage {
|
|
243
|
+
client;
|
|
244
|
+
operations;
|
|
245
|
+
constructor({ client, operations }) {
|
|
246
|
+
super();
|
|
247
|
+
this.client = client;
|
|
248
|
+
this.operations = operations;
|
|
249
|
+
}
|
|
250
|
+
async getThreadById({ threadId }) {
|
|
251
|
+
try {
|
|
252
|
+
const thread = await this.operations.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
|
|
253
|
+
if (!thread) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
...thread,
|
|
258
|
+
createdAt: new Date(thread.createdAt),
|
|
259
|
+
updatedAt: new Date(thread.updatedAt)
|
|
260
|
+
};
|
|
261
|
+
} catch (error) {
|
|
262
|
+
throw new MastraError(
|
|
263
|
+
{
|
|
264
|
+
id: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
|
|
265
|
+
domain: ErrorDomain.STORAGE,
|
|
266
|
+
category: ErrorCategory.THIRD_PARTY
|
|
267
|
+
},
|
|
268
|
+
error
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
273
|
+
try {
|
|
274
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
275
|
+
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
276
|
+
const records = await query.toArray();
|
|
277
|
+
return processResultWithTypeConversion(
|
|
278
|
+
records,
|
|
279
|
+
await getTableSchema({ tableName: TABLE_THREADS, client: this.client })
|
|
280
|
+
);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
throw new MastraError(
|
|
283
|
+
{
|
|
284
|
+
id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
285
|
+
domain: ErrorDomain.STORAGE,
|
|
286
|
+
category: ErrorCategory.THIRD_PARTY
|
|
287
|
+
},
|
|
288
|
+
error
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
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 }) {
|
|
298
|
+
try {
|
|
299
|
+
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
300
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
301
|
+
await table.add([record], { mode: "append" });
|
|
302
|
+
return thread;
|
|
303
|
+
} catch (error) {
|
|
304
|
+
throw new MastraError(
|
|
305
|
+
{
|
|
306
|
+
id: "LANCE_STORE_SAVE_THREAD_FAILED",
|
|
307
|
+
domain: ErrorDomain.STORAGE,
|
|
308
|
+
category: ErrorCategory.THIRD_PARTY
|
|
309
|
+
},
|
|
310
|
+
error
|
|
311
|
+
);
|
|
312
|
+
}
|
|
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
|
+
try {
|
|
367
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
368
|
+
await table.delete(`id = '${threadId}'`);
|
|
369
|
+
const messagesTable = await this.client.openTable(TABLE_MESSAGES);
|
|
370
|
+
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
371
|
+
} catch (error) {
|
|
372
|
+
throw new MastraError(
|
|
373
|
+
{
|
|
374
|
+
id: "LANCE_STORE_DELETE_THREAD_FAILED",
|
|
375
|
+
domain: ErrorDomain.STORAGE,
|
|
376
|
+
category: ErrorCategory.THIRD_PARTY
|
|
377
|
+
},
|
|
378
|
+
error
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
async getMessages({
|
|
383
|
+
threadId,
|
|
384
|
+
resourceId,
|
|
385
|
+
selectBy,
|
|
386
|
+
format,
|
|
387
|
+
threadConfig
|
|
388
|
+
}) {
|
|
389
|
+
try {
|
|
390
|
+
if (threadConfig) {
|
|
391
|
+
throw new Error("ThreadConfig is not supported by LanceDB storage");
|
|
392
|
+
}
|
|
393
|
+
const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
|
|
394
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
395
|
+
let allRecords = [];
|
|
396
|
+
if (selectBy?.include && selectBy.include.length > 0) {
|
|
397
|
+
const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
|
|
398
|
+
for (const threadId2 of threadIds) {
|
|
399
|
+
const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
|
|
400
|
+
let threadRecords = await threadQuery.toArray();
|
|
401
|
+
allRecords.push(...threadRecords);
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
let query = table.query().where(`\`thread_id\` = '${threadId}'`);
|
|
405
|
+
allRecords = await query.toArray();
|
|
406
|
+
}
|
|
407
|
+
allRecords.sort((a, b) => {
|
|
408
|
+
const dateA = new Date(a.createdAt).getTime();
|
|
409
|
+
const dateB = new Date(b.createdAt).getTime();
|
|
410
|
+
return dateA - dateB;
|
|
411
|
+
});
|
|
412
|
+
if (selectBy?.include && selectBy.include.length > 0) {
|
|
413
|
+
allRecords = this.processMessagesWithContext(allRecords, selectBy.include);
|
|
414
|
+
}
|
|
415
|
+
if (limit !== Number.MAX_SAFE_INTEGER) {
|
|
416
|
+
allRecords = allRecords.slice(-limit);
|
|
417
|
+
}
|
|
418
|
+
const messages = processResultWithTypeConversion(
|
|
419
|
+
allRecords,
|
|
420
|
+
await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
|
|
421
|
+
);
|
|
422
|
+
const normalized = messages.map((msg) => {
|
|
423
|
+
const { thread_id, ...rest } = msg;
|
|
424
|
+
return {
|
|
425
|
+
...rest,
|
|
426
|
+
threadId: thread_id,
|
|
427
|
+
content: typeof msg.content === "string" ? (() => {
|
|
428
|
+
try {
|
|
429
|
+
return JSON.parse(msg.content);
|
|
430
|
+
} catch {
|
|
431
|
+
return msg.content;
|
|
432
|
+
}
|
|
433
|
+
})() : msg.content
|
|
434
|
+
};
|
|
435
|
+
});
|
|
436
|
+
const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
|
|
437
|
+
if (format === "v2") return list.get.all.v2();
|
|
438
|
+
return list.get.all.v1();
|
|
439
|
+
} catch (error) {
|
|
440
|
+
throw new MastraError(
|
|
441
|
+
{
|
|
442
|
+
id: "LANCE_STORE_GET_MESSAGES_FAILED",
|
|
443
|
+
domain: ErrorDomain.STORAGE,
|
|
444
|
+
category: ErrorCategory.THIRD_PARTY
|
|
445
|
+
},
|
|
446
|
+
error
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async saveMessages(args) {
|
|
451
|
+
try {
|
|
452
|
+
const { messages, format = "v1" } = args;
|
|
453
|
+
if (messages.length === 0) {
|
|
454
|
+
return [];
|
|
455
|
+
}
|
|
456
|
+
const threadId = messages[0]?.threadId;
|
|
457
|
+
if (!threadId) {
|
|
458
|
+
throw new Error("Thread ID is required");
|
|
459
|
+
}
|
|
460
|
+
for (const message of messages) {
|
|
461
|
+
if (!message.id) {
|
|
462
|
+
throw new Error("Message ID is required");
|
|
463
|
+
}
|
|
464
|
+
if (!message.threadId) {
|
|
465
|
+
throw new Error("Thread ID is required for all messages");
|
|
466
|
+
}
|
|
467
|
+
if (message.resourceId === null || message.resourceId === void 0) {
|
|
468
|
+
throw new Error("Resource ID cannot be null or undefined");
|
|
469
|
+
}
|
|
470
|
+
if (!message.content) {
|
|
471
|
+
throw new Error("Message content is required");
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
const transformedMessages = messages.map((message) => {
|
|
475
|
+
const { threadId: threadId2, type, ...rest } = message;
|
|
476
|
+
return {
|
|
477
|
+
...rest,
|
|
478
|
+
thread_id: threadId2,
|
|
479
|
+
type: type ?? "v2",
|
|
480
|
+
content: JSON.stringify(message.content)
|
|
481
|
+
};
|
|
482
|
+
});
|
|
483
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
484
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
485
|
+
const threadsTable = await this.client.openTable(TABLE_THREADS);
|
|
486
|
+
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
487
|
+
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
488
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
489
|
+
const list = new MessageList().add(messages, "memory");
|
|
490
|
+
if (format === `v2`) return list.get.all.v2();
|
|
491
|
+
return list.get.all.v1();
|
|
492
|
+
} catch (error) {
|
|
493
|
+
throw new MastraError(
|
|
494
|
+
{
|
|
495
|
+
id: "LANCE_STORE_SAVE_MESSAGES_FAILED",
|
|
496
|
+
domain: ErrorDomain.STORAGE,
|
|
497
|
+
category: ErrorCategory.THIRD_PARTY
|
|
498
|
+
},
|
|
499
|
+
error
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
504
|
+
try {
|
|
505
|
+
const { resourceId, page = 0, perPage = 10 } = args;
|
|
506
|
+
const table = await this.client.openTable(TABLE_THREADS);
|
|
507
|
+
const total = await table.countRows(`\`resourceId\` = '${resourceId}'`);
|
|
508
|
+
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
509
|
+
const offset = page * perPage;
|
|
510
|
+
query.limit(perPage);
|
|
511
|
+
if (offset > 0) {
|
|
512
|
+
query.offset(offset);
|
|
513
|
+
}
|
|
514
|
+
const records = await query.toArray();
|
|
515
|
+
records.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
516
|
+
const schema = await getTableSchema({ tableName: TABLE_THREADS, client: this.client });
|
|
517
|
+
const threads = records.map((record) => processResultWithTypeConversion(record, schema));
|
|
518
|
+
return {
|
|
519
|
+
threads,
|
|
520
|
+
total,
|
|
521
|
+
page,
|
|
522
|
+
perPage,
|
|
523
|
+
hasMore: total > (page + 1) * perPage
|
|
524
|
+
};
|
|
525
|
+
} catch (error) {
|
|
526
|
+
throw new MastraError(
|
|
527
|
+
{
|
|
528
|
+
id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
|
|
529
|
+
domain: ErrorDomain.STORAGE,
|
|
530
|
+
category: ErrorCategory.THIRD_PARTY
|
|
531
|
+
},
|
|
532
|
+
error
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
538
|
+
* @param records - The sorted array of records to process
|
|
539
|
+
* @param include - The array of include specifications with context parameters
|
|
540
|
+
* @returns The processed array with context messages included
|
|
541
|
+
*/
|
|
542
|
+
processMessagesWithContext(records, include) {
|
|
543
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
544
|
+
if (messagesWithContext.length === 0) {
|
|
545
|
+
return records;
|
|
546
|
+
}
|
|
547
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
548
|
+
records.forEach((message, index) => {
|
|
549
|
+
messageIndexMap.set(message.id, index);
|
|
550
|
+
});
|
|
551
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
552
|
+
for (const item of messagesWithContext) {
|
|
553
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
554
|
+
if (messageIndex !== void 0) {
|
|
555
|
+
if (item.withPreviousMessages) {
|
|
556
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
557
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
558
|
+
additionalIndices.add(i);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (item.withNextMessages) {
|
|
562
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
563
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
564
|
+
additionalIndices.add(i);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (additionalIndices.size === 0) {
|
|
570
|
+
return records;
|
|
571
|
+
}
|
|
572
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
573
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
574
|
+
records.forEach((record, index) => {
|
|
575
|
+
if (originalMatchIds.has(record.id)) {
|
|
576
|
+
allIndices.add(index);
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
additionalIndices.forEach((index) => {
|
|
580
|
+
allIndices.add(index);
|
|
581
|
+
});
|
|
582
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
583
|
+
}
|
|
584
|
+
async getMessagesPaginated(args) {
|
|
585
|
+
try {
|
|
586
|
+
const { threadId, resourceId, selectBy, format = "v1" } = args;
|
|
587
|
+
if (!threadId) {
|
|
588
|
+
throw new Error("Thread ID is required for getMessagesPaginated");
|
|
589
|
+
}
|
|
590
|
+
const page = selectBy?.pagination?.page ?? 0;
|
|
591
|
+
const perPage = selectBy?.pagination?.perPage ?? 10;
|
|
592
|
+
const dateRange = selectBy?.pagination?.dateRange;
|
|
593
|
+
const fromDate = dateRange?.start;
|
|
594
|
+
const toDate = dateRange?.end;
|
|
595
|
+
const table = await this.client.openTable(TABLE_MESSAGES);
|
|
596
|
+
const messages = [];
|
|
597
|
+
if (selectBy?.include && Array.isArray(selectBy.include)) {
|
|
598
|
+
const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
|
|
599
|
+
const allThreadMessages = [];
|
|
600
|
+
for (const threadId2 of threadIds) {
|
|
601
|
+
const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
|
|
602
|
+
let threadRecords = await threadQuery.toArray();
|
|
603
|
+
if (fromDate) threadRecords = threadRecords.filter((m) => m.createdAt >= fromDate.getTime());
|
|
604
|
+
if (toDate) threadRecords = threadRecords.filter((m) => m.createdAt <= toDate.getTime());
|
|
605
|
+
allThreadMessages.push(...threadRecords);
|
|
606
|
+
}
|
|
607
|
+
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
608
|
+
const contextMessages = this.processMessagesWithContext(allThreadMessages, selectBy.include);
|
|
609
|
+
messages.push(...contextMessages);
|
|
610
|
+
}
|
|
611
|
+
const conditions = [`thread_id = '${threadId}'`];
|
|
612
|
+
if (resourceId) {
|
|
613
|
+
conditions.push(`\`resourceId\` = '${resourceId}'`);
|
|
614
|
+
}
|
|
615
|
+
if (fromDate) {
|
|
616
|
+
conditions.push(`\`createdAt\` >= ${fromDate.getTime()}`);
|
|
617
|
+
}
|
|
618
|
+
if (toDate) {
|
|
619
|
+
conditions.push(`\`createdAt\` <= ${toDate.getTime()}`);
|
|
620
|
+
}
|
|
621
|
+
let total = 0;
|
|
622
|
+
if (conditions.length > 0) {
|
|
623
|
+
total = await table.countRows(conditions.join(" AND "));
|
|
624
|
+
} else {
|
|
625
|
+
total = await table.countRows();
|
|
626
|
+
}
|
|
627
|
+
if (total === 0 && messages.length === 0) {
|
|
628
|
+
return {
|
|
629
|
+
messages: [],
|
|
630
|
+
total: 0,
|
|
631
|
+
page,
|
|
632
|
+
perPage,
|
|
633
|
+
hasMore: false
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
const excludeIds = messages.map((m) => m.id);
|
|
637
|
+
let selectedMessages = [];
|
|
638
|
+
if (selectBy?.last && selectBy.last > 0) {
|
|
639
|
+
const query = table.query();
|
|
640
|
+
if (conditions.length > 0) {
|
|
641
|
+
query.where(conditions.join(" AND "));
|
|
642
|
+
}
|
|
643
|
+
let records = await query.toArray();
|
|
644
|
+
records = records.sort((a, b) => a.createdAt - b.createdAt);
|
|
645
|
+
if (excludeIds.length > 0) {
|
|
646
|
+
records = records.filter((m) => !excludeIds.includes(m.id));
|
|
647
|
+
}
|
|
648
|
+
selectedMessages = records.slice(-selectBy.last);
|
|
649
|
+
} else {
|
|
650
|
+
const query = table.query();
|
|
651
|
+
if (conditions.length > 0) {
|
|
652
|
+
query.where(conditions.join(" AND "));
|
|
653
|
+
}
|
|
654
|
+
let records = await query.toArray();
|
|
655
|
+
records = records.sort((a, b) => a.createdAt - b.createdAt);
|
|
656
|
+
if (excludeIds.length > 0) {
|
|
657
|
+
records = records.filter((m) => !excludeIds.includes(m.id));
|
|
658
|
+
}
|
|
659
|
+
selectedMessages = records.slice(page * perPage, (page + 1) * perPage);
|
|
660
|
+
}
|
|
661
|
+
const allMessages = [...messages, ...selectedMessages];
|
|
662
|
+
const seen = /* @__PURE__ */ new Set();
|
|
663
|
+
const dedupedMessages = allMessages.filter((m) => {
|
|
664
|
+
const key = `${m.id}:${m.thread_id}`;
|
|
665
|
+
if (seen.has(key)) return false;
|
|
666
|
+
seen.add(key);
|
|
667
|
+
return true;
|
|
668
|
+
});
|
|
669
|
+
const formattedMessages = dedupedMessages.map((msg) => {
|
|
670
|
+
const { thread_id, ...rest } = msg;
|
|
671
|
+
return {
|
|
672
|
+
...rest,
|
|
673
|
+
threadId: thread_id,
|
|
674
|
+
content: typeof msg.content === "string" ? (() => {
|
|
675
|
+
try {
|
|
676
|
+
return JSON.parse(msg.content);
|
|
677
|
+
} catch {
|
|
678
|
+
return msg.content;
|
|
679
|
+
}
|
|
680
|
+
})() : msg.content
|
|
681
|
+
};
|
|
682
|
+
});
|
|
683
|
+
const list = new MessageList().add(formattedMessages, "memory");
|
|
684
|
+
return {
|
|
685
|
+
messages: format === "v2" ? list.get.all.v2() : list.get.all.v1(),
|
|
686
|
+
total,
|
|
687
|
+
// Total should be the count of messages matching the filters
|
|
688
|
+
page,
|
|
689
|
+
perPage,
|
|
690
|
+
hasMore: total > (page + 1) * perPage
|
|
691
|
+
};
|
|
692
|
+
} catch (error) {
|
|
693
|
+
throw new MastraError(
|
|
694
|
+
{
|
|
695
|
+
id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
|
|
696
|
+
domain: ErrorDomain.STORAGE,
|
|
697
|
+
category: ErrorCategory.THIRD_PARTY
|
|
698
|
+
},
|
|
699
|
+
error
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Parse message data from LanceDB record format to MastraMessageV2 format
|
|
705
|
+
*/
|
|
706
|
+
parseMessageData(data) {
|
|
707
|
+
const { thread_id, ...rest } = data;
|
|
708
|
+
return {
|
|
709
|
+
...rest,
|
|
710
|
+
threadId: thread_id,
|
|
711
|
+
content: typeof data.content === "string" ? (() => {
|
|
712
|
+
try {
|
|
713
|
+
return JSON.parse(data.content);
|
|
714
|
+
} catch {
|
|
715
|
+
return data.content;
|
|
716
|
+
}
|
|
717
|
+
})() : data.content,
|
|
718
|
+
createdAt: new Date(data.createdAt),
|
|
719
|
+
updatedAt: new Date(data.updatedAt)
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
async updateMessages(args) {
|
|
723
|
+
const { messages } = args;
|
|
724
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
725
|
+
if (!messages.length) {
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
const updatedMessages = [];
|
|
729
|
+
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
730
|
+
try {
|
|
731
|
+
for (const updateData of messages) {
|
|
732
|
+
const { id, ...updates } = updateData;
|
|
733
|
+
const existingMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
|
|
734
|
+
if (!existingMessage) {
|
|
735
|
+
this.logger.warn("Message not found for update", { id });
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
const existingMsg = this.parseMessageData(existingMessage);
|
|
739
|
+
const originalThreadId = existingMsg.threadId;
|
|
740
|
+
affectedThreadIds.add(originalThreadId);
|
|
741
|
+
const updatePayload = {};
|
|
742
|
+
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
743
|
+
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
744
|
+
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
745
|
+
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
746
|
+
updatePayload.thread_id = updates.threadId;
|
|
747
|
+
affectedThreadIds.add(updates.threadId);
|
|
748
|
+
}
|
|
749
|
+
if (updates.content) {
|
|
750
|
+
const existingContent = existingMsg.content;
|
|
751
|
+
let newContent = { ...existingContent };
|
|
752
|
+
if (updates.content.metadata !== void 0) {
|
|
753
|
+
newContent.metadata = {
|
|
754
|
+
...existingContent.metadata || {},
|
|
755
|
+
...updates.content.metadata || {}
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
if (updates.content.content !== void 0) {
|
|
759
|
+
newContent.content = updates.content.content;
|
|
760
|
+
}
|
|
761
|
+
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
762
|
+
newContent.parts = updates.content.parts;
|
|
763
|
+
}
|
|
764
|
+
updatePayload.content = JSON.stringify(newContent);
|
|
765
|
+
}
|
|
766
|
+
await this.operations.insert({ tableName: TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
767
|
+
const updatedMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
|
|
768
|
+
if (updatedMessage) {
|
|
769
|
+
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
for (const threadId of affectedThreadIds) {
|
|
773
|
+
await this.operations.insert({
|
|
774
|
+
tableName: TABLE_THREADS,
|
|
775
|
+
record: { id: threadId, updatedAt: Date.now() }
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
return updatedMessages;
|
|
779
|
+
} catch (error) {
|
|
780
|
+
throw new MastraError(
|
|
781
|
+
{
|
|
782
|
+
id: "LANCE_STORE_UPDATE_MESSAGES_FAILED",
|
|
783
|
+
domain: ErrorDomain.STORAGE,
|
|
784
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
785
|
+
details: { count: messages.length }
|
|
786
|
+
},
|
|
787
|
+
error
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
async getResourceById({ resourceId }) {
|
|
792
|
+
try {
|
|
793
|
+
const resource = await this.operations.load({ tableName: TABLE_RESOURCES, keys: { id: resourceId } });
|
|
794
|
+
if (!resource) {
|
|
795
|
+
return null;
|
|
796
|
+
}
|
|
797
|
+
let createdAt;
|
|
798
|
+
let updatedAt;
|
|
799
|
+
try {
|
|
800
|
+
if (resource.createdAt instanceof Date) {
|
|
801
|
+
createdAt = resource.createdAt;
|
|
802
|
+
} else if (typeof resource.createdAt === "string") {
|
|
803
|
+
createdAt = new Date(resource.createdAt);
|
|
804
|
+
} else if (typeof resource.createdAt === "number") {
|
|
805
|
+
createdAt = new Date(resource.createdAt);
|
|
806
|
+
} else {
|
|
807
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
808
|
+
}
|
|
809
|
+
if (isNaN(createdAt.getTime())) {
|
|
810
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
811
|
+
}
|
|
812
|
+
} catch {
|
|
813
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
814
|
+
}
|
|
815
|
+
try {
|
|
816
|
+
if (resource.updatedAt instanceof Date) {
|
|
817
|
+
updatedAt = resource.updatedAt;
|
|
818
|
+
} else if (typeof resource.updatedAt === "string") {
|
|
819
|
+
updatedAt = new Date(resource.updatedAt);
|
|
820
|
+
} else if (typeof resource.updatedAt === "number") {
|
|
821
|
+
updatedAt = new Date(resource.updatedAt);
|
|
822
|
+
} else {
|
|
823
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
824
|
+
}
|
|
825
|
+
if (isNaN(updatedAt.getTime())) {
|
|
826
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
827
|
+
}
|
|
828
|
+
} catch {
|
|
829
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
830
|
+
}
|
|
831
|
+
let workingMemory = resource.workingMemory;
|
|
832
|
+
if (workingMemory === null || workingMemory === void 0) {
|
|
833
|
+
workingMemory = void 0;
|
|
834
|
+
} else if (workingMemory === "") {
|
|
835
|
+
workingMemory = "";
|
|
836
|
+
} else if (typeof workingMemory === "object") {
|
|
837
|
+
workingMemory = JSON.stringify(workingMemory);
|
|
838
|
+
}
|
|
839
|
+
let metadata = resource.metadata;
|
|
840
|
+
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
841
|
+
metadata = void 0;
|
|
842
|
+
} else if (typeof metadata === "string") {
|
|
843
|
+
try {
|
|
844
|
+
metadata = JSON.parse(metadata);
|
|
845
|
+
} catch {
|
|
846
|
+
metadata = metadata;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return {
|
|
850
|
+
...resource,
|
|
851
|
+
createdAt,
|
|
852
|
+
updatedAt,
|
|
853
|
+
workingMemory,
|
|
854
|
+
metadata
|
|
855
|
+
};
|
|
856
|
+
} catch (error) {
|
|
857
|
+
throw new MastraError(
|
|
858
|
+
{
|
|
859
|
+
id: "LANCE_STORE_GET_RESOURCE_BY_ID_FAILED",
|
|
860
|
+
domain: ErrorDomain.STORAGE,
|
|
861
|
+
category: ErrorCategory.THIRD_PARTY
|
|
862
|
+
},
|
|
863
|
+
error
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
async saveResource({ resource }) {
|
|
868
|
+
try {
|
|
869
|
+
const record = {
|
|
870
|
+
...resource,
|
|
871
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
872
|
+
createdAt: resource.createdAt.getTime(),
|
|
873
|
+
// Store as timestamp (milliseconds)
|
|
874
|
+
updatedAt: resource.updatedAt.getTime()
|
|
875
|
+
// Store as timestamp (milliseconds)
|
|
876
|
+
};
|
|
877
|
+
const table = await this.client.openTable(TABLE_RESOURCES);
|
|
878
|
+
await table.add([record], { mode: "append" });
|
|
879
|
+
return resource;
|
|
880
|
+
} catch (error) {
|
|
881
|
+
throw new MastraError(
|
|
882
|
+
{
|
|
883
|
+
id: "LANCE_STORE_SAVE_RESOURCE_FAILED",
|
|
884
|
+
domain: ErrorDomain.STORAGE,
|
|
885
|
+
category: ErrorCategory.THIRD_PARTY
|
|
886
|
+
},
|
|
887
|
+
error
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
async updateResource({
|
|
892
|
+
resourceId,
|
|
893
|
+
workingMemory,
|
|
894
|
+
metadata
|
|
895
|
+
}) {
|
|
896
|
+
const maxRetries = 3;
|
|
897
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
898
|
+
try {
|
|
899
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
900
|
+
if (!existingResource) {
|
|
901
|
+
const newResource = {
|
|
902
|
+
id: resourceId,
|
|
903
|
+
workingMemory,
|
|
904
|
+
metadata: metadata || {},
|
|
905
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
906
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
907
|
+
};
|
|
908
|
+
return this.saveResource({ resource: newResource });
|
|
909
|
+
}
|
|
910
|
+
const updatedResource = {
|
|
911
|
+
...existingResource,
|
|
912
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
913
|
+
metadata: {
|
|
914
|
+
...existingResource.metadata,
|
|
915
|
+
...metadata
|
|
916
|
+
},
|
|
917
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
918
|
+
};
|
|
919
|
+
const record = {
|
|
920
|
+
id: resourceId,
|
|
921
|
+
workingMemory: updatedResource.workingMemory || "",
|
|
922
|
+
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
923
|
+
updatedAt: updatedResource.updatedAt.getTime()
|
|
924
|
+
// Store as timestamp (milliseconds)
|
|
925
|
+
};
|
|
926
|
+
const table = await this.client.openTable(TABLE_RESOURCES);
|
|
927
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
928
|
+
return updatedResource;
|
|
929
|
+
} catch (error) {
|
|
930
|
+
if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
931
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
932
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
throw new MastraError(
|
|
936
|
+
{
|
|
937
|
+
id: "LANCE_STORE_UPDATE_RESOURCE_FAILED",
|
|
938
|
+
domain: ErrorDomain.STORAGE,
|
|
939
|
+
category: ErrorCategory.THIRD_PARTY
|
|
940
|
+
},
|
|
941
|
+
error
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
throw new Error("Unexpected end of retry loop");
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
var StoreOperationsLance = class extends StoreOperations {
|
|
949
|
+
client;
|
|
950
|
+
constructor({ client }) {
|
|
951
|
+
super();
|
|
952
|
+
this.client = client;
|
|
953
|
+
}
|
|
954
|
+
getDefaultValue(type) {
|
|
955
|
+
switch (type) {
|
|
956
|
+
case "text":
|
|
957
|
+
return "''";
|
|
958
|
+
case "timestamp":
|
|
959
|
+
return "CURRENT_TIMESTAMP";
|
|
960
|
+
case "integer":
|
|
961
|
+
case "bigint":
|
|
962
|
+
return "0";
|
|
963
|
+
case "jsonb":
|
|
964
|
+
return "'{}'";
|
|
965
|
+
case "uuid":
|
|
966
|
+
return "''";
|
|
967
|
+
default:
|
|
968
|
+
return super.getDefaultValue(type);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
async hasColumn(tableName, columnName) {
|
|
972
|
+
const table = await this.client.openTable(tableName);
|
|
973
|
+
const schema = await table.schema();
|
|
974
|
+
return schema.fields.some((field) => field.name === columnName);
|
|
975
|
+
}
|
|
976
|
+
translateSchema(schema) {
|
|
977
|
+
const fields = Object.entries(schema).map(([name, column]) => {
|
|
978
|
+
let arrowType;
|
|
979
|
+
switch (column.type.toLowerCase()) {
|
|
980
|
+
case "text":
|
|
981
|
+
case "uuid":
|
|
982
|
+
arrowType = new Utf8();
|
|
983
|
+
break;
|
|
984
|
+
case "int":
|
|
985
|
+
case "integer":
|
|
986
|
+
arrowType = new Int32();
|
|
987
|
+
break;
|
|
988
|
+
case "bigint":
|
|
989
|
+
arrowType = new Float64();
|
|
990
|
+
break;
|
|
991
|
+
case "float":
|
|
992
|
+
arrowType = new Float32();
|
|
993
|
+
break;
|
|
994
|
+
case "jsonb":
|
|
995
|
+
case "json":
|
|
996
|
+
arrowType = new Utf8();
|
|
997
|
+
break;
|
|
998
|
+
case "binary":
|
|
999
|
+
arrowType = new Binary();
|
|
1000
|
+
break;
|
|
1001
|
+
case "timestamp":
|
|
1002
|
+
arrowType = new Float64();
|
|
1003
|
+
break;
|
|
1004
|
+
default:
|
|
1005
|
+
arrowType = new Utf8();
|
|
1006
|
+
}
|
|
1007
|
+
return new Field(name, arrowType, column.nullable ?? true);
|
|
1008
|
+
});
|
|
1009
|
+
return new Schema(fields);
|
|
1010
|
+
}
|
|
1011
|
+
async createTable({
|
|
1012
|
+
tableName,
|
|
1013
|
+
schema
|
|
1014
|
+
}) {
|
|
1015
|
+
try {
|
|
1016
|
+
if (!this.client) {
|
|
1017
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1018
|
+
}
|
|
1019
|
+
if (!tableName) {
|
|
1020
|
+
throw new Error("tableName is required for createTable.");
|
|
1021
|
+
}
|
|
1022
|
+
if (!schema) {
|
|
1023
|
+
throw new Error("schema is required for createTable.");
|
|
1024
|
+
}
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
throw new MastraError(
|
|
1027
|
+
{
|
|
1028
|
+
id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
|
|
1029
|
+
domain: ErrorDomain.STORAGE,
|
|
1030
|
+
category: ErrorCategory.USER,
|
|
1031
|
+
details: { tableName }
|
|
1032
|
+
},
|
|
1033
|
+
error
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
try {
|
|
1037
|
+
const arrowSchema = this.translateSchema(schema);
|
|
1038
|
+
await this.client.createEmptyTable(tableName, arrowSchema);
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
if (error.message?.includes("already exists")) {
|
|
1041
|
+
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
throw new MastraError(
|
|
1045
|
+
{
|
|
1046
|
+
id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
|
|
1047
|
+
domain: ErrorDomain.STORAGE,
|
|
1048
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1049
|
+
details: { tableName }
|
|
1050
|
+
},
|
|
1051
|
+
error
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
async dropTable({ tableName }) {
|
|
1056
|
+
try {
|
|
1057
|
+
if (!this.client) {
|
|
1058
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1059
|
+
}
|
|
1060
|
+
if (!tableName) {
|
|
1061
|
+
throw new Error("tableName is required for dropTable.");
|
|
1062
|
+
}
|
|
1063
|
+
} catch (validationError) {
|
|
1064
|
+
throw new MastraError(
|
|
1065
|
+
{
|
|
1066
|
+
id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
|
|
1067
|
+
domain: ErrorDomain.STORAGE,
|
|
1068
|
+
category: ErrorCategory.USER,
|
|
1069
|
+
text: validationError.message,
|
|
1070
|
+
details: { tableName }
|
|
1071
|
+
},
|
|
1072
|
+
validationError
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
try {
|
|
1076
|
+
await this.client.dropTable(tableName);
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
|
|
1079
|
+
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
throw new MastraError(
|
|
1083
|
+
{
|
|
1084
|
+
id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
|
|
1085
|
+
domain: ErrorDomain.STORAGE,
|
|
1086
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1087
|
+
details: { tableName }
|
|
1088
|
+
},
|
|
1089
|
+
error
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
async alterTable({
|
|
1094
|
+
tableName,
|
|
1095
|
+
schema,
|
|
1096
|
+
ifNotExists
|
|
1097
|
+
}) {
|
|
1098
|
+
try {
|
|
1099
|
+
if (!this.client) {
|
|
1100
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1101
|
+
}
|
|
1102
|
+
if (!tableName) {
|
|
1103
|
+
throw new Error("tableName is required for alterTable.");
|
|
1104
|
+
}
|
|
1105
|
+
if (!schema) {
|
|
1106
|
+
throw new Error("schema is required for alterTable.");
|
|
1107
|
+
}
|
|
1108
|
+
if (!ifNotExists || ifNotExists.length === 0) {
|
|
1109
|
+
this.logger.debug("No columns specified to add in alterTable, skipping.");
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
} catch (validationError) {
|
|
1113
|
+
throw new MastraError(
|
|
1114
|
+
{
|
|
1115
|
+
id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_INVALID_ARGS",
|
|
1116
|
+
domain: ErrorDomain.STORAGE,
|
|
1117
|
+
category: ErrorCategory.USER,
|
|
1118
|
+
text: validationError.message,
|
|
1119
|
+
details: { tableName }
|
|
1120
|
+
},
|
|
1121
|
+
validationError
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
try {
|
|
1125
|
+
const table = await this.client.openTable(tableName);
|
|
1126
|
+
const currentSchema = await table.schema();
|
|
1127
|
+
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
1128
|
+
const typeMap = {
|
|
1129
|
+
text: "string",
|
|
1130
|
+
integer: "int",
|
|
1131
|
+
bigint: "bigint",
|
|
1132
|
+
timestamp: "timestamp",
|
|
1133
|
+
jsonb: "string",
|
|
1134
|
+
uuid: "string"
|
|
1135
|
+
};
|
|
1136
|
+
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
1137
|
+
const colDef = schema[col];
|
|
1138
|
+
return {
|
|
1139
|
+
name: col,
|
|
1140
|
+
valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
|
|
1141
|
+
};
|
|
1142
|
+
});
|
|
1143
|
+
if (columnsToAdd.length > 0) {
|
|
1144
|
+
await table.addColumns(columnsToAdd);
|
|
1145
|
+
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
1146
|
+
}
|
|
1147
|
+
} catch (error) {
|
|
1148
|
+
throw new MastraError(
|
|
1149
|
+
{
|
|
1150
|
+
id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_FAILED",
|
|
1151
|
+
domain: ErrorDomain.STORAGE,
|
|
1152
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1153
|
+
details: { tableName }
|
|
1154
|
+
},
|
|
1155
|
+
error
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
async clearTable({ tableName }) {
|
|
1160
|
+
try {
|
|
1161
|
+
if (!this.client) {
|
|
1162
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1163
|
+
}
|
|
1164
|
+
if (!tableName) {
|
|
1165
|
+
throw new Error("tableName is required for clearTable.");
|
|
1166
|
+
}
|
|
1167
|
+
} catch (validationError) {
|
|
1168
|
+
throw new MastraError(
|
|
1169
|
+
{
|
|
1170
|
+
id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_INVALID_ARGS",
|
|
1171
|
+
domain: ErrorDomain.STORAGE,
|
|
1172
|
+
category: ErrorCategory.USER,
|
|
1173
|
+
text: validationError.message,
|
|
1174
|
+
details: { tableName }
|
|
1175
|
+
},
|
|
1176
|
+
validationError
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
try {
|
|
1180
|
+
const table = await this.client.openTable(tableName);
|
|
1181
|
+
await table.delete("1=1");
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
throw new MastraError(
|
|
1184
|
+
{
|
|
1185
|
+
id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_FAILED",
|
|
1186
|
+
domain: ErrorDomain.STORAGE,
|
|
1187
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1188
|
+
details: { tableName }
|
|
1189
|
+
},
|
|
1190
|
+
error
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
async insert({ tableName, record }) {
|
|
1195
|
+
try {
|
|
1196
|
+
if (!this.client) {
|
|
1197
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1198
|
+
}
|
|
1199
|
+
if (!tableName) {
|
|
1200
|
+
throw new Error("tableName is required for insert.");
|
|
1201
|
+
}
|
|
1202
|
+
if (!record || Object.keys(record).length === 0) {
|
|
1203
|
+
throw new Error("record is required and cannot be empty for insert.");
|
|
1204
|
+
}
|
|
1205
|
+
} catch (validationError) {
|
|
1206
|
+
throw new MastraError(
|
|
1207
|
+
{
|
|
1208
|
+
id: "STORAGE_LANCE_STORAGE_INSERT_INVALID_ARGS",
|
|
1209
|
+
domain: ErrorDomain.STORAGE,
|
|
1210
|
+
category: ErrorCategory.USER,
|
|
1211
|
+
text: validationError.message,
|
|
1212
|
+
details: { tableName }
|
|
1213
|
+
},
|
|
1214
|
+
validationError
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
try {
|
|
1218
|
+
const table = await this.client.openTable(tableName);
|
|
1219
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
1220
|
+
const processedRecord = { ...record };
|
|
1221
|
+
for (const key in processedRecord) {
|
|
1222
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
1223
|
+
this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
|
|
1224
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
console.log(await table.schema());
|
|
1228
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
1229
|
+
} catch (error) {
|
|
1230
|
+
throw new MastraError(
|
|
1231
|
+
{
|
|
1232
|
+
id: "STORAGE_LANCE_STORAGE_INSERT_FAILED",
|
|
1233
|
+
domain: ErrorDomain.STORAGE,
|
|
1234
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1235
|
+
details: { tableName }
|
|
1236
|
+
},
|
|
1237
|
+
error
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
async batchInsert({ tableName, records }) {
|
|
1242
|
+
try {
|
|
1243
|
+
if (!this.client) {
|
|
1244
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1245
|
+
}
|
|
1246
|
+
if (!tableName) {
|
|
1247
|
+
throw new Error("tableName is required for batchInsert.");
|
|
1248
|
+
}
|
|
1249
|
+
if (!records || records.length === 0) {
|
|
1250
|
+
throw new Error("records array is required and cannot be empty for batchInsert.");
|
|
1251
|
+
}
|
|
1252
|
+
} catch (validationError) {
|
|
1253
|
+
throw new MastraError(
|
|
1254
|
+
{
|
|
1255
|
+
id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_INVALID_ARGS",
|
|
1256
|
+
domain: ErrorDomain.STORAGE,
|
|
1257
|
+
category: ErrorCategory.USER,
|
|
1258
|
+
text: validationError.message,
|
|
1259
|
+
details: { tableName }
|
|
1260
|
+
},
|
|
1261
|
+
validationError
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
try {
|
|
1265
|
+
const table = await this.client.openTable(tableName);
|
|
1266
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
1267
|
+
const processedRecords = records.map((record) => {
|
|
1268
|
+
const processedRecord = { ...record };
|
|
1269
|
+
for (const key in processedRecord) {
|
|
1270
|
+
if (processedRecord[key] == null) continue;
|
|
1271
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
1272
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return processedRecord;
|
|
1276
|
+
});
|
|
1277
|
+
console.log(processedRecords);
|
|
1278
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
|
|
1279
|
+
} catch (error) {
|
|
1280
|
+
throw new MastraError(
|
|
1281
|
+
{
|
|
1282
|
+
id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_FAILED",
|
|
1283
|
+
domain: ErrorDomain.STORAGE,
|
|
1284
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1285
|
+
details: { tableName }
|
|
1286
|
+
},
|
|
1287
|
+
error
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
async load({ tableName, keys }) {
|
|
1292
|
+
try {
|
|
1293
|
+
if (!this.client) {
|
|
1294
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1295
|
+
}
|
|
1296
|
+
if (!tableName) {
|
|
1297
|
+
throw new Error("tableName is required for load.");
|
|
1298
|
+
}
|
|
1299
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1300
|
+
throw new Error("keys are required and cannot be empty for load.");
|
|
1301
|
+
}
|
|
1302
|
+
} catch (validationError) {
|
|
1303
|
+
throw new MastraError(
|
|
1304
|
+
{
|
|
1305
|
+
id: "STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS",
|
|
1306
|
+
domain: ErrorDomain.STORAGE,
|
|
1307
|
+
category: ErrorCategory.USER,
|
|
1308
|
+
text: validationError.message,
|
|
1309
|
+
details: { tableName }
|
|
1310
|
+
},
|
|
1311
|
+
validationError
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
try {
|
|
1315
|
+
const table = await this.client.openTable(tableName);
|
|
1316
|
+
const tableSchema = await getTableSchema({ tableName, client: this.client });
|
|
1317
|
+
const query = table.query();
|
|
1318
|
+
if (Object.keys(keys).length > 0) {
|
|
1319
|
+
validateKeyTypes(keys, tableSchema);
|
|
1320
|
+
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
1321
|
+
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
1322
|
+
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
1323
|
+
if (typeof value === "string") {
|
|
1324
|
+
return `${quotedKey} = '${value}'`;
|
|
1325
|
+
} else if (value === null) {
|
|
1326
|
+
return `${quotedKey} IS NULL`;
|
|
1327
|
+
} else {
|
|
1328
|
+
return `${quotedKey} = ${value}`;
|
|
1329
|
+
}
|
|
1330
|
+
}).join(" AND ");
|
|
1331
|
+
this.logger.debug("where clause generated: " + filterConditions);
|
|
1332
|
+
query.where(filterConditions);
|
|
1333
|
+
}
|
|
1334
|
+
const result = await query.limit(1).toArray();
|
|
1335
|
+
if (result.length === 0) {
|
|
1336
|
+
this.logger.debug("No record found");
|
|
1337
|
+
return null;
|
|
1338
|
+
}
|
|
1339
|
+
return processResultWithTypeConversion(result[0], tableSchema);
|
|
1340
|
+
} catch (error) {
|
|
1341
|
+
if (error instanceof MastraError) throw error;
|
|
1342
|
+
throw new MastraError(
|
|
1343
|
+
{
|
|
1344
|
+
id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
|
|
1345
|
+
domain: ErrorDomain.STORAGE,
|
|
1346
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1347
|
+
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
1348
|
+
},
|
|
1349
|
+
error
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
var StoreScoresLance = class extends ScoresStorage {
|
|
1355
|
+
client;
|
|
1356
|
+
constructor({ client }) {
|
|
1357
|
+
super();
|
|
1358
|
+
this.client = client;
|
|
1359
|
+
}
|
|
1360
|
+
async saveScore(score) {
|
|
1361
|
+
try {
|
|
1362
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1363
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1364
|
+
const allowedFields = new Set(schema.fields.map((f) => f.name));
|
|
1365
|
+
const filteredScore = {};
|
|
1366
|
+
Object.keys(score).forEach((key) => {
|
|
1367
|
+
if (allowedFields.has(key)) {
|
|
1368
|
+
filteredScore[key] = score[key];
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
for (const key in filteredScore) {
|
|
1372
|
+
if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
|
|
1373
|
+
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
console.log("Saving score to LanceStorage:", filteredScore);
|
|
1377
|
+
await table.add([filteredScore], { mode: "append" });
|
|
1378
|
+
return { score };
|
|
1379
|
+
} catch (error) {
|
|
1380
|
+
throw new MastraError(
|
|
1381
|
+
{
|
|
1382
|
+
id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
|
|
1383
|
+
text: "Failed to save score in LanceStorage",
|
|
1384
|
+
domain: ErrorDomain.STORAGE,
|
|
1385
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1386
|
+
details: { error: error?.message }
|
|
1387
|
+
},
|
|
1388
|
+
error
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
async getScoreById({ id }) {
|
|
1393
|
+
try {
|
|
1394
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1395
|
+
const query = table.query().where(`id = '${id}'`).limit(1);
|
|
1396
|
+
const records = await query.toArray();
|
|
1397
|
+
if (records.length === 0) return null;
|
|
1398
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1399
|
+
return processResultWithTypeConversion(records[0], schema);
|
|
1400
|
+
} catch (error) {
|
|
1401
|
+
throw new MastraError(
|
|
1402
|
+
{
|
|
1403
|
+
id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
|
|
1404
|
+
text: "Failed to get score by id in LanceStorage",
|
|
1405
|
+
domain: ErrorDomain.STORAGE,
|
|
1406
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1407
|
+
details: { error: error?.message }
|
|
1408
|
+
},
|
|
1409
|
+
error
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
async getScoresByScorerId({
|
|
1414
|
+
scorerId,
|
|
1415
|
+
pagination
|
|
1416
|
+
}) {
|
|
1417
|
+
try {
|
|
1418
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1419
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1420
|
+
const offset = page * perPage;
|
|
1421
|
+
const query = table.query().where(`\`scorerId\` = '${scorerId}'`).limit(perPage);
|
|
1422
|
+
if (offset > 0) query.offset(offset);
|
|
1423
|
+
const records = await query.toArray();
|
|
1424
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1425
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1426
|
+
const allRecords = await table.query().where(`\`scorerId\` = '${scorerId}'`).toArray();
|
|
1427
|
+
const total = allRecords.length;
|
|
1428
|
+
return {
|
|
1429
|
+
pagination: {
|
|
1430
|
+
page,
|
|
1431
|
+
perPage,
|
|
1432
|
+
total,
|
|
1433
|
+
hasMore: offset + scores.length < total
|
|
1434
|
+
},
|
|
1435
|
+
scores
|
|
1436
|
+
};
|
|
1437
|
+
} catch (error) {
|
|
1438
|
+
throw new MastraError(
|
|
1439
|
+
{
|
|
1440
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
1441
|
+
text: "Failed to get scores by scorerId in LanceStorage",
|
|
1442
|
+
domain: ErrorDomain.STORAGE,
|
|
1443
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1444
|
+
details: { error: error?.message }
|
|
1445
|
+
},
|
|
1446
|
+
error
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
async getScoresByRunId({
|
|
1451
|
+
runId,
|
|
1452
|
+
pagination
|
|
1453
|
+
}) {
|
|
1454
|
+
try {
|
|
1455
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1456
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1457
|
+
const offset = page * perPage;
|
|
1458
|
+
const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
|
|
1459
|
+
if (offset > 0) query.offset(offset);
|
|
1460
|
+
const records = await query.toArray();
|
|
1461
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1462
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1463
|
+
const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
|
|
1464
|
+
const total = allRecords.length;
|
|
1465
|
+
return {
|
|
1466
|
+
pagination: {
|
|
1467
|
+
page,
|
|
1468
|
+
perPage,
|
|
1469
|
+
total,
|
|
1470
|
+
hasMore: offset + scores.length < total
|
|
1471
|
+
},
|
|
1472
|
+
scores
|
|
1473
|
+
};
|
|
1474
|
+
} catch (error) {
|
|
1475
|
+
throw new MastraError(
|
|
1476
|
+
{
|
|
1477
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1478
|
+
text: "Failed to get scores by runId in LanceStorage",
|
|
1479
|
+
domain: ErrorDomain.STORAGE,
|
|
1480
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1481
|
+
details: { error: error?.message }
|
|
1482
|
+
},
|
|
1483
|
+
error
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
async getScoresByEntityId({
|
|
1488
|
+
entityId,
|
|
1489
|
+
entityType,
|
|
1490
|
+
pagination
|
|
1491
|
+
}) {
|
|
1492
|
+
try {
|
|
1493
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1494
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1495
|
+
const offset = page * perPage;
|
|
1496
|
+
const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
|
|
1497
|
+
if (offset > 0) query.offset(offset);
|
|
1498
|
+
const records = await query.toArray();
|
|
1499
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1500
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1501
|
+
const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
|
|
1502
|
+
const total = allRecords.length;
|
|
1503
|
+
return {
|
|
1504
|
+
pagination: {
|
|
1505
|
+
page,
|
|
1506
|
+
perPage,
|
|
1507
|
+
total,
|
|
1508
|
+
hasMore: offset + scores.length < total
|
|
1509
|
+
},
|
|
1510
|
+
scores
|
|
1511
|
+
};
|
|
1512
|
+
} catch (error) {
|
|
1513
|
+
throw new MastraError(
|
|
1514
|
+
{
|
|
1515
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1516
|
+
text: "Failed to get scores by entityId and entityType in LanceStorage",
|
|
1517
|
+
domain: ErrorDomain.STORAGE,
|
|
1518
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1519
|
+
details: { error: error?.message }
|
|
1520
|
+
},
|
|
1521
|
+
error
|
|
1522
|
+
);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1526
|
+
var StoreTracesLance = class extends TracesStorage {
|
|
1527
|
+
client;
|
|
1528
|
+
operations;
|
|
1529
|
+
constructor({ client, operations }) {
|
|
1530
|
+
super();
|
|
1531
|
+
this.client = client;
|
|
1532
|
+
this.operations = operations;
|
|
1533
|
+
}
|
|
1534
|
+
async saveTrace({ trace }) {
|
|
1535
|
+
try {
|
|
1536
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
1537
|
+
const record = {
|
|
1538
|
+
...trace,
|
|
1539
|
+
attributes: JSON.stringify(trace.attributes),
|
|
1540
|
+
status: JSON.stringify(trace.status),
|
|
1541
|
+
events: JSON.stringify(trace.events),
|
|
1542
|
+
links: JSON.stringify(trace.links),
|
|
1543
|
+
other: JSON.stringify(trace.other)
|
|
1544
|
+
};
|
|
1545
|
+
await table.add([record], { mode: "append" });
|
|
1546
|
+
return trace;
|
|
1547
|
+
} catch (error) {
|
|
1548
|
+
throw new MastraError(
|
|
1549
|
+
{
|
|
1550
|
+
id: "LANCE_STORE_SAVE_TRACE_FAILED",
|
|
1551
|
+
domain: ErrorDomain.STORAGE,
|
|
1552
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1553
|
+
},
|
|
1554
|
+
error
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
async getTraceById({ traceId }) {
|
|
1559
|
+
try {
|
|
1560
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
1561
|
+
const query = table.query().where(`id = '${traceId}'`);
|
|
1562
|
+
const records = await query.toArray();
|
|
1563
|
+
return records[0];
|
|
1564
|
+
} catch (error) {
|
|
1565
|
+
throw new MastraError(
|
|
1566
|
+
{
|
|
1567
|
+
id: "LANCE_STORE_GET_TRACE_BY_ID_FAILED",
|
|
1568
|
+
domain: ErrorDomain.STORAGE,
|
|
1569
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1570
|
+
},
|
|
1571
|
+
error
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
async getTraces({
|
|
1576
|
+
name,
|
|
1577
|
+
scope,
|
|
1578
|
+
page = 1,
|
|
1579
|
+
perPage = 10,
|
|
1580
|
+
attributes
|
|
1581
|
+
}) {
|
|
1582
|
+
try {
|
|
1583
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
1584
|
+
const query = table.query();
|
|
1585
|
+
if (name) {
|
|
1586
|
+
query.where(`name = '${name}'`);
|
|
1587
|
+
}
|
|
1588
|
+
if (scope) {
|
|
1589
|
+
query.where(`scope = '${scope}'`);
|
|
1590
|
+
}
|
|
1591
|
+
if (attributes) {
|
|
1592
|
+
query.where(`attributes = '${JSON.stringify(attributes)}'`);
|
|
1593
|
+
}
|
|
1594
|
+
const offset = (page - 1) * perPage;
|
|
1595
|
+
query.limit(perPage);
|
|
1596
|
+
if (offset > 0) {
|
|
1597
|
+
query.offset(offset);
|
|
1598
|
+
}
|
|
1599
|
+
const records = await query.toArray();
|
|
1600
|
+
return records.map((record) => {
|
|
1601
|
+
const processed = {
|
|
1602
|
+
...record,
|
|
1603
|
+
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1604
|
+
status: record.status ? JSON.parse(record.status) : {},
|
|
1605
|
+
events: record.events ? JSON.parse(record.events) : [],
|
|
1606
|
+
links: record.links ? JSON.parse(record.links) : [],
|
|
1607
|
+
other: record.other ? JSON.parse(record.other) : {},
|
|
1608
|
+
startTime: new Date(record.startTime),
|
|
1609
|
+
endTime: new Date(record.endTime),
|
|
1610
|
+
createdAt: new Date(record.createdAt)
|
|
1611
|
+
};
|
|
1612
|
+
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1613
|
+
processed.parentSpanId = "";
|
|
1614
|
+
} else {
|
|
1615
|
+
processed.parentSpanId = String(processed.parentSpanId);
|
|
1616
|
+
}
|
|
1617
|
+
return processed;
|
|
1618
|
+
});
|
|
1619
|
+
} catch (error) {
|
|
1620
|
+
throw new MastraError(
|
|
1621
|
+
{
|
|
1622
|
+
id: "LANCE_STORE_GET_TRACES_FAILED",
|
|
1623
|
+
domain: ErrorDomain.STORAGE,
|
|
1624
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1625
|
+
details: { name: name ?? "", scope: scope ?? "" }
|
|
1626
|
+
},
|
|
1627
|
+
error
|
|
1628
|
+
);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
async getTracesPaginated(args) {
|
|
1632
|
+
try {
|
|
1633
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
1634
|
+
const query = table.query();
|
|
1635
|
+
const conditions = [];
|
|
1636
|
+
if (args.name) {
|
|
1637
|
+
conditions.push(`name = '${args.name}'`);
|
|
1638
|
+
}
|
|
1639
|
+
if (args.scope) {
|
|
1640
|
+
conditions.push(`scope = '${args.scope}'`);
|
|
1641
|
+
}
|
|
1642
|
+
if (args.attributes) {
|
|
1643
|
+
const attributesStr = JSON.stringify(args.attributes);
|
|
1644
|
+
conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
|
|
1645
|
+
}
|
|
1646
|
+
if (args.dateRange?.start) {
|
|
1647
|
+
conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
|
|
1648
|
+
}
|
|
1649
|
+
if (args.dateRange?.end) {
|
|
1650
|
+
conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
|
|
1651
|
+
}
|
|
1652
|
+
if (conditions.length > 0) {
|
|
1653
|
+
const whereClause = conditions.join(" AND ");
|
|
1654
|
+
query.where(whereClause);
|
|
1655
|
+
}
|
|
1656
|
+
let total = 0;
|
|
1657
|
+
if (conditions.length > 0) {
|
|
1658
|
+
const countQuery = table.query().where(conditions.join(" AND "));
|
|
1659
|
+
const allRecords = await countQuery.toArray();
|
|
1660
|
+
total = allRecords.length;
|
|
1661
|
+
} else {
|
|
1662
|
+
total = await table.countRows();
|
|
1663
|
+
}
|
|
1664
|
+
const page = args.page || 0;
|
|
1665
|
+
const perPage = args.perPage || 10;
|
|
1666
|
+
const offset = page * perPage;
|
|
1667
|
+
query.limit(perPage);
|
|
1668
|
+
if (offset > 0) {
|
|
1669
|
+
query.offset(offset);
|
|
1670
|
+
}
|
|
1671
|
+
const records = await query.toArray();
|
|
1672
|
+
const traces = records.map((record) => {
|
|
1673
|
+
const processed = {
|
|
1674
|
+
...record,
|
|
1675
|
+
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1676
|
+
status: record.status ? JSON.parse(record.status) : {},
|
|
1677
|
+
events: record.events ? JSON.parse(record.events) : [],
|
|
1678
|
+
links: record.links ? JSON.parse(record.links) : [],
|
|
1679
|
+
other: record.other ? JSON.parse(record.other) : {},
|
|
1680
|
+
startTime: new Date(record.startTime),
|
|
1681
|
+
endTime: new Date(record.endTime),
|
|
1682
|
+
createdAt: new Date(record.createdAt)
|
|
1683
|
+
};
|
|
1684
|
+
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1685
|
+
processed.parentSpanId = "";
|
|
1686
|
+
} else {
|
|
1687
|
+
processed.parentSpanId = String(processed.parentSpanId);
|
|
1688
|
+
}
|
|
1689
|
+
return processed;
|
|
1690
|
+
});
|
|
1691
|
+
return {
|
|
1692
|
+
traces,
|
|
1693
|
+
total,
|
|
1694
|
+
page,
|
|
1695
|
+
perPage,
|
|
1696
|
+
hasMore: total > (page + 1) * perPage
|
|
1697
|
+
};
|
|
1698
|
+
} catch (error) {
|
|
1699
|
+
throw new MastraError(
|
|
1700
|
+
{
|
|
1701
|
+
id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
1702
|
+
domain: ErrorDomain.STORAGE,
|
|
1703
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1704
|
+
details: { name: args.name ?? "", scope: args.scope ?? "" }
|
|
1705
|
+
},
|
|
1706
|
+
error
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
async batchTraceInsert({ records }) {
|
|
1711
|
+
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1712
|
+
await this.operations.batchInsert({
|
|
1713
|
+
tableName: TABLE_TRACES,
|
|
1714
|
+
records
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
function parseWorkflowRun(row) {
|
|
1719
|
+
let parsedSnapshot = row.snapshot;
|
|
1720
|
+
if (typeof parsedSnapshot === "string") {
|
|
1721
|
+
try {
|
|
1722
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1723
|
+
} catch (e) {
|
|
1724
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
return {
|
|
1728
|
+
workflowName: row.workflow_name,
|
|
1729
|
+
runId: row.run_id,
|
|
1730
|
+
snapshot: parsedSnapshot,
|
|
1731
|
+
createdAt: ensureDate(row.createdAt),
|
|
1732
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
1733
|
+
resourceId: row.resourceId
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
1737
|
+
client;
|
|
1738
|
+
constructor({ client }) {
|
|
1739
|
+
super();
|
|
1740
|
+
this.client = client;
|
|
1741
|
+
}
|
|
1742
|
+
async persistWorkflowSnapshot({
|
|
1743
|
+
workflowName,
|
|
1744
|
+
runId,
|
|
1745
|
+
snapshot
|
|
1746
|
+
}) {
|
|
1747
|
+
try {
|
|
1748
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1749
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1750
|
+
const records = await query.toArray();
|
|
1751
|
+
let createdAt;
|
|
1752
|
+
const now = Date.now();
|
|
1753
|
+
if (records.length > 0) {
|
|
1754
|
+
createdAt = records[0].createdAt ?? now;
|
|
1755
|
+
} else {
|
|
1756
|
+
createdAt = now;
|
|
1757
|
+
}
|
|
1758
|
+
const record = {
|
|
1759
|
+
workflow_name: workflowName,
|
|
1760
|
+
run_id: runId,
|
|
1761
|
+
snapshot: JSON.stringify(snapshot),
|
|
1762
|
+
createdAt,
|
|
1763
|
+
updatedAt: now
|
|
1764
|
+
};
|
|
1765
|
+
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1766
|
+
} catch (error) {
|
|
1767
|
+
throw new MastraError(
|
|
1768
|
+
{
|
|
1769
|
+
id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
1770
|
+
domain: ErrorDomain.STORAGE,
|
|
1771
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1772
|
+
details: { workflowName, runId }
|
|
1773
|
+
},
|
|
1774
|
+
error
|
|
1775
|
+
);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
async loadWorkflowSnapshot({
|
|
1779
|
+
workflowName,
|
|
1780
|
+
runId
|
|
1781
|
+
}) {
|
|
1782
|
+
try {
|
|
1783
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1784
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1785
|
+
const records = await query.toArray();
|
|
1786
|
+
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1787
|
+
} catch (error) {
|
|
1788
|
+
throw new MastraError(
|
|
1789
|
+
{
|
|
1790
|
+
id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
1791
|
+
domain: ErrorDomain.STORAGE,
|
|
1792
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1793
|
+
details: { workflowName, runId }
|
|
1794
|
+
},
|
|
1795
|
+
error
|
|
1796
|
+
);
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
async getWorkflowRunById(args) {
|
|
1800
|
+
try {
|
|
1801
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1802
|
+
let whereClause = `run_id = '${args.runId}'`;
|
|
1803
|
+
if (args.workflowName) {
|
|
1804
|
+
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
1805
|
+
}
|
|
1806
|
+
const query = table.query().where(whereClause);
|
|
1807
|
+
const records = await query.toArray();
|
|
1808
|
+
if (records.length === 0) return null;
|
|
1809
|
+
const record = records[0];
|
|
1810
|
+
return parseWorkflowRun(record);
|
|
1811
|
+
} catch (error) {
|
|
1812
|
+
throw new MastraError(
|
|
1813
|
+
{
|
|
1814
|
+
id: "LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
1815
|
+
domain: ErrorDomain.STORAGE,
|
|
1816
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1817
|
+
details: { runId: args.runId, workflowName: args.workflowName ?? "" }
|
|
1818
|
+
},
|
|
1819
|
+
error
|
|
1820
|
+
);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
async getWorkflowRuns(args) {
|
|
1824
|
+
try {
|
|
1825
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1826
|
+
let query = table.query();
|
|
1827
|
+
const conditions = [];
|
|
1828
|
+
if (args?.workflowName) {
|
|
1829
|
+
conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
|
|
1830
|
+
}
|
|
1831
|
+
if (args?.resourceId) {
|
|
1832
|
+
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1833
|
+
}
|
|
1834
|
+
if (args?.fromDate instanceof Date) {
|
|
1835
|
+
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1836
|
+
}
|
|
1837
|
+
if (args?.toDate instanceof Date) {
|
|
1838
|
+
conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1839
|
+
}
|
|
1840
|
+
let total = 0;
|
|
1841
|
+
if (conditions.length > 0) {
|
|
1842
|
+
query = query.where(conditions.join(" AND "));
|
|
1843
|
+
total = await table.countRows(conditions.join(" AND "));
|
|
1844
|
+
} else {
|
|
1845
|
+
total = await table.countRows();
|
|
1846
|
+
}
|
|
1847
|
+
if (args?.limit) {
|
|
1848
|
+
query.limit(args.limit);
|
|
1849
|
+
}
|
|
1850
|
+
if (args?.offset) {
|
|
1851
|
+
query.offset(args.offset);
|
|
1852
|
+
}
|
|
1853
|
+
const records = await query.toArray();
|
|
1854
|
+
return {
|
|
1855
|
+
runs: records.map((record) => parseWorkflowRun(record)),
|
|
1856
|
+
total: total || records.length
|
|
1857
|
+
};
|
|
1858
|
+
} catch (error) {
|
|
1859
|
+
throw new MastraError(
|
|
1860
|
+
{
|
|
1861
|
+
id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
|
|
1862
|
+
domain: ErrorDomain.STORAGE,
|
|
1863
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1864
|
+
details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
|
|
1865
|
+
},
|
|
1866
|
+
error
|
|
1867
|
+
);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
|
|
8
1872
|
// src/storage/index.ts
|
|
9
1873
|
var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
1874
|
+
stores;
|
|
10
1875
|
lanceClient;
|
|
11
1876
|
/**
|
|
12
1877
|
* Creates a new instance of LanceStorage
|
|
@@ -34,9 +1899,27 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
34
1899
|
const instance = new _LanceStorage(name);
|
|
35
1900
|
try {
|
|
36
1901
|
instance.lanceClient = await connect(uri, options);
|
|
1902
|
+
const operations = new StoreOperationsLance({ client: instance.lanceClient });
|
|
1903
|
+
instance.stores = {
|
|
1904
|
+
operations: new StoreOperationsLance({ client: instance.lanceClient }),
|
|
1905
|
+
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1906
|
+
traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
|
|
1907
|
+
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1908
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
|
|
1909
|
+
legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
|
|
1910
|
+
};
|
|
37
1911
|
return instance;
|
|
38
1912
|
} catch (e) {
|
|
39
|
-
throw new
|
|
1913
|
+
throw new MastraError(
|
|
1914
|
+
{
|
|
1915
|
+
id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
|
|
1916
|
+
domain: ErrorDomain.STORAGE,
|
|
1917
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1918
|
+
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1919
|
+
details: { uri, optionsProvided: !!options }
|
|
1920
|
+
},
|
|
1921
|
+
e
|
|
1922
|
+
);
|
|
40
1923
|
}
|
|
41
1924
|
}
|
|
42
1925
|
/**
|
|
@@ -45,312 +1928,49 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
45
1928
|
*/
|
|
46
1929
|
constructor(name) {
|
|
47
1930
|
super({ name });
|
|
1931
|
+
const operations = new StoreOperationsLance({ client: this.lanceClient });
|
|
1932
|
+
this.stores = {
|
|
1933
|
+
operations: new StoreOperationsLance({ client: this.lanceClient }),
|
|
1934
|
+
workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
|
|
1935
|
+
traces: new StoreTracesLance({ client: this.lanceClient, operations }),
|
|
1936
|
+
scores: new StoreScoresLance({ client: this.lanceClient }),
|
|
1937
|
+
legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
|
|
1938
|
+
memory: new StoreMemoryLance({ client: this.lanceClient, operations })
|
|
1939
|
+
};
|
|
48
1940
|
}
|
|
49
1941
|
async createTable({
|
|
50
1942
|
tableName,
|
|
51
1943
|
schema
|
|
52
1944
|
}) {
|
|
53
|
-
|
|
54
|
-
const arrowSchema = this.translateSchema(schema);
|
|
55
|
-
await this.lanceClient.createEmptyTable(tableName, arrowSchema);
|
|
56
|
-
} catch (error) {
|
|
57
|
-
throw new Error(`Failed to create table: ${error}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
translateSchema(schema) {
|
|
61
|
-
const fields = Object.entries(schema).map(([name, column]) => {
|
|
62
|
-
let arrowType;
|
|
63
|
-
switch (column.type.toLowerCase()) {
|
|
64
|
-
case "text":
|
|
65
|
-
case "uuid":
|
|
66
|
-
arrowType = new Utf8();
|
|
67
|
-
break;
|
|
68
|
-
case "int":
|
|
69
|
-
case "integer":
|
|
70
|
-
arrowType = new Int32();
|
|
71
|
-
break;
|
|
72
|
-
case "bigint":
|
|
73
|
-
arrowType = new Float64();
|
|
74
|
-
break;
|
|
75
|
-
case "float":
|
|
76
|
-
arrowType = new Float32();
|
|
77
|
-
break;
|
|
78
|
-
case "jsonb":
|
|
79
|
-
case "json":
|
|
80
|
-
arrowType = new Utf8();
|
|
81
|
-
break;
|
|
82
|
-
case "binary":
|
|
83
|
-
arrowType = new Binary();
|
|
84
|
-
break;
|
|
85
|
-
case "timestamp":
|
|
86
|
-
arrowType = new Float64();
|
|
87
|
-
break;
|
|
88
|
-
default:
|
|
89
|
-
arrowType = new Utf8();
|
|
90
|
-
}
|
|
91
|
-
return new Field(name, arrowType, column.nullable ?? true);
|
|
92
|
-
});
|
|
93
|
-
return new Schema(fields);
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Drop a table if it exists
|
|
97
|
-
* @param tableName Name of the table to drop
|
|
98
|
-
*/
|
|
99
|
-
async dropTable(tableName) {
|
|
100
|
-
try {
|
|
101
|
-
await this.lanceClient.dropTable(tableName);
|
|
102
|
-
} catch (error) {
|
|
103
|
-
if (error.toString().includes("was not found")) {
|
|
104
|
-
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
throw new Error(`Failed to drop table: ${error}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Get table schema
|
|
112
|
-
* @param tableName Name of the table
|
|
113
|
-
* @returns Table schema
|
|
114
|
-
*/
|
|
115
|
-
async getTableSchema(tableName) {
|
|
116
|
-
try {
|
|
117
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
118
|
-
const rawSchema = await table.schema();
|
|
119
|
-
const fields = rawSchema.fields;
|
|
120
|
-
return {
|
|
121
|
-
fields,
|
|
122
|
-
metadata: /* @__PURE__ */ new Map(),
|
|
123
|
-
get names() {
|
|
124
|
-
return fields.map((field) => field.name);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
} catch (error) {
|
|
128
|
-
throw new Error(`Failed to get table schema: ${error}`);
|
|
129
|
-
}
|
|
1945
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
130
1946
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
case "text":
|
|
134
|
-
return "''";
|
|
135
|
-
case "timestamp":
|
|
136
|
-
return "CURRENT_TIMESTAMP";
|
|
137
|
-
case "integer":
|
|
138
|
-
case "bigint":
|
|
139
|
-
return "0";
|
|
140
|
-
case "jsonb":
|
|
141
|
-
return "'{}'";
|
|
142
|
-
case "uuid":
|
|
143
|
-
return "''";
|
|
144
|
-
default:
|
|
145
|
-
return super.getDefaultValue(type);
|
|
146
|
-
}
|
|
1947
|
+
async dropTable({ tableName }) {
|
|
1948
|
+
return this.stores.operations.dropTable({ tableName });
|
|
147
1949
|
}
|
|
148
|
-
/**
|
|
149
|
-
* Alters table schema to add columns if they don't exist
|
|
150
|
-
* @param tableName Name of the table
|
|
151
|
-
* @param schema Schema of the table
|
|
152
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
153
|
-
*/
|
|
154
1950
|
async alterTable({
|
|
155
1951
|
tableName,
|
|
156
1952
|
schema,
|
|
157
1953
|
ifNotExists
|
|
158
1954
|
}) {
|
|
159
|
-
|
|
160
|
-
const currentSchema = await table.schema();
|
|
161
|
-
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
162
|
-
const typeMap = {
|
|
163
|
-
text: "string",
|
|
164
|
-
integer: "int",
|
|
165
|
-
bigint: "bigint",
|
|
166
|
-
timestamp: "timestamp",
|
|
167
|
-
jsonb: "string",
|
|
168
|
-
uuid: "string"
|
|
169
|
-
};
|
|
170
|
-
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
171
|
-
const colDef = schema[col];
|
|
172
|
-
return {
|
|
173
|
-
name: col,
|
|
174
|
-
valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
|
|
175
|
-
};
|
|
176
|
-
});
|
|
177
|
-
if (columnsToAdd.length > 0) {
|
|
178
|
-
await table.addColumns(columnsToAdd);
|
|
179
|
-
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
180
|
-
}
|
|
1955
|
+
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
181
1956
|
}
|
|
182
1957
|
async clearTable({ tableName }) {
|
|
183
|
-
|
|
184
|
-
await table.delete("1=1");
|
|
1958
|
+
return this.stores.operations.clearTable({ tableName });
|
|
185
1959
|
}
|
|
186
|
-
/**
|
|
187
|
-
* Insert a single record into a table. This function overwrites the existing record if it exists. Use this function for inserting records into tables with custom schemas.
|
|
188
|
-
* @param tableName The name of the table to insert into.
|
|
189
|
-
* @param record The record to insert.
|
|
190
|
-
*/
|
|
191
1960
|
async insert({ tableName, record }) {
|
|
192
|
-
|
|
193
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
194
|
-
const processedRecord = { ...record };
|
|
195
|
-
for (const key in processedRecord) {
|
|
196
|
-
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
197
|
-
this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
|
|
198
|
-
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
await table.add([processedRecord], { mode: "overwrite" });
|
|
202
|
-
} catch (error) {
|
|
203
|
-
throw new Error(`Failed to insert record: ${error}`);
|
|
204
|
-
}
|
|
1961
|
+
return this.stores.operations.insert({ tableName, record });
|
|
205
1962
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Insert multiple records into a table. This function overwrites the existing records if they exist. Use this function for inserting records into tables with custom schemas.
|
|
208
|
-
* @param tableName The name of the table to insert into.
|
|
209
|
-
* @param records The records to insert.
|
|
210
|
-
*/
|
|
211
1963
|
async batchInsert({ tableName, records }) {
|
|
212
|
-
|
|
213
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
214
|
-
const processedRecords = records.map((record) => {
|
|
215
|
-
const processedRecord = { ...record };
|
|
216
|
-
for (const key in processedRecord) {
|
|
217
|
-
if (processedRecord[key] == null) continue;
|
|
218
|
-
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
219
|
-
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return processedRecord;
|
|
223
|
-
});
|
|
224
|
-
await table.add(processedRecords, { mode: "overwrite" });
|
|
225
|
-
} catch (error) {
|
|
226
|
-
throw new Error(`Failed to batch insert records: ${error}`);
|
|
227
|
-
}
|
|
1964
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
228
1965
|
}
|
|
229
|
-
/**
|
|
230
|
-
* Load a record from the database by its key(s)
|
|
231
|
-
* @param tableName The name of the table to query
|
|
232
|
-
* @param keys Record of key-value pairs to use for lookup
|
|
233
|
-
* @throws Error if invalid types are provided for keys
|
|
234
|
-
* @returns The loaded record with proper type conversions, or null if not found
|
|
235
|
-
*/
|
|
236
1966
|
async load({ tableName, keys }) {
|
|
237
|
-
|
|
238
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
239
|
-
const tableSchema = await this.getTableSchema(tableName);
|
|
240
|
-
const query = table.query();
|
|
241
|
-
if (Object.keys(keys).length > 0) {
|
|
242
|
-
this.validateKeyTypes(keys, tableSchema);
|
|
243
|
-
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
244
|
-
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
245
|
-
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
246
|
-
if (typeof value === "string") {
|
|
247
|
-
return `${quotedKey} = '${value}'`;
|
|
248
|
-
} else if (value === null) {
|
|
249
|
-
return `${quotedKey} IS NULL`;
|
|
250
|
-
} else {
|
|
251
|
-
return `${quotedKey} = ${value}`;
|
|
252
|
-
}
|
|
253
|
-
}).join(" AND ");
|
|
254
|
-
this.logger.debug("where clause generated: " + filterConditions);
|
|
255
|
-
query.where(filterConditions);
|
|
256
|
-
}
|
|
257
|
-
const result = await query.limit(1).toArray();
|
|
258
|
-
if (result.length === 0) {
|
|
259
|
-
this.logger.debug("No record found");
|
|
260
|
-
return null;
|
|
261
|
-
}
|
|
262
|
-
return this.processResultWithTypeConversion(result[0], tableSchema);
|
|
263
|
-
} catch (error) {
|
|
264
|
-
throw new Error(`Failed to load record: ${error}`);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* Validates that key types match the schema definition
|
|
269
|
-
* @param keys The keys to validate
|
|
270
|
-
* @param tableSchema The table schema to validate against
|
|
271
|
-
* @throws Error if a key has an incompatible type
|
|
272
|
-
*/
|
|
273
|
-
validateKeyTypes(keys, tableSchema) {
|
|
274
|
-
const fieldTypes = new Map(
|
|
275
|
-
tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
|
|
276
|
-
);
|
|
277
|
-
for (const [key, value] of Object.entries(keys)) {
|
|
278
|
-
const fieldType = fieldTypes.get(key);
|
|
279
|
-
if (!fieldType) {
|
|
280
|
-
throw new Error(`Field '${key}' does not exist in table schema`);
|
|
281
|
-
}
|
|
282
|
-
if (value !== null) {
|
|
283
|
-
if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
|
|
284
|
-
throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
|
|
285
|
-
}
|
|
286
|
-
if (fieldType.includes("utf8") && typeof value !== "string") {
|
|
287
|
-
throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
|
|
288
|
-
}
|
|
289
|
-
if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
|
|
290
|
-
throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Process a database result with appropriate type conversions based on the table schema
|
|
297
|
-
* @param rawResult The raw result object from the database
|
|
298
|
-
* @param tableSchema The schema of the table containing type information
|
|
299
|
-
* @returns Processed result with correct data types
|
|
300
|
-
*/
|
|
301
|
-
processResultWithTypeConversion(rawResult, tableSchema) {
|
|
302
|
-
const fieldTypeMap = /* @__PURE__ */ new Map();
|
|
303
|
-
tableSchema.fields.forEach((field) => {
|
|
304
|
-
const fieldName = field.name;
|
|
305
|
-
const fieldTypeStr = field.type.toString().toLowerCase();
|
|
306
|
-
fieldTypeMap.set(fieldName, fieldTypeStr);
|
|
307
|
-
});
|
|
308
|
-
if (Array.isArray(rawResult)) {
|
|
309
|
-
return rawResult.map((item) => this.processResultWithTypeConversion(item, tableSchema));
|
|
310
|
-
}
|
|
311
|
-
const processedResult = { ...rawResult };
|
|
312
|
-
for (const key in processedResult) {
|
|
313
|
-
const fieldTypeStr = fieldTypeMap.get(key);
|
|
314
|
-
if (!fieldTypeStr) continue;
|
|
315
|
-
if (typeof processedResult[key] === "string") {
|
|
316
|
-
if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
|
|
317
|
-
if (!isNaN(Number(processedResult[key]))) {
|
|
318
|
-
processedResult[key] = Number(processedResult[key]);
|
|
319
|
-
}
|
|
320
|
-
} else if (fieldTypeStr.includes("int64")) {
|
|
321
|
-
processedResult[key] = Number(processedResult[key]);
|
|
322
|
-
} else if (fieldTypeStr.includes("utf8")) {
|
|
323
|
-
try {
|
|
324
|
-
processedResult[key] = JSON.parse(processedResult[key]);
|
|
325
|
-
} catch (e) {
|
|
326
|
-
this.logger.debug(`Failed to parse JSON for key ${key}: ${e}`);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
} else if (typeof processedResult[key] === "bigint") {
|
|
330
|
-
processedResult[key] = Number(processedResult[key]);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
return processedResult;
|
|
1967
|
+
return this.stores.operations.load({ tableName, keys });
|
|
334
1968
|
}
|
|
335
|
-
getThreadById({ threadId }) {
|
|
336
|
-
|
|
337
|
-
return this.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
|
|
338
|
-
} catch (error) {
|
|
339
|
-
throw new Error(`Failed to get thread by ID: ${error}`);
|
|
340
|
-
}
|
|
1969
|
+
async getThreadById({ threadId }) {
|
|
1970
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
341
1971
|
}
|
|
342
1972
|
async getThreadsByResourceId({ resourceId }) {
|
|
343
|
-
|
|
344
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
345
|
-
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
346
|
-
const records = await query.toArray();
|
|
347
|
-
return this.processResultWithTypeConversion(
|
|
348
|
-
records,
|
|
349
|
-
await this.getTableSchema(TABLE_THREADS)
|
|
350
|
-
);
|
|
351
|
-
} catch (error) {
|
|
352
|
-
throw new Error(`Failed to get threads by resource ID: ${error}`);
|
|
353
|
-
}
|
|
1973
|
+
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
354
1974
|
}
|
|
355
1975
|
/**
|
|
356
1976
|
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
@@ -358,41 +1978,39 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
358
1978
|
* @returns The saved thread
|
|
359
1979
|
*/
|
|
360
1980
|
async saveThread({ thread }) {
|
|
361
|
-
|
|
362
|
-
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
363
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
364
|
-
await table.add([record], { mode: "append" });
|
|
365
|
-
return thread;
|
|
366
|
-
} catch (error) {
|
|
367
|
-
throw new Error(`Failed to save thread: ${error}`);
|
|
368
|
-
}
|
|
1981
|
+
return this.stores.memory.saveThread({ thread });
|
|
369
1982
|
}
|
|
370
1983
|
async updateThread({
|
|
371
1984
|
id,
|
|
372
1985
|
title,
|
|
373
1986
|
metadata
|
|
374
1987
|
}) {
|
|
375
|
-
|
|
376
|
-
const record = { id, title, metadata: JSON.stringify(metadata) };
|
|
377
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
378
|
-
await table.add([record], { mode: "overwrite" });
|
|
379
|
-
const query = table.query().where(`id = '${id}'`);
|
|
380
|
-
const records = await query.toArray();
|
|
381
|
-
return this.processResultWithTypeConversion(
|
|
382
|
-
records[0],
|
|
383
|
-
await this.getTableSchema(TABLE_THREADS)
|
|
384
|
-
);
|
|
385
|
-
} catch (error) {
|
|
386
|
-
throw new Error(`Failed to update thread: ${error}`);
|
|
387
|
-
}
|
|
1988
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
388
1989
|
}
|
|
389
1990
|
async deleteThread({ threadId }) {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
1991
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
1992
|
+
}
|
|
1993
|
+
get supports() {
|
|
1994
|
+
return {
|
|
1995
|
+
selectByIncludeResourceScope: true,
|
|
1996
|
+
resourceWorkingMemory: true,
|
|
1997
|
+
hasColumn: true,
|
|
1998
|
+
createTable: true,
|
|
1999
|
+
deleteMessages: false
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
async getResourceById({ resourceId }) {
|
|
2003
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2004
|
+
}
|
|
2005
|
+
async saveResource({ resource }) {
|
|
2006
|
+
return this.stores.memory.saveResource({ resource });
|
|
2007
|
+
}
|
|
2008
|
+
async updateResource({
|
|
2009
|
+
resourceId,
|
|
2010
|
+
workingMemory,
|
|
2011
|
+
metadata
|
|
2012
|
+
}) {
|
|
2013
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
396
2014
|
}
|
|
397
2015
|
/**
|
|
398
2016
|
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
@@ -448,313 +2066,79 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
448
2066
|
selectBy,
|
|
449
2067
|
format,
|
|
450
2068
|
threadConfig
|
|
451
|
-
}) {
|
|
452
|
-
|
|
453
|
-
if (threadConfig) {
|
|
454
|
-
throw new Error("ThreadConfig is not supported by LanceDB storage");
|
|
455
|
-
}
|
|
456
|
-
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
|
|
457
|
-
const table = await this.lanceClient.openTable(TABLE_MESSAGES);
|
|
458
|
-
let query = table.query().where(`\`threadId\` = '${threadId}'`);
|
|
459
|
-
if (selectBy) {
|
|
460
|
-
if (selectBy.include && selectBy.include.length > 0) {
|
|
461
|
-
const includeIds = selectBy.include.map((item) => item.id);
|
|
462
|
-
const includeClause = includeIds.map((id) => `\`id\` = '${id}'`).join(" OR ");
|
|
463
|
-
query = query.where(`(\`threadId\` = '${threadId}' OR (${includeClause}))`);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
let records = await query.toArray();
|
|
467
|
-
records.sort((a, b) => {
|
|
468
|
-
const dateA = new Date(a.createdAt).getTime();
|
|
469
|
-
const dateB = new Date(b.createdAt).getTime();
|
|
470
|
-
return dateA - dateB;
|
|
471
|
-
});
|
|
472
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
473
|
-
records = this.processMessagesWithContext(records, selectBy.include);
|
|
474
|
-
}
|
|
475
|
-
if (limit !== Number.MAX_SAFE_INTEGER) {
|
|
476
|
-
records = records.slice(-limit);
|
|
477
|
-
}
|
|
478
|
-
const messages = this.processResultWithTypeConversion(records, await this.getTableSchema(TABLE_MESSAGES));
|
|
479
|
-
const normalized = messages.map((msg) => ({
|
|
480
|
-
...msg,
|
|
481
|
-
content: typeof msg.content === "string" ? (() => {
|
|
482
|
-
try {
|
|
483
|
-
return JSON.parse(msg.content);
|
|
484
|
-
} catch {
|
|
485
|
-
return msg.content;
|
|
486
|
-
}
|
|
487
|
-
})() : msg.content
|
|
488
|
-
}));
|
|
489
|
-
const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
|
|
490
|
-
if (format === "v2") return list.get.all.v2();
|
|
491
|
-
return list.get.all.v1();
|
|
492
|
-
} catch (error) {
|
|
493
|
-
throw new Error(`Failed to get messages: ${error}`);
|
|
494
|
-
}
|
|
2069
|
+
}) {
|
|
2070
|
+
return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
|
|
495
2071
|
}
|
|
496
2072
|
async saveMessages(args) {
|
|
497
|
-
|
|
498
|
-
const { messages, format = "v1" } = args;
|
|
499
|
-
if (messages.length === 0) {
|
|
500
|
-
return [];
|
|
501
|
-
}
|
|
502
|
-
const threadId = messages[0]?.threadId;
|
|
503
|
-
if (!threadId) {
|
|
504
|
-
throw new Error("Thread ID is required");
|
|
505
|
-
}
|
|
506
|
-
const transformedMessages = messages.map((message) => ({
|
|
507
|
-
...message,
|
|
508
|
-
content: JSON.stringify(message.content)
|
|
509
|
-
}));
|
|
510
|
-
const table = await this.lanceClient.openTable(TABLE_MESSAGES);
|
|
511
|
-
await table.add(transformedMessages, { mode: "overwrite" });
|
|
512
|
-
const list = new MessageList().add(messages, "memory");
|
|
513
|
-
if (format === `v2`) return list.get.all.v2();
|
|
514
|
-
return list.get.all.v1();
|
|
515
|
-
} catch (error) {
|
|
516
|
-
throw new Error(`Failed to save messages: ${error}`);
|
|
517
|
-
}
|
|
2073
|
+
return this.stores.memory.saveMessages(args);
|
|
518
2074
|
}
|
|
519
|
-
async
|
|
520
|
-
|
|
521
|
-
const table = await this.lanceClient.openTable(TABLE_TRACES);
|
|
522
|
-
const record = {
|
|
523
|
-
...trace,
|
|
524
|
-
attributes: JSON.stringify(trace.attributes),
|
|
525
|
-
status: JSON.stringify(trace.status),
|
|
526
|
-
events: JSON.stringify(trace.events),
|
|
527
|
-
links: JSON.stringify(trace.links),
|
|
528
|
-
other: JSON.stringify(trace.other)
|
|
529
|
-
};
|
|
530
|
-
await table.add([record], { mode: "append" });
|
|
531
|
-
return trace;
|
|
532
|
-
} catch (error) {
|
|
533
|
-
throw new Error(`Failed to save trace: ${error}`);
|
|
534
|
-
}
|
|
2075
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2076
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
535
2077
|
}
|
|
536
|
-
async
|
|
537
|
-
|
|
538
|
-
const table = await this.lanceClient.openTable(TABLE_TRACES);
|
|
539
|
-
const query = table.query().where(`id = '${traceId}'`);
|
|
540
|
-
const records = await query.toArray();
|
|
541
|
-
return this.processResultWithTypeConversion(records[0], await this.getTableSchema(TABLE_TRACES));
|
|
542
|
-
} catch (error) {
|
|
543
|
-
throw new Error(`Failed to get trace by ID: ${error}`);
|
|
544
|
-
}
|
|
2078
|
+
async getMessagesPaginated(args) {
|
|
2079
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
545
2080
|
}
|
|
546
|
-
async
|
|
547
|
-
|
|
548
|
-
scope,
|
|
549
|
-
page = 1,
|
|
550
|
-
perPage = 10,
|
|
551
|
-
attributes
|
|
552
|
-
}) {
|
|
553
|
-
try {
|
|
554
|
-
const table = await this.lanceClient.openTable(TABLE_TRACES);
|
|
555
|
-
const query = table.query();
|
|
556
|
-
if (name) {
|
|
557
|
-
query.where(`name = '${name}'`);
|
|
558
|
-
}
|
|
559
|
-
if (scope) {
|
|
560
|
-
query.where(`scope = '${scope}'`);
|
|
561
|
-
}
|
|
562
|
-
if (attributes) {
|
|
563
|
-
query.where(`attributes = '${JSON.stringify(attributes)}'`);
|
|
564
|
-
}
|
|
565
|
-
const offset = (page - 1) * perPage;
|
|
566
|
-
query.limit(perPage);
|
|
567
|
-
if (offset > 0) {
|
|
568
|
-
query.offset(offset);
|
|
569
|
-
}
|
|
570
|
-
const records = await query.toArray();
|
|
571
|
-
return records.map((record) => {
|
|
572
|
-
return {
|
|
573
|
-
...record,
|
|
574
|
-
attributes: JSON.parse(record.attributes),
|
|
575
|
-
status: JSON.parse(record.status),
|
|
576
|
-
events: JSON.parse(record.events),
|
|
577
|
-
links: JSON.parse(record.links),
|
|
578
|
-
other: JSON.parse(record.other),
|
|
579
|
-
startTime: new Date(record.startTime),
|
|
580
|
-
endTime: new Date(record.endTime),
|
|
581
|
-
createdAt: new Date(record.createdAt)
|
|
582
|
-
};
|
|
583
|
-
});
|
|
584
|
-
} catch (error) {
|
|
585
|
-
throw new Error(`Failed to get traces: ${error}`);
|
|
586
|
-
}
|
|
2081
|
+
async updateMessages(_args) {
|
|
2082
|
+
return this.stores.memory.updateMessages(_args);
|
|
587
2083
|
}
|
|
588
|
-
async
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
result: JSON.stringify(evalRecord.result),
|
|
597
|
-
instructions: evalRecord.instructions,
|
|
598
|
-
test_info: JSON.stringify(evalRecord.testInfo),
|
|
599
|
-
global_run_id: evalRecord.globalRunId,
|
|
600
|
-
run_id: evalRecord.runId,
|
|
601
|
-
created_at: new Date(evalRecord.createdAt).getTime()
|
|
602
|
-
}));
|
|
603
|
-
await table.add(transformedEvals, { mode: "append" });
|
|
604
|
-
return evals;
|
|
605
|
-
} catch (error) {
|
|
606
|
-
throw new Error(`Failed to save evals: ${error}`);
|
|
607
|
-
}
|
|
2084
|
+
async getTraceById(args) {
|
|
2085
|
+
return this.stores.traces.getTraceById(args);
|
|
2086
|
+
}
|
|
2087
|
+
async getTraces(args) {
|
|
2088
|
+
return this.stores.traces.getTraces(args);
|
|
2089
|
+
}
|
|
2090
|
+
async getTracesPaginated(args) {
|
|
2091
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
608
2092
|
}
|
|
609
2093
|
async getEvalsByAgentName(agentName, type) {
|
|
610
|
-
|
|
611
|
-
if (type) {
|
|
612
|
-
this.logger.warn("Type is not implemented yet in LanceDB storage");
|
|
613
|
-
}
|
|
614
|
-
const table = await this.lanceClient.openTable(TABLE_EVALS);
|
|
615
|
-
const query = table.query().where(`agent_name = '${agentName}'`);
|
|
616
|
-
const records = await query.toArray();
|
|
617
|
-
return records.map((record) => {
|
|
618
|
-
return {
|
|
619
|
-
id: record.id,
|
|
620
|
-
input: record.input,
|
|
621
|
-
output: record.output,
|
|
622
|
-
agentName: record.agent_name,
|
|
623
|
-
metricName: record.metric_name,
|
|
624
|
-
result: JSON.parse(record.result),
|
|
625
|
-
instructions: record.instructions,
|
|
626
|
-
testInfo: JSON.parse(record.test_info),
|
|
627
|
-
globalRunId: record.global_run_id,
|
|
628
|
-
runId: record.run_id,
|
|
629
|
-
createdAt: new Date(record.created_at).toString()
|
|
630
|
-
};
|
|
631
|
-
});
|
|
632
|
-
} catch (error) {
|
|
633
|
-
throw new Error(`Failed to get evals by agent name: ${error}`);
|
|
634
|
-
}
|
|
2094
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
635
2095
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (typeof parsedSnapshot === "string") {
|
|
639
|
-
try {
|
|
640
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
641
|
-
} catch (e) {
|
|
642
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
return {
|
|
646
|
-
workflowName: row.workflow_name,
|
|
647
|
-
runId: row.run_id,
|
|
648
|
-
snapshot: parsedSnapshot,
|
|
649
|
-
createdAt: this.ensureDate(row.createdAt),
|
|
650
|
-
updatedAt: this.ensureDate(row.updatedAt),
|
|
651
|
-
resourceId: row.resourceId
|
|
652
|
-
};
|
|
2096
|
+
async getEvals(options) {
|
|
2097
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
653
2098
|
}
|
|
654
2099
|
async getWorkflowRuns(args) {
|
|
655
|
-
|
|
656
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
657
|
-
const query = table.query();
|
|
658
|
-
if (args?.workflowName) {
|
|
659
|
-
query.where(`workflow_name = '${args.workflowName}'`);
|
|
660
|
-
}
|
|
661
|
-
if (args?.fromDate) {
|
|
662
|
-
query.where(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
663
|
-
}
|
|
664
|
-
if (args?.toDate) {
|
|
665
|
-
query.where(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
666
|
-
}
|
|
667
|
-
if (args?.limit) {
|
|
668
|
-
query.limit(args.limit);
|
|
669
|
-
}
|
|
670
|
-
if (args?.offset) {
|
|
671
|
-
query.offset(args.offset);
|
|
672
|
-
}
|
|
673
|
-
const records = await query.toArray();
|
|
674
|
-
return {
|
|
675
|
-
runs: records.map((record) => this.parseWorkflowRun(record)),
|
|
676
|
-
total: records.length
|
|
677
|
-
};
|
|
678
|
-
} catch (error) {
|
|
679
|
-
throw new Error(`Failed to get workflow runs: ${error}`);
|
|
680
|
-
}
|
|
2100
|
+
return this.stores.workflows.getWorkflowRuns(args);
|
|
681
2101
|
}
|
|
682
|
-
/**
|
|
683
|
-
* Retrieve a single workflow run by its runId.
|
|
684
|
-
* @param args The ID of the workflow run to retrieve
|
|
685
|
-
* @returns The workflow run object or null if not found
|
|
686
|
-
*/
|
|
687
2102
|
async getWorkflowRunById(args) {
|
|
688
|
-
|
|
689
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
690
|
-
let whereClause = `run_id = '${args.runId}'`;
|
|
691
|
-
if (args.workflowName) {
|
|
692
|
-
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
693
|
-
}
|
|
694
|
-
const query = table.query().where(whereClause);
|
|
695
|
-
const records = await query.toArray();
|
|
696
|
-
if (records.length === 0) return null;
|
|
697
|
-
const record = records[0];
|
|
698
|
-
return this.parseWorkflowRun(record);
|
|
699
|
-
} catch (error) {
|
|
700
|
-
throw new Error(`Failed to get workflow run by id: ${error}`);
|
|
701
|
-
}
|
|
2103
|
+
return this.stores.workflows.getWorkflowRunById(args);
|
|
702
2104
|
}
|
|
703
2105
|
async persistWorkflowSnapshot({
|
|
704
2106
|
workflowName,
|
|
705
2107
|
runId,
|
|
706
2108
|
snapshot
|
|
707
2109
|
}) {
|
|
708
|
-
|
|
709
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
710
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
711
|
-
const records = await query.toArray();
|
|
712
|
-
let createdAt;
|
|
713
|
-
const now = Date.now();
|
|
714
|
-
let mode = "append";
|
|
715
|
-
if (records.length > 0) {
|
|
716
|
-
createdAt = records[0].createdAt ?? now;
|
|
717
|
-
mode = "overwrite";
|
|
718
|
-
} else {
|
|
719
|
-
createdAt = now;
|
|
720
|
-
}
|
|
721
|
-
const record = {
|
|
722
|
-
workflow_name: workflowName,
|
|
723
|
-
run_id: runId,
|
|
724
|
-
snapshot: JSON.stringify(snapshot),
|
|
725
|
-
createdAt,
|
|
726
|
-
updatedAt: now
|
|
727
|
-
};
|
|
728
|
-
await table.add([record], { mode });
|
|
729
|
-
} catch (error) {
|
|
730
|
-
throw new Error(`Failed to persist workflow snapshot: ${error}`);
|
|
731
|
-
}
|
|
2110
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
732
2111
|
}
|
|
733
2112
|
async loadWorkflowSnapshot({
|
|
734
2113
|
workflowName,
|
|
735
2114
|
runId
|
|
736
2115
|
}) {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
742
|
-
} catch (error) {
|
|
743
|
-
throw new Error(`Failed to load workflow snapshot: ${error}`);
|
|
744
|
-
}
|
|
2116
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2117
|
+
}
|
|
2118
|
+
async getScoreById({ id: _id }) {
|
|
2119
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
745
2120
|
}
|
|
746
|
-
async
|
|
747
|
-
|
|
2121
|
+
async getScoresByScorerId({
|
|
2122
|
+
scorerId,
|
|
2123
|
+
pagination
|
|
2124
|
+
}) {
|
|
2125
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
|
|
748
2126
|
}
|
|
749
|
-
async
|
|
750
|
-
|
|
2127
|
+
async saveScore(_score) {
|
|
2128
|
+
return this.stores.scores.saveScore(_score);
|
|
751
2129
|
}
|
|
752
|
-
async
|
|
753
|
-
|
|
2130
|
+
async getScoresByRunId({
|
|
2131
|
+
runId,
|
|
2132
|
+
pagination
|
|
2133
|
+
}) {
|
|
2134
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
754
2135
|
}
|
|
755
|
-
async
|
|
756
|
-
|
|
757
|
-
|
|
2136
|
+
async getScoresByEntityId({
|
|
2137
|
+
entityId,
|
|
2138
|
+
entityType,
|
|
2139
|
+
pagination
|
|
2140
|
+
}) {
|
|
2141
|
+
return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
|
|
758
2142
|
}
|
|
759
2143
|
};
|
|
760
2144
|
var LanceFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -1108,7 +2492,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1108
2492
|
instance.lanceClient = await connect(uri, options);
|
|
1109
2493
|
return instance;
|
|
1110
2494
|
} catch (e) {
|
|
1111
|
-
throw new
|
|
2495
|
+
throw new MastraError(
|
|
2496
|
+
{
|
|
2497
|
+
id: "STORAGE_LANCE_VECTOR_CONNECT_FAILED",
|
|
2498
|
+
domain: ErrorDomain.STORAGE,
|
|
2499
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2500
|
+
details: { uri }
|
|
2501
|
+
},
|
|
2502
|
+
e
|
|
2503
|
+
);
|
|
1112
2504
|
}
|
|
1113
2505
|
}
|
|
1114
2506
|
/**
|
|
@@ -1132,14 +2524,27 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1132
2524
|
columns = [],
|
|
1133
2525
|
includeAllColumns = false
|
|
1134
2526
|
}) {
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
2527
|
+
try {
|
|
2528
|
+
if (!this.lanceClient) {
|
|
2529
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2530
|
+
}
|
|
2531
|
+
if (!tableName) {
|
|
2532
|
+
throw new Error("tableName is required");
|
|
2533
|
+
}
|
|
2534
|
+
if (!queryVector) {
|
|
2535
|
+
throw new Error("queryVector is required");
|
|
2536
|
+
}
|
|
2537
|
+
} catch (error) {
|
|
2538
|
+
throw new MastraError(
|
|
2539
|
+
{
|
|
2540
|
+
id: "STORAGE_LANCE_VECTOR_QUERY_FAILED_INVALID_ARGS",
|
|
2541
|
+
domain: ErrorDomain.STORAGE,
|
|
2542
|
+
category: ErrorCategory.USER,
|
|
2543
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
2544
|
+
details: { tableName }
|
|
2545
|
+
},
|
|
2546
|
+
error
|
|
2547
|
+
);
|
|
1143
2548
|
}
|
|
1144
2549
|
try {
|
|
1145
2550
|
const table = await this.lanceClient.openTable(tableName);
|
|
@@ -1178,7 +2583,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1178
2583
|
};
|
|
1179
2584
|
});
|
|
1180
2585
|
} catch (error) {
|
|
1181
|
-
throw new
|
|
2586
|
+
throw new MastraError(
|
|
2587
|
+
{
|
|
2588
|
+
id: "STORAGE_LANCE_VECTOR_QUERY_FAILED",
|
|
2589
|
+
domain: ErrorDomain.STORAGE,
|
|
2590
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2591
|
+
details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
|
|
2592
|
+
},
|
|
2593
|
+
error
|
|
2594
|
+
);
|
|
1182
2595
|
}
|
|
1183
2596
|
}
|
|
1184
2597
|
filterTranslator(filter) {
|
|
@@ -1211,14 +2624,27 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1211
2624
|
return translator.translate(prefixedFilter);
|
|
1212
2625
|
}
|
|
1213
2626
|
async upsert({ tableName, vectors, metadata = [], ids = [] }) {
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
2627
|
+
try {
|
|
2628
|
+
if (!this.lanceClient) {
|
|
2629
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2630
|
+
}
|
|
2631
|
+
if (!tableName) {
|
|
2632
|
+
throw new Error("tableName is required");
|
|
2633
|
+
}
|
|
2634
|
+
if (!vectors || !Array.isArray(vectors) || vectors.length === 0) {
|
|
2635
|
+
throw new Error("vectors array is required and must not be empty");
|
|
2636
|
+
}
|
|
2637
|
+
} catch (error) {
|
|
2638
|
+
throw new MastraError(
|
|
2639
|
+
{
|
|
2640
|
+
id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED_INVALID_ARGS",
|
|
2641
|
+
domain: ErrorDomain.STORAGE,
|
|
2642
|
+
category: ErrorCategory.USER,
|
|
2643
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
2644
|
+
details: { tableName }
|
|
2645
|
+
},
|
|
2646
|
+
error
|
|
2647
|
+
);
|
|
1222
2648
|
}
|
|
1223
2649
|
try {
|
|
1224
2650
|
const tables = await this.lanceClient.tableNames();
|
|
@@ -1245,7 +2671,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1245
2671
|
await table.add(data, { mode: "overwrite" });
|
|
1246
2672
|
return vectorIds;
|
|
1247
2673
|
} catch (error) {
|
|
1248
|
-
throw new
|
|
2674
|
+
throw new MastraError(
|
|
2675
|
+
{
|
|
2676
|
+
id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED",
|
|
2677
|
+
domain: ErrorDomain.STORAGE,
|
|
2678
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2679
|
+
details: { tableName, vectorCount: vectors.length, metadataCount: metadata.length, idsCount: ids.length }
|
|
2680
|
+
},
|
|
2681
|
+
error
|
|
2682
|
+
);
|
|
1249
2683
|
}
|
|
1250
2684
|
}
|
|
1251
2685
|
/**
|
|
@@ -1265,29 +2699,78 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1265
2699
|
}
|
|
1266
2700
|
async createTable(tableName, data, options) {
|
|
1267
2701
|
if (!this.lanceClient) {
|
|
1268
|
-
throw new
|
|
2702
|
+
throw new MastraError({
|
|
2703
|
+
id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED_INVALID_ARGS",
|
|
2704
|
+
domain: ErrorDomain.STORAGE,
|
|
2705
|
+
category: ErrorCategory.USER,
|
|
2706
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
2707
|
+
details: { tableName }
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
if (Array.isArray(data)) {
|
|
2711
|
+
data = data.map((record) => this.flattenObject(record));
|
|
1269
2712
|
}
|
|
1270
2713
|
try {
|
|
1271
|
-
if (Array.isArray(data)) {
|
|
1272
|
-
data = data.map((record) => this.flattenObject(record));
|
|
1273
|
-
}
|
|
1274
2714
|
return await this.lanceClient.createTable(tableName, data, options);
|
|
1275
2715
|
} catch (error) {
|
|
1276
|
-
throw new
|
|
2716
|
+
throw new MastraError(
|
|
2717
|
+
{
|
|
2718
|
+
id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED",
|
|
2719
|
+
domain: ErrorDomain.STORAGE,
|
|
2720
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2721
|
+
details: { tableName }
|
|
2722
|
+
},
|
|
2723
|
+
error
|
|
2724
|
+
);
|
|
1277
2725
|
}
|
|
1278
2726
|
}
|
|
1279
2727
|
async listTables() {
|
|
1280
2728
|
if (!this.lanceClient) {
|
|
1281
|
-
throw new
|
|
2729
|
+
throw new MastraError({
|
|
2730
|
+
id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED_INVALID_ARGS",
|
|
2731
|
+
domain: ErrorDomain.STORAGE,
|
|
2732
|
+
category: ErrorCategory.USER,
|
|
2733
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
2734
|
+
details: { methodName: "listTables" }
|
|
2735
|
+
});
|
|
2736
|
+
}
|
|
2737
|
+
try {
|
|
2738
|
+
return await this.lanceClient.tableNames();
|
|
2739
|
+
} catch (error) {
|
|
2740
|
+
throw new MastraError(
|
|
2741
|
+
{
|
|
2742
|
+
id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED",
|
|
2743
|
+
domain: ErrorDomain.STORAGE,
|
|
2744
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2745
|
+
},
|
|
2746
|
+
error
|
|
2747
|
+
);
|
|
1282
2748
|
}
|
|
1283
|
-
return await this.lanceClient.tableNames();
|
|
1284
2749
|
}
|
|
1285
2750
|
async getTableSchema(tableName) {
|
|
1286
2751
|
if (!this.lanceClient) {
|
|
1287
|
-
throw new
|
|
2752
|
+
throw new MastraError({
|
|
2753
|
+
id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED_INVALID_ARGS",
|
|
2754
|
+
domain: ErrorDomain.STORAGE,
|
|
2755
|
+
category: ErrorCategory.USER,
|
|
2756
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
2757
|
+
details: { tableName }
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
try {
|
|
2761
|
+
const table = await this.lanceClient.openTable(tableName);
|
|
2762
|
+
return await table.schema();
|
|
2763
|
+
} catch (error) {
|
|
2764
|
+
throw new MastraError(
|
|
2765
|
+
{
|
|
2766
|
+
id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED",
|
|
2767
|
+
domain: ErrorDomain.STORAGE,
|
|
2768
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2769
|
+
details: { tableName }
|
|
2770
|
+
},
|
|
2771
|
+
error
|
|
2772
|
+
);
|
|
1288
2773
|
}
|
|
1289
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
1290
|
-
return await table.schema();
|
|
1291
2774
|
}
|
|
1292
2775
|
/**
|
|
1293
2776
|
* indexName is actually a column name in a table in lanceDB
|
|
@@ -1299,10 +2782,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1299
2782
|
metric = "cosine",
|
|
1300
2783
|
indexConfig = {}
|
|
1301
2784
|
}) {
|
|
1302
|
-
if (!this.lanceClient) {
|
|
1303
|
-
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
1304
|
-
}
|
|
1305
2785
|
try {
|
|
2786
|
+
if (!this.lanceClient) {
|
|
2787
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2788
|
+
}
|
|
1306
2789
|
if (!tableName) {
|
|
1307
2790
|
throw new Error("tableName is required");
|
|
1308
2791
|
}
|
|
@@ -1312,6 +2795,18 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1312
2795
|
if (typeof dimension !== "number" || dimension <= 0) {
|
|
1313
2796
|
throw new Error("dimension must be a positive number");
|
|
1314
2797
|
}
|
|
2798
|
+
} catch (err) {
|
|
2799
|
+
throw new MastraError(
|
|
2800
|
+
{
|
|
2801
|
+
id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED_INVALID_ARGS",
|
|
2802
|
+
domain: ErrorDomain.STORAGE,
|
|
2803
|
+
category: ErrorCategory.USER,
|
|
2804
|
+
details: { tableName: tableName || "", indexName, dimension, metric }
|
|
2805
|
+
},
|
|
2806
|
+
err
|
|
2807
|
+
);
|
|
2808
|
+
}
|
|
2809
|
+
try {
|
|
1315
2810
|
const tables = await this.lanceClient.tableNames();
|
|
1316
2811
|
if (!tables.includes(tableName)) {
|
|
1317
2812
|
throw new Error(
|
|
@@ -1346,12 +2841,26 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1346
2841
|
});
|
|
1347
2842
|
}
|
|
1348
2843
|
} catch (error) {
|
|
1349
|
-
throw new
|
|
2844
|
+
throw new MastraError(
|
|
2845
|
+
{
|
|
2846
|
+
id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED",
|
|
2847
|
+
domain: ErrorDomain.STORAGE,
|
|
2848
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2849
|
+
details: { tableName: tableName || "", indexName, dimension }
|
|
2850
|
+
},
|
|
2851
|
+
error
|
|
2852
|
+
);
|
|
1350
2853
|
}
|
|
1351
2854
|
}
|
|
1352
2855
|
async listIndexes() {
|
|
1353
2856
|
if (!this.lanceClient) {
|
|
1354
|
-
throw new
|
|
2857
|
+
throw new MastraError({
|
|
2858
|
+
id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED_INVALID_ARGS",
|
|
2859
|
+
domain: ErrorDomain.STORAGE,
|
|
2860
|
+
category: ErrorCategory.USER,
|
|
2861
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
2862
|
+
details: { methodName: "listIndexes" }
|
|
2863
|
+
});
|
|
1355
2864
|
}
|
|
1356
2865
|
try {
|
|
1357
2866
|
const tables = await this.lanceClient.tableNames();
|
|
@@ -1363,15 +2872,34 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1363
2872
|
}
|
|
1364
2873
|
return allIndices;
|
|
1365
2874
|
} catch (error) {
|
|
1366
|
-
throw new
|
|
2875
|
+
throw new MastraError(
|
|
2876
|
+
{
|
|
2877
|
+
id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED",
|
|
2878
|
+
domain: ErrorDomain.STORAGE,
|
|
2879
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2880
|
+
},
|
|
2881
|
+
error
|
|
2882
|
+
);
|
|
1367
2883
|
}
|
|
1368
2884
|
}
|
|
1369
2885
|
async describeIndex({ indexName }) {
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
2886
|
+
try {
|
|
2887
|
+
if (!this.lanceClient) {
|
|
2888
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2889
|
+
}
|
|
2890
|
+
if (!indexName) {
|
|
2891
|
+
throw new Error("indexName is required");
|
|
2892
|
+
}
|
|
2893
|
+
} catch (err) {
|
|
2894
|
+
throw new MastraError(
|
|
2895
|
+
{
|
|
2896
|
+
id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED_INVALID_ARGS",
|
|
2897
|
+
domain: ErrorDomain.STORAGE,
|
|
2898
|
+
category: ErrorCategory.USER,
|
|
2899
|
+
details: { indexName }
|
|
2900
|
+
},
|
|
2901
|
+
err
|
|
2902
|
+
);
|
|
1375
2903
|
}
|
|
1376
2904
|
try {
|
|
1377
2905
|
const tables = await this.lanceClient.tableNames();
|
|
@@ -1398,15 +2926,35 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1398
2926
|
}
|
|
1399
2927
|
throw new Error(`IndexName: ${indexName} not found`);
|
|
1400
2928
|
} catch (error) {
|
|
1401
|
-
throw new
|
|
2929
|
+
throw new MastraError(
|
|
2930
|
+
{
|
|
2931
|
+
id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED",
|
|
2932
|
+
domain: ErrorDomain.STORAGE,
|
|
2933
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2934
|
+
details: { indexName }
|
|
2935
|
+
},
|
|
2936
|
+
error
|
|
2937
|
+
);
|
|
1402
2938
|
}
|
|
1403
2939
|
}
|
|
1404
2940
|
async deleteIndex({ indexName }) {
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
2941
|
+
try {
|
|
2942
|
+
if (!this.lanceClient) {
|
|
2943
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2944
|
+
}
|
|
2945
|
+
if (!indexName) {
|
|
2946
|
+
throw new Error("indexName is required");
|
|
2947
|
+
}
|
|
2948
|
+
} catch (err) {
|
|
2949
|
+
throw new MastraError(
|
|
2950
|
+
{
|
|
2951
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED_INVALID_ARGS",
|
|
2952
|
+
domain: ErrorDomain.STORAGE,
|
|
2953
|
+
category: ErrorCategory.USER,
|
|
2954
|
+
details: { indexName }
|
|
2955
|
+
},
|
|
2956
|
+
err
|
|
2957
|
+
);
|
|
1410
2958
|
}
|
|
1411
2959
|
try {
|
|
1412
2960
|
const tables = await this.lanceClient.tableNames();
|
|
@@ -1421,7 +2969,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1421
2969
|
}
|
|
1422
2970
|
throw new Error(`Index ${indexName} not found`);
|
|
1423
2971
|
} catch (error) {
|
|
1424
|
-
throw new
|
|
2972
|
+
throw new MastraError(
|
|
2973
|
+
{
|
|
2974
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED",
|
|
2975
|
+
domain: ErrorDomain.STORAGE,
|
|
2976
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2977
|
+
details: { indexName }
|
|
2978
|
+
},
|
|
2979
|
+
error
|
|
2980
|
+
);
|
|
1425
2981
|
}
|
|
1426
2982
|
}
|
|
1427
2983
|
/**
|
|
@@ -1429,33 +2985,73 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1429
2985
|
*/
|
|
1430
2986
|
async deleteAllTables() {
|
|
1431
2987
|
if (!this.lanceClient) {
|
|
1432
|
-
throw new
|
|
2988
|
+
throw new MastraError({
|
|
2989
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED_INVALID_ARGS",
|
|
2990
|
+
domain: ErrorDomain.STORAGE,
|
|
2991
|
+
category: ErrorCategory.USER,
|
|
2992
|
+
details: { methodName: "deleteAllTables" },
|
|
2993
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance"
|
|
2994
|
+
});
|
|
1433
2995
|
}
|
|
1434
2996
|
try {
|
|
1435
2997
|
await this.lanceClient.dropAllTables();
|
|
1436
2998
|
} catch (error) {
|
|
1437
|
-
throw new
|
|
2999
|
+
throw new MastraError(
|
|
3000
|
+
{
|
|
3001
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED",
|
|
3002
|
+
domain: ErrorDomain.STORAGE,
|
|
3003
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3004
|
+
details: { methodName: "deleteAllTables" }
|
|
3005
|
+
},
|
|
3006
|
+
error
|
|
3007
|
+
);
|
|
1438
3008
|
}
|
|
1439
3009
|
}
|
|
1440
3010
|
async deleteTable(tableName) {
|
|
1441
3011
|
if (!this.lanceClient) {
|
|
1442
|
-
throw new
|
|
3012
|
+
throw new MastraError({
|
|
3013
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED_INVALID_ARGS",
|
|
3014
|
+
domain: ErrorDomain.STORAGE,
|
|
3015
|
+
category: ErrorCategory.USER,
|
|
3016
|
+
details: { tableName },
|
|
3017
|
+
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance"
|
|
3018
|
+
});
|
|
1443
3019
|
}
|
|
1444
3020
|
try {
|
|
1445
3021
|
await this.lanceClient.dropTable(tableName);
|
|
1446
3022
|
} catch (error) {
|
|
1447
|
-
throw new
|
|
3023
|
+
throw new MastraError(
|
|
3024
|
+
{
|
|
3025
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED",
|
|
3026
|
+
domain: ErrorDomain.STORAGE,
|
|
3027
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3028
|
+
details: { tableName }
|
|
3029
|
+
},
|
|
3030
|
+
error
|
|
3031
|
+
);
|
|
1448
3032
|
}
|
|
1449
3033
|
}
|
|
1450
3034
|
async updateVector({ indexName, id, update }) {
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
3035
|
+
try {
|
|
3036
|
+
if (!this.lanceClient) {
|
|
3037
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
3038
|
+
}
|
|
3039
|
+
if (!indexName) {
|
|
3040
|
+
throw new Error("indexName is required");
|
|
3041
|
+
}
|
|
3042
|
+
if (!id) {
|
|
3043
|
+
throw new Error("id is required");
|
|
3044
|
+
}
|
|
3045
|
+
} catch (err) {
|
|
3046
|
+
throw new MastraError(
|
|
3047
|
+
{
|
|
3048
|
+
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
|
|
3049
|
+
domain: ErrorDomain.STORAGE,
|
|
3050
|
+
category: ErrorCategory.USER,
|
|
3051
|
+
details: { indexName, id }
|
|
3052
|
+
},
|
|
3053
|
+
err
|
|
3054
|
+
);
|
|
1459
3055
|
}
|
|
1460
3056
|
try {
|
|
1461
3057
|
const tables = await this.lanceClient.tableNames();
|
|
@@ -1509,18 +3105,38 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1509
3105
|
}
|
|
1510
3106
|
throw new Error(`No table found with column/index '${indexName}'`);
|
|
1511
3107
|
} catch (error) {
|
|
1512
|
-
throw new
|
|
3108
|
+
throw new MastraError(
|
|
3109
|
+
{
|
|
3110
|
+
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
|
|
3111
|
+
domain: ErrorDomain.STORAGE,
|
|
3112
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3113
|
+
details: { indexName, id, hasVector: !!update.vector, hasMetadata: !!update.metadata }
|
|
3114
|
+
},
|
|
3115
|
+
error
|
|
3116
|
+
);
|
|
1513
3117
|
}
|
|
1514
3118
|
}
|
|
1515
3119
|
async deleteVector({ indexName, id }) {
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
3120
|
+
try {
|
|
3121
|
+
if (!this.lanceClient) {
|
|
3122
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
3123
|
+
}
|
|
3124
|
+
if (!indexName) {
|
|
3125
|
+
throw new Error("indexName is required");
|
|
3126
|
+
}
|
|
3127
|
+
if (!id) {
|
|
3128
|
+
throw new Error("id is required");
|
|
3129
|
+
}
|
|
3130
|
+
} catch (err) {
|
|
3131
|
+
throw new MastraError(
|
|
3132
|
+
{
|
|
3133
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
|
|
3134
|
+
domain: ErrorDomain.STORAGE,
|
|
3135
|
+
category: ErrorCategory.USER,
|
|
3136
|
+
details: { indexName, id }
|
|
3137
|
+
},
|
|
3138
|
+
err
|
|
3139
|
+
);
|
|
1524
3140
|
}
|
|
1525
3141
|
try {
|
|
1526
3142
|
const tables = await this.lanceClient.tableNames();
|
|
@@ -1542,7 +3158,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1542
3158
|
}
|
|
1543
3159
|
throw new Error(`No table found with column/index '${indexName}'`);
|
|
1544
3160
|
} catch (error) {
|
|
1545
|
-
throw new
|
|
3161
|
+
throw new MastraError(
|
|
3162
|
+
{
|
|
3163
|
+
id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
|
|
3164
|
+
domain: ErrorDomain.STORAGE,
|
|
3165
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
3166
|
+
details: { indexName, id }
|
|
3167
|
+
},
|
|
3168
|
+
error
|
|
3169
|
+
);
|
|
1546
3170
|
}
|
|
1547
3171
|
}
|
|
1548
3172
|
/**
|
|
@@ -1573,3 +3197,5 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
1573
3197
|
};
|
|
1574
3198
|
|
|
1575
3199
|
export { LanceStorage, LanceVectorStore };
|
|
3200
|
+
//# sourceMappingURL=index.js.map
|
|
3201
|
+
//# sourceMappingURL=index.js.map
|