@mastra/lance 0.0.0-mcp-changeset-20250707162621 → 0.0.0-memory-system-message-error-20250813233316
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 +177 -9
- package/LICENSE.md +11 -42
- package/dist/index.cjs +1649 -643
- 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 +1584 -578
- 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 +42 -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 +236 -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 +11 -10
- 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 +243 -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 -1332
- package/src/storage/index.ts +163 -1162
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +1 -1
- package/tsup.config.ts +17 -0
- package/dist/_tsup-dts-rollup.d.cts +0 -409
- package/dist/_tsup-dts-rollup.d.ts +0 -409
- package/dist/index.d.cts +0 -2
package/dist/index.js
CHANGED
|
@@ -1,110 +1,978 @@
|
|
|
1
1
|
import { connect, Index } from '@lancedb/lancedb';
|
|
2
|
-
import { MessageList } from '@mastra/core/agent';
|
|
3
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
4
|
-
import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES,
|
|
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';
|
|
4
|
+
import { MessageList } from '@mastra/core/agent';
|
|
5
5
|
import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
|
|
6
6
|
import { MastraVector } from '@mastra/core/vector';
|
|
7
7
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
8
8
|
|
|
9
9
|
// src/storage/index.ts
|
|
10
|
-
var
|
|
11
|
-
|
|
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
|
+
}
|
|
12
292
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param
|
|
15
|
-
* @
|
|
16
|
-
*
|
|
17
|
-
* Usage:
|
|
18
|
-
*
|
|
19
|
-
* Connect to a local database
|
|
20
|
-
* ```ts
|
|
21
|
-
* const store = await LanceStorage.create('/path/to/db');
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* Connect to a LanceDB cloud database
|
|
25
|
-
* ```ts
|
|
26
|
-
* const store = await LanceStorage.create('db://host:port');
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* Connect to a cloud database
|
|
30
|
-
* ```ts
|
|
31
|
-
* const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
32
|
-
* ```
|
|
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
|
|
33
296
|
*/
|
|
34
|
-
|
|
35
|
-
const instance = new _LanceStorage(name);
|
|
297
|
+
async saveThread({ thread }) {
|
|
36
298
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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) {
|
|
40
693
|
throw new MastraError(
|
|
41
694
|
{
|
|
42
|
-
id: "
|
|
695
|
+
id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
|
|
43
696
|
domain: ErrorDomain.STORAGE,
|
|
44
|
-
category: ErrorCategory.THIRD_PARTY
|
|
45
|
-
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
46
|
-
details: { uri, optionsProvided: !!options }
|
|
697
|
+
category: ErrorCategory.THIRD_PARTY
|
|
47
698
|
},
|
|
48
|
-
|
|
699
|
+
error
|
|
49
700
|
);
|
|
50
701
|
}
|
|
51
702
|
}
|
|
52
|
-
getPrimaryKeys(tableName) {
|
|
53
|
-
let primaryId = ["id"];
|
|
54
|
-
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
55
|
-
primaryId = ["workflow_name", "run_id"];
|
|
56
|
-
} else if (tableName === TABLE_EVALS) {
|
|
57
|
-
primaryId = ["agent_name", "metric_name", "run_id"];
|
|
58
|
-
}
|
|
59
|
-
return primaryId;
|
|
60
|
-
}
|
|
61
703
|
/**
|
|
62
|
-
*
|
|
63
|
-
* Private constructor to enforce using the create factory method
|
|
704
|
+
* Parse message data from LanceDB record format to MastraMessageV2 format
|
|
64
705
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
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
|
+
};
|
|
67
721
|
}
|
|
68
|
-
async
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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();
|
|
72
730
|
try {
|
|
73
|
-
|
|
74
|
-
|
|
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
|
+
}
|
|
75
771
|
}
|
|
76
|
-
|
|
77
|
-
|
|
772
|
+
for (const threadId of affectedThreadIds) {
|
|
773
|
+
await this.operations.insert({
|
|
774
|
+
tableName: TABLE_THREADS,
|
|
775
|
+
record: { id: threadId, updatedAt: Date.now() }
|
|
776
|
+
});
|
|
78
777
|
}
|
|
79
|
-
|
|
80
|
-
|
|
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
|
+
}
|
|
81
848
|
}
|
|
849
|
+
return {
|
|
850
|
+
...resource,
|
|
851
|
+
createdAt,
|
|
852
|
+
updatedAt,
|
|
853
|
+
workingMemory,
|
|
854
|
+
metadata
|
|
855
|
+
};
|
|
82
856
|
} catch (error) {
|
|
83
857
|
throw new MastraError(
|
|
84
858
|
{
|
|
85
|
-
id: "
|
|
859
|
+
id: "LANCE_STORE_GET_RESOURCE_BY_ID_FAILED",
|
|
86
860
|
domain: ErrorDomain.STORAGE,
|
|
87
|
-
category: ErrorCategory.
|
|
88
|
-
details: { tableName }
|
|
861
|
+
category: ErrorCategory.THIRD_PARTY
|
|
89
862
|
},
|
|
90
863
|
error
|
|
91
864
|
);
|
|
92
865
|
}
|
|
866
|
+
}
|
|
867
|
+
async saveResource({ resource }) {
|
|
93
868
|
try {
|
|
94
|
-
const
|
|
95
|
-
|
|
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;
|
|
96
880
|
} catch (error) {
|
|
97
881
|
throw new MastraError(
|
|
98
882
|
{
|
|
99
|
-
id: "
|
|
883
|
+
id: "LANCE_STORE_SAVE_RESOURCE_FAILED",
|
|
100
884
|
domain: ErrorDomain.STORAGE,
|
|
101
|
-
category: ErrorCategory.THIRD_PARTY
|
|
102
|
-
details: { tableName }
|
|
885
|
+
category: ErrorCategory.THIRD_PARTY
|
|
103
886
|
},
|
|
104
887
|
error
|
|
105
888
|
);
|
|
106
889
|
}
|
|
107
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
|
+
}
|
|
108
976
|
translateSchema(schema) {
|
|
109
977
|
const fields = Object.entries(schema).map(([name, column]) => {
|
|
110
978
|
let arrowType;
|
|
@@ -140,40 +1008,42 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
140
1008
|
});
|
|
141
1009
|
return new Schema(fields);
|
|
142
1010
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
async dropTable(tableName) {
|
|
1011
|
+
async createTable({
|
|
1012
|
+
tableName,
|
|
1013
|
+
schema
|
|
1014
|
+
}) {
|
|
148
1015
|
try {
|
|
149
|
-
if (!this.
|
|
1016
|
+
if (!this.client) {
|
|
150
1017
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
151
1018
|
}
|
|
152
1019
|
if (!tableName) {
|
|
153
|
-
throw new Error("tableName is required for
|
|
1020
|
+
throw new Error("tableName is required for createTable.");
|
|
154
1021
|
}
|
|
155
|
-
|
|
1022
|
+
if (!schema) {
|
|
1023
|
+
throw new Error("schema is required for createTable.");
|
|
1024
|
+
}
|
|
1025
|
+
} catch (error) {
|
|
156
1026
|
throw new MastraError(
|
|
157
1027
|
{
|
|
158
|
-
id: "
|
|
1028
|
+
id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
|
|
159
1029
|
domain: ErrorDomain.STORAGE,
|
|
160
1030
|
category: ErrorCategory.USER,
|
|
161
|
-
text: validationError.message,
|
|
162
1031
|
details: { tableName }
|
|
163
1032
|
},
|
|
164
|
-
|
|
1033
|
+
error
|
|
165
1034
|
);
|
|
166
1035
|
}
|
|
167
1036
|
try {
|
|
168
|
-
|
|
1037
|
+
const arrowSchema = this.translateSchema(schema);
|
|
1038
|
+
await this.client.createEmptyTable(tableName, arrowSchema);
|
|
169
1039
|
} catch (error) {
|
|
170
|
-
if (error.
|
|
171
|
-
this.logger.debug(`Table '${tableName}'
|
|
1040
|
+
if (error.message?.includes("already exists")) {
|
|
1041
|
+
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
172
1042
|
return;
|
|
173
1043
|
}
|
|
174
1044
|
throw new MastraError(
|
|
175
1045
|
{
|
|
176
|
-
id: "
|
|
1046
|
+
id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
|
|
177
1047
|
domain: ErrorDomain.STORAGE,
|
|
178
1048
|
category: ErrorCategory.THIRD_PARTY,
|
|
179
1049
|
details: { tableName }
|
|
@@ -182,23 +1052,18 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
182
1052
|
);
|
|
183
1053
|
}
|
|
184
1054
|
}
|
|
185
|
-
|
|
186
|
-
* Get table schema
|
|
187
|
-
* @param tableName Name of the table
|
|
188
|
-
* @returns Table schema
|
|
189
|
-
*/
|
|
190
|
-
async getTableSchema(tableName) {
|
|
1055
|
+
async dropTable({ tableName }) {
|
|
191
1056
|
try {
|
|
192
|
-
if (!this.
|
|
1057
|
+
if (!this.client) {
|
|
193
1058
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
194
1059
|
}
|
|
195
1060
|
if (!tableName) {
|
|
196
|
-
throw new Error("tableName is required for
|
|
1061
|
+
throw new Error("tableName is required for dropTable.");
|
|
197
1062
|
}
|
|
198
1063
|
} catch (validationError) {
|
|
199
1064
|
throw new MastraError(
|
|
200
1065
|
{
|
|
201
|
-
id: "
|
|
1066
|
+
id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
|
|
202
1067
|
domain: ErrorDomain.STORAGE,
|
|
203
1068
|
category: ErrorCategory.USER,
|
|
204
1069
|
text: validationError.message,
|
|
@@ -208,20 +1073,15 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
208
1073
|
);
|
|
209
1074
|
}
|
|
210
1075
|
try {
|
|
211
|
-
|
|
212
|
-
const rawSchema = await table.schema();
|
|
213
|
-
const fields = rawSchema.fields;
|
|
214
|
-
return {
|
|
215
|
-
fields,
|
|
216
|
-
metadata: /* @__PURE__ */ new Map(),
|
|
217
|
-
get names() {
|
|
218
|
-
return fields.map((field) => field.name);
|
|
219
|
-
}
|
|
220
|
-
};
|
|
1076
|
+
await this.client.dropTable(tableName);
|
|
221
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
|
+
}
|
|
222
1082
|
throw new MastraError(
|
|
223
1083
|
{
|
|
224
|
-
id: "
|
|
1084
|
+
id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
|
|
225
1085
|
domain: ErrorDomain.STORAGE,
|
|
226
1086
|
category: ErrorCategory.THIRD_PARTY,
|
|
227
1087
|
details: { tableName }
|
|
@@ -230,36 +1090,13 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
230
1090
|
);
|
|
231
1091
|
}
|
|
232
1092
|
}
|
|
233
|
-
getDefaultValue(type) {
|
|
234
|
-
switch (type) {
|
|
235
|
-
case "text":
|
|
236
|
-
return "''";
|
|
237
|
-
case "timestamp":
|
|
238
|
-
return "CURRENT_TIMESTAMP";
|
|
239
|
-
case "integer":
|
|
240
|
-
case "bigint":
|
|
241
|
-
return "0";
|
|
242
|
-
case "jsonb":
|
|
243
|
-
return "'{}'";
|
|
244
|
-
case "uuid":
|
|
245
|
-
return "''";
|
|
246
|
-
default:
|
|
247
|
-
return super.getDefaultValue(type);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Alters table schema to add columns if they don't exist
|
|
252
|
-
* @param tableName Name of the table
|
|
253
|
-
* @param schema Schema of the table
|
|
254
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
255
|
-
*/
|
|
256
1093
|
async alterTable({
|
|
257
1094
|
tableName,
|
|
258
1095
|
schema,
|
|
259
1096
|
ifNotExists
|
|
260
1097
|
}) {
|
|
261
1098
|
try {
|
|
262
|
-
if (!this.
|
|
1099
|
+
if (!this.client) {
|
|
263
1100
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
264
1101
|
}
|
|
265
1102
|
if (!tableName) {
|
|
@@ -285,7 +1122,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
285
1122
|
);
|
|
286
1123
|
}
|
|
287
1124
|
try {
|
|
288
|
-
const table = await this.
|
|
1125
|
+
const table = await this.client.openTable(tableName);
|
|
289
1126
|
const currentSchema = await table.schema();
|
|
290
1127
|
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
291
1128
|
const typeMap = {
|
|
@@ -321,7 +1158,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
321
1158
|
}
|
|
322
1159
|
async clearTable({ tableName }) {
|
|
323
1160
|
try {
|
|
324
|
-
if (!this.
|
|
1161
|
+
if (!this.client) {
|
|
325
1162
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
326
1163
|
}
|
|
327
1164
|
if (!tableName) {
|
|
@@ -340,7 +1177,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
340
1177
|
);
|
|
341
1178
|
}
|
|
342
1179
|
try {
|
|
343
|
-
const table = await this.
|
|
1180
|
+
const table = await this.client.openTable(tableName);
|
|
344
1181
|
await table.delete("1=1");
|
|
345
1182
|
} catch (error) {
|
|
346
1183
|
throw new MastraError(
|
|
@@ -354,14 +1191,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
354
1191
|
);
|
|
355
1192
|
}
|
|
356
1193
|
}
|
|
357
|
-
/**
|
|
358
|
-
* Insert a single record into a table. This function overwrites the existing record if it exists. Use this function for inserting records into tables with custom schemas.
|
|
359
|
-
* @param tableName The name of the table to insert into.
|
|
360
|
-
* @param record The record to insert.
|
|
361
|
-
*/
|
|
362
1194
|
async insert({ tableName, record }) {
|
|
363
1195
|
try {
|
|
364
|
-
if (!this.
|
|
1196
|
+
if (!this.client) {
|
|
365
1197
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
366
1198
|
}
|
|
367
1199
|
if (!tableName) {
|
|
@@ -383,8 +1215,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
383
1215
|
);
|
|
384
1216
|
}
|
|
385
1217
|
try {
|
|
386
|
-
const table = await this.
|
|
387
|
-
const primaryId =
|
|
1218
|
+
const table = await this.client.openTable(tableName);
|
|
1219
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
388
1220
|
const processedRecord = { ...record };
|
|
389
1221
|
for (const key in processedRecord) {
|
|
390
1222
|
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
@@ -392,6 +1224,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
392
1224
|
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
393
1225
|
}
|
|
394
1226
|
}
|
|
1227
|
+
console.log(await table.schema());
|
|
395
1228
|
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
396
1229
|
} catch (error) {
|
|
397
1230
|
throw new MastraError(
|
|
@@ -405,14 +1238,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
405
1238
|
);
|
|
406
1239
|
}
|
|
407
1240
|
}
|
|
408
|
-
/**
|
|
409
|
-
* Insert multiple records into a table. This function overwrites the existing records if they exist. Use this function for inserting records into tables with custom schemas.
|
|
410
|
-
* @param tableName The name of the table to insert into.
|
|
411
|
-
* @param records The records to insert.
|
|
412
|
-
*/
|
|
413
1241
|
async batchInsert({ tableName, records }) {
|
|
414
1242
|
try {
|
|
415
|
-
if (!this.
|
|
1243
|
+
if (!this.client) {
|
|
416
1244
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
417
1245
|
}
|
|
418
1246
|
if (!tableName) {
|
|
@@ -434,8 +1262,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
434
1262
|
);
|
|
435
1263
|
}
|
|
436
1264
|
try {
|
|
437
|
-
const table = await this.
|
|
438
|
-
const primaryId =
|
|
1265
|
+
const table = await this.client.openTable(tableName);
|
|
1266
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
439
1267
|
const processedRecords = records.map((record) => {
|
|
440
1268
|
const processedRecord = { ...record };
|
|
441
1269
|
for (const key in processedRecord) {
|
|
@@ -446,6 +1274,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
446
1274
|
}
|
|
447
1275
|
return processedRecord;
|
|
448
1276
|
});
|
|
1277
|
+
console.log(processedRecords);
|
|
449
1278
|
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
|
|
450
1279
|
} catch (error) {
|
|
451
1280
|
throw new MastraError(
|
|
@@ -459,16 +1288,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
459
1288
|
);
|
|
460
1289
|
}
|
|
461
1290
|
}
|
|
462
|
-
/**
|
|
463
|
-
* Load a record from the database by its key(s)
|
|
464
|
-
* @param tableName The name of the table to query
|
|
465
|
-
* @param keys Record of key-value pairs to use for lookup
|
|
466
|
-
* @throws Error if invalid types are provided for keys
|
|
467
|
-
* @returns The loaded record with proper type conversions, or null if not found
|
|
468
|
-
*/
|
|
469
1291
|
async load({ tableName, keys }) {
|
|
470
1292
|
try {
|
|
471
|
-
if (!this.
|
|
1293
|
+
if (!this.client) {
|
|
472
1294
|
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
473
1295
|
}
|
|
474
1296
|
if (!tableName) {
|
|
@@ -490,11 +1312,11 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
490
1312
|
);
|
|
491
1313
|
}
|
|
492
1314
|
try {
|
|
493
|
-
const table = await this.
|
|
494
|
-
const tableSchema = await
|
|
1315
|
+
const table = await this.client.openTable(tableName);
|
|
1316
|
+
const tableSchema = await getTableSchema({ tableName, client: this.client });
|
|
495
1317
|
const query = table.query();
|
|
496
1318
|
if (Object.keys(keys).length > 0) {
|
|
497
|
-
|
|
1319
|
+
validateKeyTypes(keys, tableSchema);
|
|
498
1320
|
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
499
1321
|
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
500
1322
|
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
@@ -508,330 +1330,228 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
508
1330
|
}).join(" AND ");
|
|
509
1331
|
this.logger.debug("where clause generated: " + filterConditions);
|
|
510
1332
|
query.where(filterConditions);
|
|
511
|
-
}
|
|
512
|
-
const result = await query.limit(1).toArray();
|
|
513
|
-
if (result.length === 0) {
|
|
514
|
-
this.logger.debug("No record found");
|
|
515
|
-
return null;
|
|
516
|
-
}
|
|
517
|
-
return
|
|
518
|
-
} catch (error) {
|
|
519
|
-
if (error instanceof MastraError) throw error;
|
|
520
|
-
throw new MastraError(
|
|
521
|
-
{
|
|
522
|
-
id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
|
|
523
|
-
domain: ErrorDomain.STORAGE,
|
|
524
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
525
|
-
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
526
|
-
},
|
|
527
|
-
error
|
|
528
|
-
);
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
/**
|
|
532
|
-
* Validates that key types match the schema definition
|
|
533
|
-
* @param keys The keys to validate
|
|
534
|
-
* @param tableSchema The table schema to validate against
|
|
535
|
-
* @throws Error if a key has an incompatible type
|
|
536
|
-
*/
|
|
537
|
-
validateKeyTypes(keys, tableSchema) {
|
|
538
|
-
const fieldTypes = new Map(
|
|
539
|
-
tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
|
|
540
|
-
);
|
|
541
|
-
for (const [key, value] of Object.entries(keys)) {
|
|
542
|
-
const fieldType = fieldTypes.get(key);
|
|
543
|
-
if (!fieldType) {
|
|
544
|
-
throw new Error(`Field '${key}' does not exist in table schema`);
|
|
545
|
-
}
|
|
546
|
-
if (value !== null) {
|
|
547
|
-
if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
|
|
548
|
-
throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
|
|
549
|
-
}
|
|
550
|
-
if (fieldType.includes("utf8") && typeof value !== "string") {
|
|
551
|
-
throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
|
|
552
|
-
}
|
|
553
|
-
if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
|
|
554
|
-
throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Process a database result with appropriate type conversions based on the table schema
|
|
561
|
-
* @param rawResult The raw result object from the database
|
|
562
|
-
* @param tableSchema The schema of the table containing type information
|
|
563
|
-
* @returns Processed result with correct data types
|
|
564
|
-
*/
|
|
565
|
-
processResultWithTypeConversion(rawResult, tableSchema) {
|
|
566
|
-
const fieldTypeMap = /* @__PURE__ */ new Map();
|
|
567
|
-
tableSchema.fields.forEach((field) => {
|
|
568
|
-
const fieldName = field.name;
|
|
569
|
-
const fieldTypeStr = field.type.toString().toLowerCase();
|
|
570
|
-
fieldTypeMap.set(fieldName, fieldTypeStr);
|
|
571
|
-
});
|
|
572
|
-
if (Array.isArray(rawResult)) {
|
|
573
|
-
return rawResult.map((item) => this.processResultWithTypeConversion(item, tableSchema));
|
|
574
|
-
}
|
|
575
|
-
const processedResult = { ...rawResult };
|
|
576
|
-
for (const key in processedResult) {
|
|
577
|
-
const fieldTypeStr = fieldTypeMap.get(key);
|
|
578
|
-
if (!fieldTypeStr) continue;
|
|
579
|
-
if (typeof processedResult[key] === "string") {
|
|
580
|
-
if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
|
|
581
|
-
if (!isNaN(Number(processedResult[key]))) {
|
|
582
|
-
processedResult[key] = Number(processedResult[key]);
|
|
583
|
-
}
|
|
584
|
-
} else if (fieldTypeStr.includes("int64")) {
|
|
585
|
-
processedResult[key] = Number(processedResult[key]);
|
|
586
|
-
} else if (fieldTypeStr.includes("utf8")) {
|
|
587
|
-
try {
|
|
588
|
-
processedResult[key] = JSON.parse(processedResult[key]);
|
|
589
|
-
} catch (e) {
|
|
590
|
-
this.logger.debug(`Failed to parse JSON for key ${key}: ${e}`);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
} else if (typeof processedResult[key] === "bigint") {
|
|
594
|
-
processedResult[key] = Number(processedResult[key]);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return processedResult;
|
|
598
|
-
}
|
|
599
|
-
getThreadById({ threadId }) {
|
|
600
|
-
try {
|
|
601
|
-
return this.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
|
|
602
|
-
} catch (error) {
|
|
603
|
-
throw new MastraError(
|
|
604
|
-
{
|
|
605
|
-
id: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
|
|
606
|
-
domain: ErrorDomain.STORAGE,
|
|
607
|
-
category: ErrorCategory.THIRD_PARTY
|
|
608
|
-
},
|
|
609
|
-
error
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
async getThreadsByResourceId({ resourceId }) {
|
|
614
|
-
try {
|
|
615
|
-
const table = await this.lanceClient.openTable(TABLE_THREADS);
|
|
616
|
-
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
617
|
-
const records = await query.toArray();
|
|
618
|
-
return this.processResultWithTypeConversion(
|
|
619
|
-
records,
|
|
620
|
-
await this.getTableSchema(TABLE_THREADS)
|
|
621
|
-
);
|
|
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);
|
|
622
1340
|
} catch (error) {
|
|
1341
|
+
if (error instanceof MastraError) throw error;
|
|
623
1342
|
throw new MastraError(
|
|
624
1343
|
{
|
|
625
|
-
id: "
|
|
1344
|
+
id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
|
|
626
1345
|
domain: ErrorDomain.STORAGE,
|
|
627
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1346
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1347
|
+
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
628
1348
|
},
|
|
629
1349
|
error
|
|
630
1350
|
);
|
|
631
1351
|
}
|
|
632
1352
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
1353
|
+
};
|
|
1354
|
+
var StoreScoresLance = class extends ScoresStorage {
|
|
1355
|
+
client;
|
|
1356
|
+
constructor({ client }) {
|
|
1357
|
+
super();
|
|
1358
|
+
this.client = client;
|
|
1359
|
+
}
|
|
1360
|
+
async saveScore(score) {
|
|
639
1361
|
try {
|
|
640
|
-
const
|
|
641
|
-
const table = await this.
|
|
642
|
-
await
|
|
643
|
-
|
|
1362
|
+
const id = crypto.randomUUID();
|
|
1363
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1364
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1365
|
+
const allowedFields = new Set(schema.fields.map((f) => f.name));
|
|
1366
|
+
const filteredScore = {};
|
|
1367
|
+
Object.keys(score).forEach((key) => {
|
|
1368
|
+
if (allowedFields.has(key)) {
|
|
1369
|
+
filteredScore[key] = score[key];
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
for (const key in filteredScore) {
|
|
1373
|
+
if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
|
|
1374
|
+
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
filteredScore.id = id;
|
|
1378
|
+
await table.add([filteredScore], { mode: "append" });
|
|
1379
|
+
return { score };
|
|
644
1380
|
} catch (error) {
|
|
645
1381
|
throw new MastraError(
|
|
646
1382
|
{
|
|
647
|
-
id: "
|
|
1383
|
+
id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
|
|
1384
|
+
text: "Failed to save score in LanceStorage",
|
|
648
1385
|
domain: ErrorDomain.STORAGE,
|
|
649
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1386
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1387
|
+
details: { error: error?.message }
|
|
650
1388
|
},
|
|
651
1389
|
error
|
|
652
1390
|
);
|
|
653
1391
|
}
|
|
654
1392
|
}
|
|
655
|
-
async
|
|
656
|
-
id,
|
|
657
|
-
title,
|
|
658
|
-
metadata
|
|
659
|
-
}) {
|
|
1393
|
+
async getScoreById({ id }) {
|
|
660
1394
|
try {
|
|
661
|
-
const
|
|
662
|
-
const
|
|
663
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
664
|
-
const query = table.query().where(`id = '${id}'`);
|
|
1395
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1396
|
+
const query = table.query().where(`id = '${id}'`).limit(1);
|
|
665
1397
|
const records = await query.toArray();
|
|
666
|
-
return
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
);
|
|
1398
|
+
if (records.length === 0) return null;
|
|
1399
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1400
|
+
return processResultWithTypeConversion(records[0], schema);
|
|
670
1401
|
} catch (error) {
|
|
671
1402
|
throw new MastraError(
|
|
672
1403
|
{
|
|
673
|
-
id: "
|
|
1404
|
+
id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
|
|
1405
|
+
text: "Failed to get score by id in LanceStorage",
|
|
674
1406
|
domain: ErrorDomain.STORAGE,
|
|
675
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1407
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1408
|
+
details: { error: error?.message }
|
|
676
1409
|
},
|
|
677
1410
|
error
|
|
678
1411
|
);
|
|
679
1412
|
}
|
|
680
1413
|
}
|
|
681
|
-
async
|
|
1414
|
+
async getScoresByScorerId({
|
|
1415
|
+
scorerId,
|
|
1416
|
+
pagination,
|
|
1417
|
+
entityId,
|
|
1418
|
+
entityType,
|
|
1419
|
+
source
|
|
1420
|
+
}) {
|
|
682
1421
|
try {
|
|
683
|
-
const table = await this.
|
|
684
|
-
|
|
1422
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1423
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1424
|
+
const offset = page * perPage;
|
|
1425
|
+
let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1426
|
+
if (source) {
|
|
1427
|
+
query = query.where(`\`source\` = '${source}'`);
|
|
1428
|
+
}
|
|
1429
|
+
if (entityId) {
|
|
1430
|
+
query = query.where(`\`entityId\` = '${entityId}'`);
|
|
1431
|
+
}
|
|
1432
|
+
if (entityType) {
|
|
1433
|
+
query = query.where(`\`entityType\` = '${entityType}'`);
|
|
1434
|
+
}
|
|
1435
|
+
query = query.limit(perPage);
|
|
1436
|
+
if (offset > 0) query.offset(offset);
|
|
1437
|
+
const records = await query.toArray();
|
|
1438
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1439
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1440
|
+
let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1441
|
+
if (source) {
|
|
1442
|
+
totalQuery = totalQuery.where(`\`source\` = '${source}'`);
|
|
1443
|
+
}
|
|
1444
|
+
const allRecords = await totalQuery.toArray();
|
|
1445
|
+
const total = allRecords.length;
|
|
1446
|
+
return {
|
|
1447
|
+
pagination: {
|
|
1448
|
+
page,
|
|
1449
|
+
perPage,
|
|
1450
|
+
total,
|
|
1451
|
+
hasMore: offset + scores.length < total
|
|
1452
|
+
},
|
|
1453
|
+
scores
|
|
1454
|
+
};
|
|
685
1455
|
} catch (error) {
|
|
686
1456
|
throw new MastraError(
|
|
687
1457
|
{
|
|
688
|
-
id: "
|
|
1458
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
1459
|
+
text: "Failed to get scores by scorerId in LanceStorage",
|
|
689
1460
|
domain: ErrorDomain.STORAGE,
|
|
690
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1461
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1462
|
+
details: { error: error?.message }
|
|
691
1463
|
},
|
|
692
1464
|
error
|
|
693
1465
|
);
|
|
694
1466
|
}
|
|
695
1467
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
* @param include - The array of include specifications with context parameters
|
|
700
|
-
* @returns The processed array with context messages included
|
|
701
|
-
*/
|
|
702
|
-
processMessagesWithContext(records, include) {
|
|
703
|
-
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
704
|
-
if (messagesWithContext.length === 0) {
|
|
705
|
-
return records;
|
|
706
|
-
}
|
|
707
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
708
|
-
records.forEach((message, index) => {
|
|
709
|
-
messageIndexMap.set(message.id, index);
|
|
710
|
-
});
|
|
711
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
712
|
-
for (const item of messagesWithContext) {
|
|
713
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
714
|
-
if (messageIndex !== void 0) {
|
|
715
|
-
if (item.withPreviousMessages) {
|
|
716
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
717
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
718
|
-
additionalIndices.add(i);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
if (item.withNextMessages) {
|
|
722
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
723
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
724
|
-
additionalIndices.add(i);
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
if (additionalIndices.size === 0) {
|
|
730
|
-
return records;
|
|
731
|
-
}
|
|
732
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
733
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
734
|
-
records.forEach((record, index) => {
|
|
735
|
-
if (originalMatchIds.has(record.id)) {
|
|
736
|
-
allIndices.add(index);
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
additionalIndices.forEach((index) => {
|
|
740
|
-
allIndices.add(index);
|
|
741
|
-
});
|
|
742
|
-
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
743
|
-
}
|
|
744
|
-
async getMessages({
|
|
745
|
-
threadId,
|
|
746
|
-
resourceId,
|
|
747
|
-
selectBy,
|
|
748
|
-
format,
|
|
749
|
-
threadConfig
|
|
1468
|
+
async getScoresByRunId({
|
|
1469
|
+
runId,
|
|
1470
|
+
pagination
|
|
750
1471
|
}) {
|
|
751
1472
|
try {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
const
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
}
|
|
771
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
772
|
-
records = this.processMessagesWithContext(records, selectBy.include);
|
|
773
|
-
}
|
|
774
|
-
if (limit !== Number.MAX_SAFE_INTEGER) {
|
|
775
|
-
records = records.slice(-limit);
|
|
776
|
-
}
|
|
777
|
-
const messages = this.processResultWithTypeConversion(records, await this.getTableSchema(TABLE_MESSAGES));
|
|
778
|
-
const normalized = messages.map((msg) => ({
|
|
779
|
-
...msg,
|
|
780
|
-
content: typeof msg.content === "string" ? (() => {
|
|
781
|
-
try {
|
|
782
|
-
return JSON.parse(msg.content);
|
|
783
|
-
} catch {
|
|
784
|
-
return msg.content;
|
|
785
|
-
}
|
|
786
|
-
})() : msg.content
|
|
787
|
-
}));
|
|
788
|
-
const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
|
|
789
|
-
if (format === "v2") return list.get.all.v2();
|
|
790
|
-
return list.get.all.v1();
|
|
1473
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1474
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1475
|
+
const offset = page * perPage;
|
|
1476
|
+
const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
|
|
1477
|
+
if (offset > 0) query.offset(offset);
|
|
1478
|
+
const records = await query.toArray();
|
|
1479
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1480
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1481
|
+
const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
|
|
1482
|
+
const total = allRecords.length;
|
|
1483
|
+
return {
|
|
1484
|
+
pagination: {
|
|
1485
|
+
page,
|
|
1486
|
+
perPage,
|
|
1487
|
+
total,
|
|
1488
|
+
hasMore: offset + scores.length < total
|
|
1489
|
+
},
|
|
1490
|
+
scores
|
|
1491
|
+
};
|
|
791
1492
|
} catch (error) {
|
|
792
1493
|
throw new MastraError(
|
|
793
1494
|
{
|
|
794
|
-
id: "
|
|
1495
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1496
|
+
text: "Failed to get scores by runId in LanceStorage",
|
|
795
1497
|
domain: ErrorDomain.STORAGE,
|
|
796
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1498
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1499
|
+
details: { error: error?.message }
|
|
797
1500
|
},
|
|
798
1501
|
error
|
|
799
1502
|
);
|
|
800
1503
|
}
|
|
801
1504
|
}
|
|
802
|
-
async
|
|
1505
|
+
async getScoresByEntityId({
|
|
1506
|
+
entityId,
|
|
1507
|
+
entityType,
|
|
1508
|
+
pagination
|
|
1509
|
+
}) {
|
|
803
1510
|
try {
|
|
804
|
-
const
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
1511
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1512
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1513
|
+
const offset = page * perPage;
|
|
1514
|
+
const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
|
|
1515
|
+
if (offset > 0) query.offset(offset);
|
|
1516
|
+
const records = await query.toArray();
|
|
1517
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1518
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1519
|
+
const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
|
|
1520
|
+
const total = allRecords.length;
|
|
1521
|
+
return {
|
|
1522
|
+
pagination: {
|
|
1523
|
+
page,
|
|
1524
|
+
perPage,
|
|
1525
|
+
total,
|
|
1526
|
+
hasMore: offset + scores.length < total
|
|
1527
|
+
},
|
|
1528
|
+
scores
|
|
1529
|
+
};
|
|
821
1530
|
} catch (error) {
|
|
822
1531
|
throw new MastraError(
|
|
823
1532
|
{
|
|
824
|
-
id: "
|
|
1533
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1534
|
+
text: "Failed to get scores by entityId and entityType in LanceStorage",
|
|
825
1535
|
domain: ErrorDomain.STORAGE,
|
|
826
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1536
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1537
|
+
details: { error: error?.message }
|
|
827
1538
|
},
|
|
828
1539
|
error
|
|
829
1540
|
);
|
|
830
1541
|
}
|
|
831
1542
|
}
|
|
1543
|
+
};
|
|
1544
|
+
var StoreTracesLance = class extends TracesStorage {
|
|
1545
|
+
client;
|
|
1546
|
+
operations;
|
|
1547
|
+
constructor({ client, operations }) {
|
|
1548
|
+
super();
|
|
1549
|
+
this.client = client;
|
|
1550
|
+
this.operations = operations;
|
|
1551
|
+
}
|
|
832
1552
|
async saveTrace({ trace }) {
|
|
833
1553
|
try {
|
|
834
|
-
const table = await this.
|
|
1554
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
835
1555
|
const record = {
|
|
836
1556
|
...trace,
|
|
837
1557
|
attributes: JSON.stringify(trace.attributes),
|
|
@@ -855,10 +1575,10 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
855
1575
|
}
|
|
856
1576
|
async getTraceById({ traceId }) {
|
|
857
1577
|
try {
|
|
858
|
-
const table = await this.
|
|
1578
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
859
1579
|
const query = table.query().where(`id = '${traceId}'`);
|
|
860
1580
|
const records = await query.toArray();
|
|
861
|
-
return
|
|
1581
|
+
return records[0];
|
|
862
1582
|
} catch (error) {
|
|
863
1583
|
throw new MastraError(
|
|
864
1584
|
{
|
|
@@ -878,7 +1598,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
878
1598
|
attributes
|
|
879
1599
|
}) {
|
|
880
1600
|
try {
|
|
881
|
-
const table = await this.
|
|
1601
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
882
1602
|
const query = table.query();
|
|
883
1603
|
if (name) {
|
|
884
1604
|
query.where(`name = '${name}'`);
|
|
@@ -896,17 +1616,23 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
896
1616
|
}
|
|
897
1617
|
const records = await query.toArray();
|
|
898
1618
|
return records.map((record) => {
|
|
899
|
-
|
|
1619
|
+
const processed = {
|
|
900
1620
|
...record,
|
|
901
|
-
attributes: JSON.parse(record.attributes),
|
|
902
|
-
status: JSON.parse(record.status),
|
|
903
|
-
events: JSON.parse(record.events),
|
|
904
|
-
links: JSON.parse(record.links),
|
|
905
|
-
other: JSON.parse(record.other),
|
|
1621
|
+
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1622
|
+
status: record.status ? JSON.parse(record.status) : {},
|
|
1623
|
+
events: record.events ? JSON.parse(record.events) : [],
|
|
1624
|
+
links: record.links ? JSON.parse(record.links) : [],
|
|
1625
|
+
other: record.other ? JSON.parse(record.other) : {},
|
|
906
1626
|
startTime: new Date(record.startTime),
|
|
907
1627
|
endTime: new Date(record.endTime),
|
|
908
1628
|
createdAt: new Date(record.createdAt)
|
|
909
1629
|
};
|
|
1630
|
+
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1631
|
+
processed.parentSpanId = "";
|
|
1632
|
+
} else {
|
|
1633
|
+
processed.parentSpanId = String(processed.parentSpanId);
|
|
1634
|
+
}
|
|
1635
|
+
return processed;
|
|
910
1636
|
});
|
|
911
1637
|
} catch (error) {
|
|
912
1638
|
throw new MastraError(
|
|
@@ -920,131 +1646,177 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
920
1646
|
);
|
|
921
1647
|
}
|
|
922
1648
|
}
|
|
923
|
-
async
|
|
1649
|
+
async getTracesPaginated(args) {
|
|
924
1650
|
try {
|
|
925
|
-
const table = await this.
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
|
|
1651
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
1652
|
+
const query = table.query();
|
|
1653
|
+
const conditions = [];
|
|
1654
|
+
if (args.name) {
|
|
1655
|
+
conditions.push(`name = '${args.name}'`);
|
|
1656
|
+
}
|
|
1657
|
+
if (args.scope) {
|
|
1658
|
+
conditions.push(`scope = '${args.scope}'`);
|
|
1659
|
+
}
|
|
1660
|
+
if (args.attributes) {
|
|
1661
|
+
const attributesStr = JSON.stringify(args.attributes);
|
|
1662
|
+
conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
|
|
1663
|
+
}
|
|
1664
|
+
if (args.dateRange?.start) {
|
|
1665
|
+
conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
|
|
1666
|
+
}
|
|
1667
|
+
if (args.dateRange?.end) {
|
|
1668
|
+
conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
|
|
1669
|
+
}
|
|
1670
|
+
if (conditions.length > 0) {
|
|
1671
|
+
const whereClause = conditions.join(" AND ");
|
|
1672
|
+
query.where(whereClause);
|
|
1673
|
+
}
|
|
1674
|
+
let total = 0;
|
|
1675
|
+
if (conditions.length > 0) {
|
|
1676
|
+
const countQuery = table.query().where(conditions.join(" AND "));
|
|
1677
|
+
const allRecords = await countQuery.toArray();
|
|
1678
|
+
total = allRecords.length;
|
|
1679
|
+
} else {
|
|
1680
|
+
total = await table.countRows();
|
|
1681
|
+
}
|
|
1682
|
+
const page = args.page || 0;
|
|
1683
|
+
const perPage = args.perPage || 10;
|
|
1684
|
+
const offset = page * perPage;
|
|
1685
|
+
query.limit(perPage);
|
|
1686
|
+
if (offset > 0) {
|
|
1687
|
+
query.offset(offset);
|
|
1688
|
+
}
|
|
1689
|
+
const records = await query.toArray();
|
|
1690
|
+
const traces = records.map((record) => {
|
|
1691
|
+
const processed = {
|
|
1692
|
+
...record,
|
|
1693
|
+
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1694
|
+
status: record.status ? JSON.parse(record.status) : {},
|
|
1695
|
+
events: record.events ? JSON.parse(record.events) : [],
|
|
1696
|
+
links: record.links ? JSON.parse(record.links) : [],
|
|
1697
|
+
other: record.other ? JSON.parse(record.other) : {},
|
|
1698
|
+
startTime: new Date(record.startTime),
|
|
1699
|
+
endTime: new Date(record.endTime),
|
|
1700
|
+
createdAt: new Date(record.createdAt)
|
|
1701
|
+
};
|
|
1702
|
+
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1703
|
+
processed.parentSpanId = "";
|
|
1704
|
+
} else {
|
|
1705
|
+
processed.parentSpanId = String(processed.parentSpanId);
|
|
1706
|
+
}
|
|
1707
|
+
return processed;
|
|
1708
|
+
});
|
|
1709
|
+
return {
|
|
1710
|
+
traces,
|
|
1711
|
+
total,
|
|
1712
|
+
page,
|
|
1713
|
+
perPage,
|
|
1714
|
+
hasMore: total > (page + 1) * perPage
|
|
1715
|
+
};
|
|
940
1716
|
} catch (error) {
|
|
941
1717
|
throw new MastraError(
|
|
942
1718
|
{
|
|
943
|
-
id: "
|
|
1719
|
+
id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
944
1720
|
domain: ErrorDomain.STORAGE,
|
|
945
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1721
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1722
|
+
details: { name: args.name ?? "", scope: args.scope ?? "" }
|
|
946
1723
|
},
|
|
947
1724
|
error
|
|
948
1725
|
);
|
|
949
1726
|
}
|
|
950
1727
|
}
|
|
951
|
-
async
|
|
1728
|
+
async batchTraceInsert({ records }) {
|
|
1729
|
+
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1730
|
+
await this.operations.batchInsert({
|
|
1731
|
+
tableName: TABLE_TRACES,
|
|
1732
|
+
records
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
function parseWorkflowRun(row) {
|
|
1737
|
+
let parsedSnapshot = row.snapshot;
|
|
1738
|
+
if (typeof parsedSnapshot === "string") {
|
|
952
1739
|
try {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
|
|
1740
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1741
|
+
} catch (e) {
|
|
1742
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
return {
|
|
1746
|
+
workflowName: row.workflow_name,
|
|
1747
|
+
runId: row.run_id,
|
|
1748
|
+
snapshot: parsedSnapshot,
|
|
1749
|
+
createdAt: ensureDate(row.createdAt),
|
|
1750
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
1751
|
+
resourceId: row.resourceId
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
1755
|
+
client;
|
|
1756
|
+
constructor({ client }) {
|
|
1757
|
+
super();
|
|
1758
|
+
this.client = client;
|
|
1759
|
+
}
|
|
1760
|
+
async persistWorkflowSnapshot({
|
|
1761
|
+
workflowName,
|
|
1762
|
+
runId,
|
|
1763
|
+
snapshot
|
|
1764
|
+
}) {
|
|
1765
|
+
try {
|
|
1766
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1767
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
958
1768
|
const records = await query.toArray();
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1769
|
+
let createdAt;
|
|
1770
|
+
const now = Date.now();
|
|
1771
|
+
if (records.length > 0) {
|
|
1772
|
+
createdAt = records[0].createdAt ?? now;
|
|
1773
|
+
} else {
|
|
1774
|
+
createdAt = now;
|
|
1775
|
+
}
|
|
1776
|
+
const record = {
|
|
1777
|
+
workflow_name: workflowName,
|
|
1778
|
+
run_id: runId,
|
|
1779
|
+
snapshot: JSON.stringify(snapshot),
|
|
1780
|
+
createdAt,
|
|
1781
|
+
updatedAt: now
|
|
1782
|
+
};
|
|
1783
|
+
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
974
1784
|
} catch (error) {
|
|
975
1785
|
throw new MastraError(
|
|
976
1786
|
{
|
|
977
|
-
id: "
|
|
1787
|
+
id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
978
1788
|
domain: ErrorDomain.STORAGE,
|
|
979
1789
|
category: ErrorCategory.THIRD_PARTY,
|
|
980
|
-
details: {
|
|
1790
|
+
details: { workflowName, runId }
|
|
981
1791
|
},
|
|
982
1792
|
error
|
|
983
1793
|
);
|
|
984
1794
|
}
|
|
985
1795
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
return {
|
|
996
|
-
workflowName: row.workflow_name,
|
|
997
|
-
runId: row.run_id,
|
|
998
|
-
snapshot: parsedSnapshot,
|
|
999
|
-
createdAt: this.ensureDate(row.createdAt),
|
|
1000
|
-
updatedAt: this.ensureDate(row.updatedAt),
|
|
1001
|
-
resourceId: row.resourceId
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
async getWorkflowRuns(args) {
|
|
1005
|
-
try {
|
|
1006
|
-
const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1007
|
-
const query = table.query();
|
|
1008
|
-
if (args?.workflowName) {
|
|
1009
|
-
query.where(`workflow_name = '${args.workflowName}'`);
|
|
1010
|
-
}
|
|
1011
|
-
if (args?.fromDate) {
|
|
1012
|
-
query.where(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1013
|
-
}
|
|
1014
|
-
if (args?.toDate) {
|
|
1015
|
-
query.where(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1016
|
-
}
|
|
1017
|
-
if (args?.limit) {
|
|
1018
|
-
query.limit(args.limit);
|
|
1019
|
-
}
|
|
1020
|
-
if (args?.offset) {
|
|
1021
|
-
query.offset(args.offset);
|
|
1022
|
-
}
|
|
1796
|
+
async loadWorkflowSnapshot({
|
|
1797
|
+
workflowName,
|
|
1798
|
+
runId
|
|
1799
|
+
}) {
|
|
1800
|
+
try {
|
|
1801
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1802
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1023
1803
|
const records = await query.toArray();
|
|
1024
|
-
return
|
|
1025
|
-
runs: records.map((record) => this.parseWorkflowRun(record)),
|
|
1026
|
-
total: records.length
|
|
1027
|
-
};
|
|
1804
|
+
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1028
1805
|
} catch (error) {
|
|
1029
1806
|
throw new MastraError(
|
|
1030
1807
|
{
|
|
1031
|
-
id: "
|
|
1808
|
+
id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
1032
1809
|
domain: ErrorDomain.STORAGE,
|
|
1033
1810
|
category: ErrorCategory.THIRD_PARTY,
|
|
1034
|
-
details: {
|
|
1811
|
+
details: { workflowName, runId }
|
|
1035
1812
|
},
|
|
1036
1813
|
error
|
|
1037
1814
|
);
|
|
1038
1815
|
}
|
|
1039
1816
|
}
|
|
1040
|
-
/**
|
|
1041
|
-
* Retrieve a single workflow run by its runId.
|
|
1042
|
-
* @param args The ID of the workflow run to retrieve
|
|
1043
|
-
* @returns The workflow run object or null if not found
|
|
1044
|
-
*/
|
|
1045
1817
|
async getWorkflowRunById(args) {
|
|
1046
1818
|
try {
|
|
1047
|
-
const table = await this.
|
|
1819
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1048
1820
|
let whereClause = `run_id = '${args.runId}'`;
|
|
1049
1821
|
if (args.workflowName) {
|
|
1050
1822
|
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
@@ -1053,7 +1825,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1053
1825
|
const records = await query.toArray();
|
|
1054
1826
|
if (records.length === 0) return null;
|
|
1055
1827
|
const record = records[0];
|
|
1056
|
-
return
|
|
1828
|
+
return parseWorkflowRun(record);
|
|
1057
1829
|
} catch (error) {
|
|
1058
1830
|
throw new MastraError(
|
|
1059
1831
|
{
|
|
@@ -1066,96 +1838,328 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1066
1838
|
);
|
|
1067
1839
|
}
|
|
1068
1840
|
}
|
|
1069
|
-
async
|
|
1070
|
-
workflowName,
|
|
1071
|
-
runId,
|
|
1072
|
-
snapshot
|
|
1073
|
-
}) {
|
|
1841
|
+
async getWorkflowRuns(args) {
|
|
1074
1842
|
try {
|
|
1075
|
-
const table = await this.
|
|
1076
|
-
|
|
1077
|
-
const
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1843
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1844
|
+
let query = table.query();
|
|
1845
|
+
const conditions = [];
|
|
1846
|
+
if (args?.workflowName) {
|
|
1847
|
+
conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
|
|
1848
|
+
}
|
|
1849
|
+
if (args?.resourceId) {
|
|
1850
|
+
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1851
|
+
}
|
|
1852
|
+
if (args?.fromDate instanceof Date) {
|
|
1853
|
+
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1854
|
+
}
|
|
1855
|
+
if (args?.toDate instanceof Date) {
|
|
1856
|
+
conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1857
|
+
}
|
|
1858
|
+
let total = 0;
|
|
1859
|
+
if (conditions.length > 0) {
|
|
1860
|
+
query = query.where(conditions.join(" AND "));
|
|
1861
|
+
total = await table.countRows(conditions.join(" AND "));
|
|
1082
1862
|
} else {
|
|
1083
|
-
|
|
1863
|
+
total = await table.countRows();
|
|
1084
1864
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1865
|
+
if (args?.limit) {
|
|
1866
|
+
query.limit(args.limit);
|
|
1867
|
+
}
|
|
1868
|
+
if (args?.offset) {
|
|
1869
|
+
query.offset(args.offset);
|
|
1870
|
+
}
|
|
1871
|
+
const records = await query.toArray();
|
|
1872
|
+
return {
|
|
1873
|
+
runs: records.map((record) => parseWorkflowRun(record)),
|
|
1874
|
+
total: total || records.length
|
|
1091
1875
|
};
|
|
1092
|
-
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1093
1876
|
} catch (error) {
|
|
1094
1877
|
throw new MastraError(
|
|
1095
1878
|
{
|
|
1096
|
-
id: "
|
|
1879
|
+
id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
|
|
1097
1880
|
domain: ErrorDomain.STORAGE,
|
|
1098
1881
|
category: ErrorCategory.THIRD_PARTY,
|
|
1099
|
-
details: {
|
|
1882
|
+
details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
|
|
1100
1883
|
},
|
|
1101
1884
|
error
|
|
1102
1885
|
);
|
|
1103
1886
|
}
|
|
1104
1887
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1888
|
+
};
|
|
1889
|
+
|
|
1890
|
+
// src/storage/index.ts
|
|
1891
|
+
var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
1892
|
+
stores;
|
|
1893
|
+
lanceClient;
|
|
1894
|
+
/**
|
|
1895
|
+
* Creates a new instance of LanceStorage
|
|
1896
|
+
* @param uri The URI to connect to LanceDB
|
|
1897
|
+
* @param options connection options
|
|
1898
|
+
*
|
|
1899
|
+
* Usage:
|
|
1900
|
+
*
|
|
1901
|
+
* Connect to a local database
|
|
1902
|
+
* ```ts
|
|
1903
|
+
* const store = await LanceStorage.create('/path/to/db');
|
|
1904
|
+
* ```
|
|
1905
|
+
*
|
|
1906
|
+
* Connect to a LanceDB cloud database
|
|
1907
|
+
* ```ts
|
|
1908
|
+
* const store = await LanceStorage.create('db://host:port');
|
|
1909
|
+
* ```
|
|
1910
|
+
*
|
|
1911
|
+
* Connect to a cloud database
|
|
1912
|
+
* ```ts
|
|
1913
|
+
* const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
1914
|
+
* ```
|
|
1915
|
+
*/
|
|
1916
|
+
static async create(name, uri, options) {
|
|
1917
|
+
const instance = new _LanceStorage(name);
|
|
1109
1918
|
try {
|
|
1110
|
-
|
|
1111
|
-
const
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1919
|
+
instance.lanceClient = await connect(uri, options);
|
|
1920
|
+
const operations = new StoreOperationsLance({ client: instance.lanceClient });
|
|
1921
|
+
instance.stores = {
|
|
1922
|
+
operations: new StoreOperationsLance({ client: instance.lanceClient }),
|
|
1923
|
+
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1924
|
+
traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
|
|
1925
|
+
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1926
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
|
|
1927
|
+
legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
|
|
1928
|
+
};
|
|
1929
|
+
return instance;
|
|
1930
|
+
} catch (e) {
|
|
1115
1931
|
throw new MastraError(
|
|
1116
1932
|
{
|
|
1117
|
-
id: "
|
|
1933
|
+
id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
|
|
1118
1934
|
domain: ErrorDomain.STORAGE,
|
|
1119
1935
|
category: ErrorCategory.THIRD_PARTY,
|
|
1120
|
-
|
|
1936
|
+
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1937
|
+
details: { uri, optionsProvided: !!options }
|
|
1121
1938
|
},
|
|
1122
|
-
|
|
1939
|
+
e
|
|
1123
1940
|
);
|
|
1124
1941
|
}
|
|
1125
1942
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1943
|
+
/**
|
|
1944
|
+
* @internal
|
|
1945
|
+
* Private constructor to enforce using the create factory method
|
|
1946
|
+
*/
|
|
1947
|
+
constructor(name) {
|
|
1948
|
+
super({ name });
|
|
1949
|
+
const operations = new StoreOperationsLance({ client: this.lanceClient });
|
|
1950
|
+
this.stores = {
|
|
1951
|
+
operations: new StoreOperationsLance({ client: this.lanceClient }),
|
|
1952
|
+
workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
|
|
1953
|
+
traces: new StoreTracesLance({ client: this.lanceClient, operations }),
|
|
1954
|
+
scores: new StoreScoresLance({ client: this.lanceClient }),
|
|
1955
|
+
legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
|
|
1956
|
+
memory: new StoreMemoryLance({ client: this.lanceClient, operations })
|
|
1957
|
+
};
|
|
1135
1958
|
}
|
|
1136
|
-
async
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1142
|
-
},
|
|
1143
|
-
"Method not implemented."
|
|
1144
|
-
);
|
|
1959
|
+
async createTable({
|
|
1960
|
+
tableName,
|
|
1961
|
+
schema
|
|
1962
|
+
}) {
|
|
1963
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
1145
1964
|
}
|
|
1146
|
-
async
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
);
|
|
1965
|
+
async dropTable({ tableName }) {
|
|
1966
|
+
return this.stores.operations.dropTable({ tableName });
|
|
1967
|
+
}
|
|
1968
|
+
async alterTable({
|
|
1969
|
+
tableName,
|
|
1970
|
+
schema,
|
|
1971
|
+
ifNotExists
|
|
1972
|
+
}) {
|
|
1973
|
+
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
1974
|
+
}
|
|
1975
|
+
async clearTable({ tableName }) {
|
|
1976
|
+
return this.stores.operations.clearTable({ tableName });
|
|
1977
|
+
}
|
|
1978
|
+
async insert({ tableName, record }) {
|
|
1979
|
+
return this.stores.operations.insert({ tableName, record });
|
|
1980
|
+
}
|
|
1981
|
+
async batchInsert({ tableName, records }) {
|
|
1982
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
1983
|
+
}
|
|
1984
|
+
async load({ tableName, keys }) {
|
|
1985
|
+
return this.stores.operations.load({ tableName, keys });
|
|
1986
|
+
}
|
|
1987
|
+
async getThreadById({ threadId }) {
|
|
1988
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
1989
|
+
}
|
|
1990
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
1991
|
+
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
1992
|
+
}
|
|
1993
|
+
/**
|
|
1994
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
1995
|
+
* @param thread - The thread to save
|
|
1996
|
+
* @returns The saved thread
|
|
1997
|
+
*/
|
|
1998
|
+
async saveThread({ thread }) {
|
|
1999
|
+
return this.stores.memory.saveThread({ thread });
|
|
2000
|
+
}
|
|
2001
|
+
async updateThread({
|
|
2002
|
+
id,
|
|
2003
|
+
title,
|
|
2004
|
+
metadata
|
|
2005
|
+
}) {
|
|
2006
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2007
|
+
}
|
|
2008
|
+
async deleteThread({ threadId }) {
|
|
2009
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2010
|
+
}
|
|
2011
|
+
get supports() {
|
|
2012
|
+
return {
|
|
2013
|
+
selectByIncludeResourceScope: true,
|
|
2014
|
+
resourceWorkingMemory: true,
|
|
2015
|
+
hasColumn: true,
|
|
2016
|
+
createTable: true,
|
|
2017
|
+
deleteMessages: false
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
async getResourceById({ resourceId }) {
|
|
2021
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2022
|
+
}
|
|
2023
|
+
async saveResource({ resource }) {
|
|
2024
|
+
return this.stores.memory.saveResource({ resource });
|
|
2025
|
+
}
|
|
2026
|
+
async updateResource({
|
|
2027
|
+
resourceId,
|
|
2028
|
+
workingMemory,
|
|
2029
|
+
metadata
|
|
2030
|
+
}) {
|
|
2031
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2032
|
+
}
|
|
2033
|
+
/**
|
|
2034
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
2035
|
+
* @param records - The sorted array of records to process
|
|
2036
|
+
* @param include - The array of include specifications with context parameters
|
|
2037
|
+
* @returns The processed array with context messages included
|
|
2038
|
+
*/
|
|
2039
|
+
processMessagesWithContext(records, include) {
|
|
2040
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
2041
|
+
if (messagesWithContext.length === 0) {
|
|
2042
|
+
return records;
|
|
2043
|
+
}
|
|
2044
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
2045
|
+
records.forEach((message, index) => {
|
|
2046
|
+
messageIndexMap.set(message.id, index);
|
|
2047
|
+
});
|
|
2048
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
2049
|
+
for (const item of messagesWithContext) {
|
|
2050
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
2051
|
+
if (messageIndex !== void 0) {
|
|
2052
|
+
if (item.withPreviousMessages) {
|
|
2053
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
2054
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
2055
|
+
additionalIndices.add(i);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
if (item.withNextMessages) {
|
|
2059
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
2060
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
2061
|
+
additionalIndices.add(i);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
if (additionalIndices.size === 0) {
|
|
2067
|
+
return records;
|
|
2068
|
+
}
|
|
2069
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
2070
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
2071
|
+
records.forEach((record, index) => {
|
|
2072
|
+
if (originalMatchIds.has(record.id)) {
|
|
2073
|
+
allIndices.add(index);
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
additionalIndices.forEach((index) => {
|
|
2077
|
+
allIndices.add(index);
|
|
2078
|
+
});
|
|
2079
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
2080
|
+
}
|
|
2081
|
+
async getMessages({
|
|
2082
|
+
threadId,
|
|
2083
|
+
resourceId,
|
|
2084
|
+
selectBy,
|
|
2085
|
+
format,
|
|
2086
|
+
threadConfig
|
|
2087
|
+
}) {
|
|
2088
|
+
return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
|
|
2089
|
+
}
|
|
2090
|
+
async saveMessages(args) {
|
|
2091
|
+
return this.stores.memory.saveMessages(args);
|
|
2092
|
+
}
|
|
2093
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2094
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2095
|
+
}
|
|
2096
|
+
async getMessagesPaginated(args) {
|
|
2097
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
1155
2098
|
}
|
|
1156
2099
|
async updateMessages(_args) {
|
|
1157
|
-
this.
|
|
1158
|
-
|
|
2100
|
+
return this.stores.memory.updateMessages(_args);
|
|
2101
|
+
}
|
|
2102
|
+
async getTraceById(args) {
|
|
2103
|
+
return this.stores.traces.getTraceById(args);
|
|
2104
|
+
}
|
|
2105
|
+
async getTraces(args) {
|
|
2106
|
+
return this.stores.traces.getTraces(args);
|
|
2107
|
+
}
|
|
2108
|
+
async getTracesPaginated(args) {
|
|
2109
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
2110
|
+
}
|
|
2111
|
+
async getEvalsByAgentName(agentName, type) {
|
|
2112
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2113
|
+
}
|
|
2114
|
+
async getEvals(options) {
|
|
2115
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
2116
|
+
}
|
|
2117
|
+
async getWorkflowRuns(args) {
|
|
2118
|
+
return this.stores.workflows.getWorkflowRuns(args);
|
|
2119
|
+
}
|
|
2120
|
+
async getWorkflowRunById(args) {
|
|
2121
|
+
return this.stores.workflows.getWorkflowRunById(args);
|
|
2122
|
+
}
|
|
2123
|
+
async persistWorkflowSnapshot({
|
|
2124
|
+
workflowName,
|
|
2125
|
+
runId,
|
|
2126
|
+
snapshot
|
|
2127
|
+
}) {
|
|
2128
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2129
|
+
}
|
|
2130
|
+
async loadWorkflowSnapshot({
|
|
2131
|
+
workflowName,
|
|
2132
|
+
runId
|
|
2133
|
+
}) {
|
|
2134
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2135
|
+
}
|
|
2136
|
+
async getScoreById({ id: _id }) {
|
|
2137
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
2138
|
+
}
|
|
2139
|
+
async getScoresByScorerId({
|
|
2140
|
+
scorerId,
|
|
2141
|
+
source,
|
|
2142
|
+
entityId,
|
|
2143
|
+
entityType,
|
|
2144
|
+
pagination
|
|
2145
|
+
}) {
|
|
2146
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
|
|
2147
|
+
}
|
|
2148
|
+
async saveScore(_score) {
|
|
2149
|
+
return this.stores.scores.saveScore(_score);
|
|
2150
|
+
}
|
|
2151
|
+
async getScoresByRunId({
|
|
2152
|
+
runId,
|
|
2153
|
+
pagination
|
|
2154
|
+
}) {
|
|
2155
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
2156
|
+
}
|
|
2157
|
+
async getScoresByEntityId({
|
|
2158
|
+
entityId,
|
|
2159
|
+
entityType,
|
|
2160
|
+
pagination
|
|
2161
|
+
}) {
|
|
2162
|
+
return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
|
|
1159
2163
|
}
|
|
1160
2164
|
};
|
|
1161
2165
|
var LanceFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -2214,3 +3218,5 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
|
|
|
2214
3218
|
};
|
|
2215
3219
|
|
|
2216
3220
|
export { LanceStorage, LanceVectorStore };
|
|
3221
|
+
//# sourceMappingURL=index.js.map
|
|
3222
|
+
//# sourceMappingURL=index.js.map
|