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