@mastra/lance 0.2.0 → 0.2.1
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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +55 -0
- package/LICENSE.md +11 -42
- package/dist/_tsup-dts-rollup.d.cts +360 -89
- package/dist/_tsup-dts-rollup.d.ts +360 -89
- package/dist/index.cjs +1628 -646
- package/dist/index.js +1563 -581
- package/package.json +6 -6
- package/src/storage/domains/legacy-evals/index.ts +156 -0
- package/src/storage/domains/memory/index.ts +947 -0
- package/src/storage/domains/operations/index.ts +489 -0
- package/src/storage/domains/scores/index.ts +221 -0
- package/src/storage/domains/traces/index.ts +212 -0
- package/src/storage/domains/utils.ts +158 -0
- package/src/storage/domains/workflows/index.ts +207 -0
- package/src/storage/index.test.ts +6 -1332
- package/src/storage/index.ts +156 -1162
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;
|
|
@@ -505,333 +1327,213 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
505
1327
|
} else {
|
|
506
1328
|
return `${quotedKey} = ${value}`;
|
|
507
1329
|
}
|
|
508
|
-
}).join(" AND ");
|
|
509
|
-
this.logger.debug("where clause generated: " + filterConditions);
|
|
510
|
-
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
|
-
);
|
|
1330
|
+
}).join(" AND ");
|
|
1331
|
+
this.logger.debug("where clause generated: " + filterConditions);
|
|
1332
|
+
query.where(filterConditions);
|
|
1333
|
+
}
|
|
1334
|
+
const result = await query.limit(1).toArray();
|
|
1335
|
+
if (result.length === 0) {
|
|
1336
|
+
this.logger.debug("No record found");
|
|
1337
|
+
return null;
|
|
1338
|
+
}
|
|
1339
|
+
return processResultWithTypeConversion(result[0], tableSchema);
|
|
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
|
|
642
|
-
|
|
643
|
-
|
|
1362
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1363
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1364
|
+
const allowedFields = new Set(schema.fields.map((f) => f.name));
|
|
1365
|
+
const filteredScore = {};
|
|
1366
|
+
Object.keys(score).forEach((key) => {
|
|
1367
|
+
if (allowedFields.has(key)) {
|
|
1368
|
+
filteredScore[key] = score[key];
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
for (const key in filteredScore) {
|
|
1372
|
+
if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
|
|
1373
|
+
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
console.log("Saving score to LanceStorage:", filteredScore);
|
|
1377
|
+
await table.add([filteredScore], { mode: "append" });
|
|
1378
|
+
return { score };
|
|
644
1379
|
} catch (error) {
|
|
645
1380
|
throw new MastraError(
|
|
646
1381
|
{
|
|
647
|
-
id: "
|
|
1382
|
+
id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
|
|
1383
|
+
text: "Failed to save score in LanceStorage",
|
|
648
1384
|
domain: ErrorDomain.STORAGE,
|
|
649
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1385
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1386
|
+
details: { error: error?.message }
|
|
650
1387
|
},
|
|
651
1388
|
error
|
|
652
1389
|
);
|
|
653
1390
|
}
|
|
654
1391
|
}
|
|
655
|
-
async
|
|
656
|
-
id,
|
|
657
|
-
title,
|
|
658
|
-
metadata
|
|
659
|
-
}) {
|
|
1392
|
+
async getScoreById({ id }) {
|
|
660
1393
|
try {
|
|
661
|
-
const
|
|
662
|
-
const
|
|
663
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
664
|
-
const query = table.query().where(`id = '${id}'`);
|
|
1394
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1395
|
+
const query = table.query().where(`id = '${id}'`).limit(1);
|
|
665
1396
|
const records = await query.toArray();
|
|
666
|
-
return
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
);
|
|
1397
|
+
if (records.length === 0) return null;
|
|
1398
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1399
|
+
return processResultWithTypeConversion(records[0], schema);
|
|
670
1400
|
} catch (error) {
|
|
671
1401
|
throw new MastraError(
|
|
672
1402
|
{
|
|
673
|
-
id: "
|
|
1403
|
+
id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
|
|
1404
|
+
text: "Failed to get score by id in LanceStorage",
|
|
674
1405
|
domain: ErrorDomain.STORAGE,
|
|
675
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1406
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1407
|
+
details: { error: error?.message }
|
|
676
1408
|
},
|
|
677
1409
|
error
|
|
678
1410
|
);
|
|
679
1411
|
}
|
|
680
1412
|
}
|
|
681
|
-
async
|
|
1413
|
+
async getScoresByScorerId({
|
|
1414
|
+
scorerId,
|
|
1415
|
+
pagination
|
|
1416
|
+
}) {
|
|
682
1417
|
try {
|
|
683
|
-
const table = await this.
|
|
684
|
-
|
|
1418
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1419
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1420
|
+
const offset = page * perPage;
|
|
1421
|
+
const query = table.query().where(`\`scorerId\` = '${scorerId}'`).limit(perPage);
|
|
1422
|
+
if (offset > 0) query.offset(offset);
|
|
1423
|
+
const records = await query.toArray();
|
|
1424
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1425
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1426
|
+
const allRecords = await table.query().where(`\`scorerId\` = '${scorerId}'`).toArray();
|
|
1427
|
+
const total = allRecords.length;
|
|
1428
|
+
return {
|
|
1429
|
+
pagination: {
|
|
1430
|
+
page,
|
|
1431
|
+
perPage,
|
|
1432
|
+
total,
|
|
1433
|
+
hasMore: offset + scores.length < total
|
|
1434
|
+
},
|
|
1435
|
+
scores
|
|
1436
|
+
};
|
|
685
1437
|
} catch (error) {
|
|
686
1438
|
throw new MastraError(
|
|
687
1439
|
{
|
|
688
|
-
id: "
|
|
1440
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
1441
|
+
text: "Failed to get scores by scorerId in LanceStorage",
|
|
689
1442
|
domain: ErrorDomain.STORAGE,
|
|
690
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1443
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1444
|
+
details: { error: error?.message }
|
|
691
1445
|
},
|
|
692
1446
|
error
|
|
693
1447
|
);
|
|
694
1448
|
}
|
|
695
1449
|
}
|
|
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
|
|
1450
|
+
async getScoresByRunId({
|
|
1451
|
+
runId,
|
|
1452
|
+
pagination
|
|
750
1453
|
}) {
|
|
751
1454
|
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();
|
|
1455
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1456
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1457
|
+
const offset = page * perPage;
|
|
1458
|
+
const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
|
|
1459
|
+
if (offset > 0) query.offset(offset);
|
|
1460
|
+
const records = await query.toArray();
|
|
1461
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1462
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1463
|
+
const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
|
|
1464
|
+
const total = allRecords.length;
|
|
1465
|
+
return {
|
|
1466
|
+
pagination: {
|
|
1467
|
+
page,
|
|
1468
|
+
perPage,
|
|
1469
|
+
total,
|
|
1470
|
+
hasMore: offset + scores.length < total
|
|
1471
|
+
},
|
|
1472
|
+
scores
|
|
1473
|
+
};
|
|
791
1474
|
} catch (error) {
|
|
792
1475
|
throw new MastraError(
|
|
793
1476
|
{
|
|
794
|
-
id: "
|
|
1477
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1478
|
+
text: "Failed to get scores by runId in LanceStorage",
|
|
795
1479
|
domain: ErrorDomain.STORAGE,
|
|
796
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1480
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1481
|
+
details: { error: error?.message }
|
|
797
1482
|
},
|
|
798
1483
|
error
|
|
799
1484
|
);
|
|
800
1485
|
}
|
|
801
1486
|
}
|
|
802
|
-
async
|
|
1487
|
+
async getScoresByEntityId({
|
|
1488
|
+
entityId,
|
|
1489
|
+
entityType,
|
|
1490
|
+
pagination
|
|
1491
|
+
}) {
|
|
803
1492
|
try {
|
|
804
|
-
const
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
1493
|
+
const table = await this.client.openTable(TABLE_SCORERS);
|
|
1494
|
+
const { page = 0, perPage = 10 } = pagination || {};
|
|
1495
|
+
const offset = page * perPage;
|
|
1496
|
+
const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
|
|
1497
|
+
if (offset > 0) query.offset(offset);
|
|
1498
|
+
const records = await query.toArray();
|
|
1499
|
+
const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
|
|
1500
|
+
const scores = processResultWithTypeConversion(records, schema);
|
|
1501
|
+
const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
|
|
1502
|
+
const total = allRecords.length;
|
|
1503
|
+
return {
|
|
1504
|
+
pagination: {
|
|
1505
|
+
page,
|
|
1506
|
+
perPage,
|
|
1507
|
+
total,
|
|
1508
|
+
hasMore: offset + scores.length < total
|
|
1509
|
+
},
|
|
1510
|
+
scores
|
|
1511
|
+
};
|
|
821
1512
|
} catch (error) {
|
|
822
1513
|
throw new MastraError(
|
|
823
1514
|
{
|
|
824
|
-
id: "
|
|
1515
|
+
id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1516
|
+
text: "Failed to get scores by entityId and entityType in LanceStorage",
|
|
825
1517
|
domain: ErrorDomain.STORAGE,
|
|
826
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1518
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1519
|
+
details: { error: error?.message }
|
|
827
1520
|
},
|
|
828
1521
|
error
|
|
829
1522
|
);
|
|
830
1523
|
}
|
|
831
1524
|
}
|
|
1525
|
+
};
|
|
1526
|
+
var StoreTracesLance = class extends TracesStorage {
|
|
1527
|
+
client;
|
|
1528
|
+
operations;
|
|
1529
|
+
constructor({ client, operations }) {
|
|
1530
|
+
super();
|
|
1531
|
+
this.client = client;
|
|
1532
|
+
this.operations = operations;
|
|
1533
|
+
}
|
|
832
1534
|
async saveTrace({ trace }) {
|
|
833
1535
|
try {
|
|
834
|
-
const table = await this.
|
|
1536
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
835
1537
|
const record = {
|
|
836
1538
|
...trace,
|
|
837
1539
|
attributes: JSON.stringify(trace.attributes),
|
|
@@ -855,10 +1557,10 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
855
1557
|
}
|
|
856
1558
|
async getTraceById({ traceId }) {
|
|
857
1559
|
try {
|
|
858
|
-
const table = await this.
|
|
1560
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
859
1561
|
const query = table.query().where(`id = '${traceId}'`);
|
|
860
1562
|
const records = await query.toArray();
|
|
861
|
-
return
|
|
1563
|
+
return records[0];
|
|
862
1564
|
} catch (error) {
|
|
863
1565
|
throw new MastraError(
|
|
864
1566
|
{
|
|
@@ -878,7 +1580,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
878
1580
|
attributes
|
|
879
1581
|
}) {
|
|
880
1582
|
try {
|
|
881
|
-
const table = await this.
|
|
1583
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
882
1584
|
const query = table.query();
|
|
883
1585
|
if (name) {
|
|
884
1586
|
query.where(`name = '${name}'`);
|
|
@@ -896,17 +1598,23 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
896
1598
|
}
|
|
897
1599
|
const records = await query.toArray();
|
|
898
1600
|
return records.map((record) => {
|
|
899
|
-
|
|
1601
|
+
const processed = {
|
|
900
1602
|
...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),
|
|
1603
|
+
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1604
|
+
status: record.status ? JSON.parse(record.status) : {},
|
|
1605
|
+
events: record.events ? JSON.parse(record.events) : [],
|
|
1606
|
+
links: record.links ? JSON.parse(record.links) : [],
|
|
1607
|
+
other: record.other ? JSON.parse(record.other) : {},
|
|
906
1608
|
startTime: new Date(record.startTime),
|
|
907
1609
|
endTime: new Date(record.endTime),
|
|
908
1610
|
createdAt: new Date(record.createdAt)
|
|
909
1611
|
};
|
|
1612
|
+
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1613
|
+
processed.parentSpanId = "";
|
|
1614
|
+
} else {
|
|
1615
|
+
processed.parentSpanId = String(processed.parentSpanId);
|
|
1616
|
+
}
|
|
1617
|
+
return processed;
|
|
910
1618
|
});
|
|
911
1619
|
} catch (error) {
|
|
912
1620
|
throw new MastraError(
|
|
@@ -920,131 +1628,177 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
920
1628
|
);
|
|
921
1629
|
}
|
|
922
1630
|
}
|
|
923
|
-
async
|
|
1631
|
+
async getTracesPaginated(args) {
|
|
924
1632
|
try {
|
|
925
|
-
const table = await this.
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
|
|
1633
|
+
const table = await this.client.openTable(TABLE_TRACES);
|
|
1634
|
+
const query = table.query();
|
|
1635
|
+
const conditions = [];
|
|
1636
|
+
if (args.name) {
|
|
1637
|
+
conditions.push(`name = '${args.name}'`);
|
|
1638
|
+
}
|
|
1639
|
+
if (args.scope) {
|
|
1640
|
+
conditions.push(`scope = '${args.scope}'`);
|
|
1641
|
+
}
|
|
1642
|
+
if (args.attributes) {
|
|
1643
|
+
const attributesStr = JSON.stringify(args.attributes);
|
|
1644
|
+
conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
|
|
1645
|
+
}
|
|
1646
|
+
if (args.dateRange?.start) {
|
|
1647
|
+
conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
|
|
1648
|
+
}
|
|
1649
|
+
if (args.dateRange?.end) {
|
|
1650
|
+
conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
|
|
1651
|
+
}
|
|
1652
|
+
if (conditions.length > 0) {
|
|
1653
|
+
const whereClause = conditions.join(" AND ");
|
|
1654
|
+
query.where(whereClause);
|
|
1655
|
+
}
|
|
1656
|
+
let total = 0;
|
|
1657
|
+
if (conditions.length > 0) {
|
|
1658
|
+
const countQuery = table.query().where(conditions.join(" AND "));
|
|
1659
|
+
const allRecords = await countQuery.toArray();
|
|
1660
|
+
total = allRecords.length;
|
|
1661
|
+
} else {
|
|
1662
|
+
total = await table.countRows();
|
|
1663
|
+
}
|
|
1664
|
+
const page = args.page || 0;
|
|
1665
|
+
const perPage = args.perPage || 10;
|
|
1666
|
+
const offset = page * perPage;
|
|
1667
|
+
query.limit(perPage);
|
|
1668
|
+
if (offset > 0) {
|
|
1669
|
+
query.offset(offset);
|
|
1670
|
+
}
|
|
1671
|
+
const records = await query.toArray();
|
|
1672
|
+
const traces = records.map((record) => {
|
|
1673
|
+
const processed = {
|
|
1674
|
+
...record,
|
|
1675
|
+
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1676
|
+
status: record.status ? JSON.parse(record.status) : {},
|
|
1677
|
+
events: record.events ? JSON.parse(record.events) : [],
|
|
1678
|
+
links: record.links ? JSON.parse(record.links) : [],
|
|
1679
|
+
other: record.other ? JSON.parse(record.other) : {},
|
|
1680
|
+
startTime: new Date(record.startTime),
|
|
1681
|
+
endTime: new Date(record.endTime),
|
|
1682
|
+
createdAt: new Date(record.createdAt)
|
|
1683
|
+
};
|
|
1684
|
+
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1685
|
+
processed.parentSpanId = "";
|
|
1686
|
+
} else {
|
|
1687
|
+
processed.parentSpanId = String(processed.parentSpanId);
|
|
1688
|
+
}
|
|
1689
|
+
return processed;
|
|
1690
|
+
});
|
|
1691
|
+
return {
|
|
1692
|
+
traces,
|
|
1693
|
+
total,
|
|
1694
|
+
page,
|
|
1695
|
+
perPage,
|
|
1696
|
+
hasMore: total > (page + 1) * perPage
|
|
1697
|
+
};
|
|
940
1698
|
} catch (error) {
|
|
941
1699
|
throw new MastraError(
|
|
942
1700
|
{
|
|
943
|
-
id: "
|
|
1701
|
+
id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
944
1702
|
domain: ErrorDomain.STORAGE,
|
|
945
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1703
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1704
|
+
details: { name: args.name ?? "", scope: args.scope ?? "" }
|
|
946
1705
|
},
|
|
947
1706
|
error
|
|
948
1707
|
);
|
|
949
1708
|
}
|
|
950
1709
|
}
|
|
951
|
-
async
|
|
1710
|
+
async batchTraceInsert({ records }) {
|
|
1711
|
+
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1712
|
+
await this.operations.batchInsert({
|
|
1713
|
+
tableName: TABLE_TRACES,
|
|
1714
|
+
records
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
function parseWorkflowRun(row) {
|
|
1719
|
+
let parsedSnapshot = row.snapshot;
|
|
1720
|
+
if (typeof parsedSnapshot === "string") {
|
|
952
1721
|
try {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
|
|
1722
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1723
|
+
} catch (e) {
|
|
1724
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
return {
|
|
1728
|
+
workflowName: row.workflow_name,
|
|
1729
|
+
runId: row.run_id,
|
|
1730
|
+
snapshot: parsedSnapshot,
|
|
1731
|
+
createdAt: ensureDate(row.createdAt),
|
|
1732
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
1733
|
+
resourceId: row.resourceId
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
var StoreWorkflowsLance = class extends WorkflowsStorage {
|
|
1737
|
+
client;
|
|
1738
|
+
constructor({ client }) {
|
|
1739
|
+
super();
|
|
1740
|
+
this.client = client;
|
|
1741
|
+
}
|
|
1742
|
+
async persistWorkflowSnapshot({
|
|
1743
|
+
workflowName,
|
|
1744
|
+
runId,
|
|
1745
|
+
snapshot
|
|
1746
|
+
}) {
|
|
1747
|
+
try {
|
|
1748
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1749
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
958
1750
|
const records = await query.toArray();
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1751
|
+
let createdAt;
|
|
1752
|
+
const now = Date.now();
|
|
1753
|
+
if (records.length > 0) {
|
|
1754
|
+
createdAt = records[0].createdAt ?? now;
|
|
1755
|
+
} else {
|
|
1756
|
+
createdAt = now;
|
|
1757
|
+
}
|
|
1758
|
+
const record = {
|
|
1759
|
+
workflow_name: workflowName,
|
|
1760
|
+
run_id: runId,
|
|
1761
|
+
snapshot: JSON.stringify(snapshot),
|
|
1762
|
+
createdAt,
|
|
1763
|
+
updatedAt: now
|
|
1764
|
+
};
|
|
1765
|
+
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
974
1766
|
} catch (error) {
|
|
975
1767
|
throw new MastraError(
|
|
976
1768
|
{
|
|
977
|
-
id: "
|
|
1769
|
+
id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
978
1770
|
domain: ErrorDomain.STORAGE,
|
|
979
1771
|
category: ErrorCategory.THIRD_PARTY,
|
|
980
|
-
details: {
|
|
1772
|
+
details: { workflowName, runId }
|
|
981
1773
|
},
|
|
982
1774
|
error
|
|
983
1775
|
);
|
|
984
1776
|
}
|
|
985
1777
|
}
|
|
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
|
-
}
|
|
1778
|
+
async loadWorkflowSnapshot({
|
|
1779
|
+
workflowName,
|
|
1780
|
+
runId
|
|
1781
|
+
}) {
|
|
1782
|
+
try {
|
|
1783
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1784
|
+
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1023
1785
|
const records = await query.toArray();
|
|
1024
|
-
return
|
|
1025
|
-
runs: records.map((record) => this.parseWorkflowRun(record)),
|
|
1026
|
-
total: records.length
|
|
1027
|
-
};
|
|
1786
|
+
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1028
1787
|
} catch (error) {
|
|
1029
1788
|
throw new MastraError(
|
|
1030
1789
|
{
|
|
1031
|
-
id: "
|
|
1790
|
+
id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
1032
1791
|
domain: ErrorDomain.STORAGE,
|
|
1033
1792
|
category: ErrorCategory.THIRD_PARTY,
|
|
1034
|
-
details: {
|
|
1793
|
+
details: { workflowName, runId }
|
|
1035
1794
|
},
|
|
1036
1795
|
error
|
|
1037
1796
|
);
|
|
1038
1797
|
}
|
|
1039
1798
|
}
|
|
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
1799
|
async getWorkflowRunById(args) {
|
|
1046
1800
|
try {
|
|
1047
|
-
const table = await this.
|
|
1801
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1048
1802
|
let whereClause = `run_id = '${args.runId}'`;
|
|
1049
1803
|
if (args.workflowName) {
|
|
1050
1804
|
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
@@ -1053,7 +1807,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1053
1807
|
const records = await query.toArray();
|
|
1054
1808
|
if (records.length === 0) return null;
|
|
1055
1809
|
const record = records[0];
|
|
1056
|
-
return
|
|
1810
|
+
return parseWorkflowRun(record);
|
|
1057
1811
|
} catch (error) {
|
|
1058
1812
|
throw new MastraError(
|
|
1059
1813
|
{
|
|
@@ -1066,96 +1820,324 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
|
1066
1820
|
);
|
|
1067
1821
|
}
|
|
1068
1822
|
}
|
|
1069
|
-
async
|
|
1070
|
-
workflowName,
|
|
1071
|
-
runId,
|
|
1072
|
-
snapshot
|
|
1073
|
-
}) {
|
|
1823
|
+
async getWorkflowRuns(args) {
|
|
1074
1824
|
try {
|
|
1075
|
-
const table = await this.
|
|
1076
|
-
|
|
1077
|
-
const
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1825
|
+
const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
|
|
1826
|
+
let query = table.query();
|
|
1827
|
+
const conditions = [];
|
|
1828
|
+
if (args?.workflowName) {
|
|
1829
|
+
conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
|
|
1830
|
+
}
|
|
1831
|
+
if (args?.resourceId) {
|
|
1832
|
+
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1833
|
+
}
|
|
1834
|
+
if (args?.fromDate instanceof Date) {
|
|
1835
|
+
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1836
|
+
}
|
|
1837
|
+
if (args?.toDate instanceof Date) {
|
|
1838
|
+
conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1839
|
+
}
|
|
1840
|
+
let total = 0;
|
|
1841
|
+
if (conditions.length > 0) {
|
|
1842
|
+
query = query.where(conditions.join(" AND "));
|
|
1843
|
+
total = await table.countRows(conditions.join(" AND "));
|
|
1082
1844
|
} else {
|
|
1083
|
-
|
|
1845
|
+
total = await table.countRows();
|
|
1084
1846
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1847
|
+
if (args?.limit) {
|
|
1848
|
+
query.limit(args.limit);
|
|
1849
|
+
}
|
|
1850
|
+
if (args?.offset) {
|
|
1851
|
+
query.offset(args.offset);
|
|
1852
|
+
}
|
|
1853
|
+
const records = await query.toArray();
|
|
1854
|
+
return {
|
|
1855
|
+
runs: records.map((record) => parseWorkflowRun(record)),
|
|
1856
|
+
total: total || records.length
|
|
1091
1857
|
};
|
|
1092
|
-
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1093
1858
|
} catch (error) {
|
|
1094
1859
|
throw new MastraError(
|
|
1095
1860
|
{
|
|
1096
|
-
id: "
|
|
1861
|
+
id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
|
|
1097
1862
|
domain: ErrorDomain.STORAGE,
|
|
1098
1863
|
category: ErrorCategory.THIRD_PARTY,
|
|
1099
|
-
details: {
|
|
1864
|
+
details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
|
|
1100
1865
|
},
|
|
1101
1866
|
error
|
|
1102
1867
|
);
|
|
1103
1868
|
}
|
|
1104
1869
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1870
|
+
};
|
|
1871
|
+
|
|
1872
|
+
// src/storage/index.ts
|
|
1873
|
+
var LanceStorage = class _LanceStorage extends MastraStorage {
|
|
1874
|
+
stores;
|
|
1875
|
+
lanceClient;
|
|
1876
|
+
/**
|
|
1877
|
+
* Creates a new instance of LanceStorage
|
|
1878
|
+
* @param uri The URI to connect to LanceDB
|
|
1879
|
+
* @param options connection options
|
|
1880
|
+
*
|
|
1881
|
+
* Usage:
|
|
1882
|
+
*
|
|
1883
|
+
* Connect to a local database
|
|
1884
|
+
* ```ts
|
|
1885
|
+
* const store = await LanceStorage.create('/path/to/db');
|
|
1886
|
+
* ```
|
|
1887
|
+
*
|
|
1888
|
+
* Connect to a LanceDB cloud database
|
|
1889
|
+
* ```ts
|
|
1890
|
+
* const store = await LanceStorage.create('db://host:port');
|
|
1891
|
+
* ```
|
|
1892
|
+
*
|
|
1893
|
+
* Connect to a cloud database
|
|
1894
|
+
* ```ts
|
|
1895
|
+
* const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
1896
|
+
* ```
|
|
1897
|
+
*/
|
|
1898
|
+
static async create(name, uri, options) {
|
|
1899
|
+
const instance = new _LanceStorage(name);
|
|
1109
1900
|
try {
|
|
1110
|
-
|
|
1111
|
-
const
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1901
|
+
instance.lanceClient = await connect(uri, options);
|
|
1902
|
+
const operations = new StoreOperationsLance({ client: instance.lanceClient });
|
|
1903
|
+
instance.stores = {
|
|
1904
|
+
operations: new StoreOperationsLance({ client: instance.lanceClient }),
|
|
1905
|
+
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1906
|
+
traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
|
|
1907
|
+
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1908
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
|
|
1909
|
+
legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
|
|
1910
|
+
};
|
|
1911
|
+
return instance;
|
|
1912
|
+
} catch (e) {
|
|
1115
1913
|
throw new MastraError(
|
|
1116
1914
|
{
|
|
1117
|
-
id: "
|
|
1915
|
+
id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
|
|
1118
1916
|
domain: ErrorDomain.STORAGE,
|
|
1119
1917
|
category: ErrorCategory.THIRD_PARTY,
|
|
1120
|
-
|
|
1918
|
+
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1919
|
+
details: { uri, optionsProvided: !!options }
|
|
1121
1920
|
},
|
|
1122
|
-
|
|
1921
|
+
e
|
|
1123
1922
|
);
|
|
1124
1923
|
}
|
|
1125
1924
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1925
|
+
/**
|
|
1926
|
+
* @internal
|
|
1927
|
+
* Private constructor to enforce using the create factory method
|
|
1928
|
+
*/
|
|
1929
|
+
constructor(name) {
|
|
1930
|
+
super({ name });
|
|
1931
|
+
const operations = new StoreOperationsLance({ client: this.lanceClient });
|
|
1932
|
+
this.stores = {
|
|
1933
|
+
operations: new StoreOperationsLance({ client: this.lanceClient }),
|
|
1934
|
+
workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
|
|
1935
|
+
traces: new StoreTracesLance({ client: this.lanceClient, operations }),
|
|
1936
|
+
scores: new StoreScoresLance({ client: this.lanceClient }),
|
|
1937
|
+
legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
|
|
1938
|
+
memory: new StoreMemoryLance({ client: this.lanceClient, operations })
|
|
1939
|
+
};
|
|
1135
1940
|
}
|
|
1136
|
-
async
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1142
|
-
},
|
|
1143
|
-
"Method not implemented."
|
|
1144
|
-
);
|
|
1941
|
+
async createTable({
|
|
1942
|
+
tableName,
|
|
1943
|
+
schema
|
|
1944
|
+
}) {
|
|
1945
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
1145
1946
|
}
|
|
1146
|
-
async
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
);
|
|
1947
|
+
async dropTable({ tableName }) {
|
|
1948
|
+
return this.stores.operations.dropTable({ tableName });
|
|
1949
|
+
}
|
|
1950
|
+
async alterTable({
|
|
1951
|
+
tableName,
|
|
1952
|
+
schema,
|
|
1953
|
+
ifNotExists
|
|
1954
|
+
}) {
|
|
1955
|
+
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
1956
|
+
}
|
|
1957
|
+
async clearTable({ tableName }) {
|
|
1958
|
+
return this.stores.operations.clearTable({ tableName });
|
|
1959
|
+
}
|
|
1960
|
+
async insert({ tableName, record }) {
|
|
1961
|
+
return this.stores.operations.insert({ tableName, record });
|
|
1962
|
+
}
|
|
1963
|
+
async batchInsert({ tableName, records }) {
|
|
1964
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
1965
|
+
}
|
|
1966
|
+
async load({ tableName, keys }) {
|
|
1967
|
+
return this.stores.operations.load({ tableName, keys });
|
|
1968
|
+
}
|
|
1969
|
+
async getThreadById({ threadId }) {
|
|
1970
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
1971
|
+
}
|
|
1972
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
1973
|
+
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
1977
|
+
* @param thread - The thread to save
|
|
1978
|
+
* @returns The saved thread
|
|
1979
|
+
*/
|
|
1980
|
+
async saveThread({ thread }) {
|
|
1981
|
+
return this.stores.memory.saveThread({ thread });
|
|
1982
|
+
}
|
|
1983
|
+
async updateThread({
|
|
1984
|
+
id,
|
|
1985
|
+
title,
|
|
1986
|
+
metadata
|
|
1987
|
+
}) {
|
|
1988
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
1989
|
+
}
|
|
1990
|
+
async deleteThread({ threadId }) {
|
|
1991
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
1992
|
+
}
|
|
1993
|
+
get supports() {
|
|
1994
|
+
return {
|
|
1995
|
+
selectByIncludeResourceScope: true,
|
|
1996
|
+
resourceWorkingMemory: true,
|
|
1997
|
+
hasColumn: true,
|
|
1998
|
+
createTable: true
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
async getResourceById({ resourceId }) {
|
|
2002
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2003
|
+
}
|
|
2004
|
+
async saveResource({ resource }) {
|
|
2005
|
+
return this.stores.memory.saveResource({ resource });
|
|
2006
|
+
}
|
|
2007
|
+
async updateResource({
|
|
2008
|
+
resourceId,
|
|
2009
|
+
workingMemory,
|
|
2010
|
+
metadata
|
|
2011
|
+
}) {
|
|
2012
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
2016
|
+
* @param records - The sorted array of records to process
|
|
2017
|
+
* @param include - The array of include specifications with context parameters
|
|
2018
|
+
* @returns The processed array with context messages included
|
|
2019
|
+
*/
|
|
2020
|
+
processMessagesWithContext(records, include) {
|
|
2021
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
2022
|
+
if (messagesWithContext.length === 0) {
|
|
2023
|
+
return records;
|
|
2024
|
+
}
|
|
2025
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
2026
|
+
records.forEach((message, index) => {
|
|
2027
|
+
messageIndexMap.set(message.id, index);
|
|
2028
|
+
});
|
|
2029
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
2030
|
+
for (const item of messagesWithContext) {
|
|
2031
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
2032
|
+
if (messageIndex !== void 0) {
|
|
2033
|
+
if (item.withPreviousMessages) {
|
|
2034
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
2035
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
2036
|
+
additionalIndices.add(i);
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
if (item.withNextMessages) {
|
|
2040
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
2041
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
2042
|
+
additionalIndices.add(i);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
if (additionalIndices.size === 0) {
|
|
2048
|
+
return records;
|
|
2049
|
+
}
|
|
2050
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
2051
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
2052
|
+
records.forEach((record, index) => {
|
|
2053
|
+
if (originalMatchIds.has(record.id)) {
|
|
2054
|
+
allIndices.add(index);
|
|
2055
|
+
}
|
|
2056
|
+
});
|
|
2057
|
+
additionalIndices.forEach((index) => {
|
|
2058
|
+
allIndices.add(index);
|
|
2059
|
+
});
|
|
2060
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
2061
|
+
}
|
|
2062
|
+
async getMessages({
|
|
2063
|
+
threadId,
|
|
2064
|
+
resourceId,
|
|
2065
|
+
selectBy,
|
|
2066
|
+
format,
|
|
2067
|
+
threadConfig
|
|
2068
|
+
}) {
|
|
2069
|
+
return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
|
|
2070
|
+
}
|
|
2071
|
+
async saveMessages(args) {
|
|
2072
|
+
return this.stores.memory.saveMessages(args);
|
|
2073
|
+
}
|
|
2074
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2075
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2076
|
+
}
|
|
2077
|
+
async getMessagesPaginated(args) {
|
|
2078
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
1155
2079
|
}
|
|
1156
2080
|
async updateMessages(_args) {
|
|
1157
|
-
this.
|
|
1158
|
-
|
|
2081
|
+
return this.stores.memory.updateMessages(_args);
|
|
2082
|
+
}
|
|
2083
|
+
async getTraceById(args) {
|
|
2084
|
+
return this.stores.traces.getTraceById(args);
|
|
2085
|
+
}
|
|
2086
|
+
async getTraces(args) {
|
|
2087
|
+
return this.stores.traces.getTraces(args);
|
|
2088
|
+
}
|
|
2089
|
+
async getTracesPaginated(args) {
|
|
2090
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
2091
|
+
}
|
|
2092
|
+
async getEvalsByAgentName(agentName, type) {
|
|
2093
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2094
|
+
}
|
|
2095
|
+
async getEvals(options) {
|
|
2096
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
2097
|
+
}
|
|
2098
|
+
async getWorkflowRuns(args) {
|
|
2099
|
+
return this.stores.workflows.getWorkflowRuns(args);
|
|
2100
|
+
}
|
|
2101
|
+
async getWorkflowRunById(args) {
|
|
2102
|
+
return this.stores.workflows.getWorkflowRunById(args);
|
|
2103
|
+
}
|
|
2104
|
+
async persistWorkflowSnapshot({
|
|
2105
|
+
workflowName,
|
|
2106
|
+
runId,
|
|
2107
|
+
snapshot
|
|
2108
|
+
}) {
|
|
2109
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2110
|
+
}
|
|
2111
|
+
async loadWorkflowSnapshot({
|
|
2112
|
+
workflowName,
|
|
2113
|
+
runId
|
|
2114
|
+
}) {
|
|
2115
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2116
|
+
}
|
|
2117
|
+
async getScoreById({ id: _id }) {
|
|
2118
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
2119
|
+
}
|
|
2120
|
+
async getScoresByScorerId({
|
|
2121
|
+
scorerId,
|
|
2122
|
+
pagination
|
|
2123
|
+
}) {
|
|
2124
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
|
|
2125
|
+
}
|
|
2126
|
+
async saveScore(_score) {
|
|
2127
|
+
return this.stores.scores.saveScore(_score);
|
|
2128
|
+
}
|
|
2129
|
+
async getScoresByRunId({
|
|
2130
|
+
runId,
|
|
2131
|
+
pagination
|
|
2132
|
+
}) {
|
|
2133
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
2134
|
+
}
|
|
2135
|
+
async getScoresByEntityId({
|
|
2136
|
+
entityId,
|
|
2137
|
+
entityType,
|
|
2138
|
+
pagination
|
|
2139
|
+
}) {
|
|
2140
|
+
return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
|
|
1159
2141
|
}
|
|
1160
2142
|
};
|
|
1161
2143
|
var LanceFilterTranslator = class extends BaseFilterTranslator {
|