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