@mastra/upstash 0.12.1 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +53 -0
- package/dist/_tsup-dts-rollup.d.cts +342 -40
- package/dist/_tsup-dts-rollup.d.ts +342 -40
- package/dist/index.cjs +1133 -612
- package/dist/index.js +1134 -613
- package/docker-compose.yaml +1 -1
- package/package.json +5 -5
- package/src/storage/domains/legacy-evals/index.ts +279 -0
- package/src/storage/domains/memory/index.ts +902 -0
- package/src/storage/domains/operations/index.ts +168 -0
- package/src/storage/domains/scores/index.ts +216 -0
- package/src/storage/domains/traces/index.ts +172 -0
- package/src/storage/domains/utils.ts +57 -0
- package/src/storage/domains/workflows/index.ts +243 -0
- package/src/storage/index.test.ts +13 -0
- package/src/storage/index.ts +143 -1416
- package/src/storage/upstash.test.ts +0 -1461
package/dist/index.js
CHANGED
|
@@ -1,157 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
-
import { MastraStorage, TABLE_MESSAGES, TABLE_WORKFLOW_SNAPSHOT, TABLE_EVALS, TABLE_TRACES, TABLE_THREADS, TABLE_RESOURCES } from '@mastra/core/storage';
|
|
1
|
+
import { MastraStorage, StoreOperations, TracesStorage, TABLE_TRACES, ScoresStorage, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, MemoryStorage, TABLE_THREADS, resolveMessageLimit, TABLE_RESOURCES, LegacyEvalsStorage, TABLE_EVALS, TABLE_MESSAGES, serializeDate } from '@mastra/core/storage';
|
|
4
2
|
import { Redis } from '@upstash/redis';
|
|
3
|
+
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
4
|
+
import { MessageList } from '@mastra/core/agent';
|
|
5
5
|
import { MastraVector } from '@mastra/core/vector';
|
|
6
6
|
import { Index } from '@upstash/vector';
|
|
7
7
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
8
8
|
|
|
9
9
|
// src/storage/index.ts
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
get supports() {
|
|
20
|
-
return {
|
|
21
|
-
selectByIncludeResourceScope: true,
|
|
22
|
-
resourceWorkingMemory: true
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
transformEvalRecord(record) {
|
|
26
|
-
let result = record.result;
|
|
27
|
-
if (typeof result === "string") {
|
|
28
|
-
try {
|
|
29
|
-
result = JSON.parse(result);
|
|
30
|
-
} catch {
|
|
31
|
-
console.warn("Failed to parse result JSON:");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
let testInfo = record.test_info;
|
|
35
|
-
if (typeof testInfo === "string") {
|
|
36
|
-
try {
|
|
37
|
-
testInfo = JSON.parse(testInfo);
|
|
38
|
-
} catch {
|
|
39
|
-
console.warn("Failed to parse test_info JSON:");
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
agentName: record.agent_name,
|
|
44
|
-
input: record.input,
|
|
45
|
-
output: record.output,
|
|
46
|
-
result,
|
|
47
|
-
metricName: record.metric_name,
|
|
48
|
-
instructions: record.instructions,
|
|
49
|
-
testInfo,
|
|
50
|
-
globalRunId: record.global_run_id,
|
|
51
|
-
runId: record.run_id,
|
|
52
|
-
createdAt: typeof record.created_at === "string" ? record.created_at : record.created_at instanceof Date ? record.created_at.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
parseJSON(value) {
|
|
56
|
-
if (typeof value === "string") {
|
|
57
|
-
try {
|
|
58
|
-
return JSON.parse(value);
|
|
59
|
-
} catch {
|
|
60
|
-
return value;
|
|
61
|
-
}
|
|
10
|
+
function transformEvalRecord(record) {
|
|
11
|
+
let result = record.result;
|
|
12
|
+
if (typeof result === "string") {
|
|
13
|
+
try {
|
|
14
|
+
result = JSON.parse(result);
|
|
15
|
+
} catch {
|
|
16
|
+
console.warn("Failed to parse result JSON:");
|
|
62
17
|
}
|
|
63
|
-
return value;
|
|
64
|
-
}
|
|
65
|
-
getKey(tableName, keys) {
|
|
66
|
-
const keyParts = Object.entries(keys).filter(([_, value]) => value !== void 0).map(([key, value]) => `${key}:${value}`);
|
|
67
|
-
return `${tableName}:${keyParts.join(":")}`;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Scans for keys matching the given pattern using SCAN and returns them as an array.
|
|
71
|
-
* @param pattern Redis key pattern, e.g. "table:*"
|
|
72
|
-
* @param batchSize Number of keys to scan per batch (default: 1000)
|
|
73
|
-
*/
|
|
74
|
-
async scanKeys(pattern, batchSize = 1e4) {
|
|
75
|
-
let cursor = "0";
|
|
76
|
-
let keys = [];
|
|
77
|
-
do {
|
|
78
|
-
const [nextCursor, batch] = await this.redis.scan(cursor, {
|
|
79
|
-
match: pattern,
|
|
80
|
-
count: batchSize
|
|
81
|
-
});
|
|
82
|
-
keys.push(...batch);
|
|
83
|
-
cursor = nextCursor;
|
|
84
|
-
} while (cursor !== "0");
|
|
85
|
-
return keys;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Deletes all keys matching the given pattern using SCAN and DEL in batches.
|
|
89
|
-
* @param pattern Redis key pattern, e.g. "table:*"
|
|
90
|
-
* @param batchSize Number of keys to delete per batch (default: 1000)
|
|
91
|
-
*/
|
|
92
|
-
async scanAndDelete(pattern, batchSize = 1e4) {
|
|
93
|
-
let cursor = "0";
|
|
94
|
-
let totalDeleted = 0;
|
|
95
|
-
do {
|
|
96
|
-
const [nextCursor, keys] = await this.redis.scan(cursor, {
|
|
97
|
-
match: pattern,
|
|
98
|
-
count: batchSize
|
|
99
|
-
});
|
|
100
|
-
if (keys.length > 0) {
|
|
101
|
-
await this.redis.del(...keys);
|
|
102
|
-
totalDeleted += keys.length;
|
|
103
|
-
}
|
|
104
|
-
cursor = nextCursor;
|
|
105
|
-
} while (cursor !== "0");
|
|
106
|
-
return totalDeleted;
|
|
107
|
-
}
|
|
108
|
-
getMessageKey(threadId, messageId) {
|
|
109
|
-
const key = this.getKey(TABLE_MESSAGES, { threadId, id: messageId });
|
|
110
|
-
return key;
|
|
111
18
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
120
|
-
} catch (e) {
|
|
121
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
122
|
-
}
|
|
19
|
+
let testInfo = record.test_info;
|
|
20
|
+
if (typeof testInfo === "string") {
|
|
21
|
+
try {
|
|
22
|
+
testInfo = JSON.parse(testInfo);
|
|
23
|
+
} catch {
|
|
24
|
+
console.warn("Failed to parse test_info JSON:");
|
|
123
25
|
}
|
|
124
|
-
return {
|
|
125
|
-
workflowName: row.workflow_name,
|
|
126
|
-
runId: row.run_id,
|
|
127
|
-
snapshot: parsedSnapshot,
|
|
128
|
-
createdAt: this.ensureDate(row.createdAt),
|
|
129
|
-
updatedAt: this.ensureDate(row.updatedAt),
|
|
130
|
-
resourceId: row.resourceId
|
|
131
|
-
};
|
|
132
26
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
};
|
|
154
|
-
return { key, processedRecord };
|
|
27
|
+
return {
|
|
28
|
+
agentName: record.agent_name,
|
|
29
|
+
input: record.input,
|
|
30
|
+
output: record.output,
|
|
31
|
+
result,
|
|
32
|
+
metricName: record.metric_name,
|
|
33
|
+
instructions: record.instructions,
|
|
34
|
+
testInfo,
|
|
35
|
+
globalRunId: record.global_run_id,
|
|
36
|
+
runId: record.run_id,
|
|
37
|
+
createdAt: typeof record.created_at === "string" ? record.created_at : record.created_at instanceof Date ? record.created_at.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
var StoreLegacyEvalsUpstash = class extends LegacyEvalsStorage {
|
|
41
|
+
client;
|
|
42
|
+
operations;
|
|
43
|
+
constructor({ client, operations }) {
|
|
44
|
+
super();
|
|
45
|
+
this.client = client;
|
|
46
|
+
this.operations = operations;
|
|
155
47
|
}
|
|
156
48
|
/**
|
|
157
49
|
* @deprecated Use getEvals instead
|
|
@@ -159,11 +51,11 @@ var UpstashStore = class extends MastraStorage {
|
|
|
159
51
|
async getEvalsByAgentName(agentName, type) {
|
|
160
52
|
try {
|
|
161
53
|
const pattern = `${TABLE_EVALS}:*`;
|
|
162
|
-
const keys = await this.scanKeys(pattern);
|
|
54
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
163
55
|
if (keys.length === 0) {
|
|
164
56
|
return [];
|
|
165
57
|
}
|
|
166
|
-
const pipeline = this.
|
|
58
|
+
const pipeline = this.client.pipeline();
|
|
167
59
|
keys.forEach((key) => pipeline.get(key));
|
|
168
60
|
const results = await pipeline.exec();
|
|
169
61
|
const nonNullRecords = results.filter(
|
|
@@ -197,7 +89,7 @@ var UpstashStore = class extends MastraStorage {
|
|
|
197
89
|
}
|
|
198
90
|
});
|
|
199
91
|
}
|
|
200
|
-
return filteredEvals.map((record) =>
|
|
92
|
+
return filteredEvals.map((record) => transformEvalRecord(record));
|
|
201
93
|
} catch (error) {
|
|
202
94
|
const mastraError = new MastraError(
|
|
203
95
|
{
|
|
@@ -214,148 +106,198 @@ var UpstashStore = class extends MastraStorage {
|
|
|
214
106
|
}
|
|
215
107
|
}
|
|
216
108
|
/**
|
|
217
|
-
*
|
|
109
|
+
* Get all evaluations with pagination and total count
|
|
110
|
+
* @param options Pagination and filtering options
|
|
111
|
+
* @returns Object with evals array and total count
|
|
218
112
|
*/
|
|
219
|
-
async
|
|
220
|
-
if (args.fromDate || args.toDate) {
|
|
221
|
-
args.dateRange = {
|
|
222
|
-
start: args.fromDate,
|
|
223
|
-
end: args.toDate
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
try {
|
|
227
|
-
const { traces } = await this.getTracesPaginated(args);
|
|
228
|
-
return traces;
|
|
229
|
-
} catch (error) {
|
|
230
|
-
throw new MastraError(
|
|
231
|
-
{
|
|
232
|
-
id: "STORAGE_UPSTASH_STORAGE_GET_TRACES_FAILED",
|
|
233
|
-
domain: ErrorDomain.STORAGE,
|
|
234
|
-
category: ErrorCategory.THIRD_PARTY
|
|
235
|
-
},
|
|
236
|
-
error
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
async getTracesPaginated(args) {
|
|
241
|
-
const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
|
|
242
|
-
const fromDate = dateRange?.start;
|
|
243
|
-
const toDate = dateRange?.end;
|
|
113
|
+
async getEvals(options) {
|
|
244
114
|
try {
|
|
245
|
-
const
|
|
246
|
-
const
|
|
115
|
+
const { agentName, type, page = 0, perPage = 100, dateRange } = options || {};
|
|
116
|
+
const fromDate = dateRange?.start;
|
|
117
|
+
const toDate = dateRange?.end;
|
|
118
|
+
const pattern = `${TABLE_EVALS}:*`;
|
|
119
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
247
120
|
if (keys.length === 0) {
|
|
248
121
|
return {
|
|
249
|
-
|
|
122
|
+
evals: [],
|
|
250
123
|
total: 0,
|
|
251
124
|
page,
|
|
252
|
-
perPage
|
|
125
|
+
perPage,
|
|
253
126
|
hasMore: false
|
|
254
127
|
};
|
|
255
128
|
}
|
|
256
|
-
const pipeline = this.
|
|
129
|
+
const pipeline = this.client.pipeline();
|
|
257
130
|
keys.forEach((key) => pipeline.get(key));
|
|
258
131
|
const results = await pipeline.exec();
|
|
259
|
-
let
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (name) {
|
|
263
|
-
filteredTraces = filteredTraces.filter((record) => record.name?.toLowerCase().startsWith(name.toLowerCase()));
|
|
264
|
-
}
|
|
265
|
-
if (scope) {
|
|
266
|
-
filteredTraces = filteredTraces.filter((record) => record.scope === scope);
|
|
132
|
+
let filteredEvals = results.map((result) => result).filter((record) => record !== null && typeof record === "object");
|
|
133
|
+
if (agentName) {
|
|
134
|
+
filteredEvals = filteredEvals.filter((record) => record.agent_name === agentName);
|
|
267
135
|
}
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
136
|
+
if (type === "test") {
|
|
137
|
+
filteredEvals = filteredEvals.filter((record) => {
|
|
138
|
+
if (!record.test_info) return false;
|
|
139
|
+
try {
|
|
140
|
+
if (typeof record.test_info === "string") {
|
|
141
|
+
const parsedTestInfo = JSON.parse(record.test_info);
|
|
142
|
+
return parsedTestInfo && typeof parsedTestInfo === "object" && "testPath" in parsedTestInfo;
|
|
143
|
+
}
|
|
144
|
+
return typeof record.test_info === "object" && "testPath" in record.test_info;
|
|
145
|
+
} catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
} else if (type === "live") {
|
|
150
|
+
filteredEvals = filteredEvals.filter((record) => {
|
|
151
|
+
if (!record.test_info) return true;
|
|
152
|
+
try {
|
|
153
|
+
if (typeof record.test_info === "string") {
|
|
154
|
+
const parsedTestInfo = JSON.parse(record.test_info);
|
|
155
|
+
return !(parsedTestInfo && typeof parsedTestInfo === "object" && "testPath" in parsedTestInfo);
|
|
156
|
+
}
|
|
157
|
+
return !(typeof record.test_info === "object" && "testPath" in record.test_info);
|
|
158
|
+
} catch {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
274
161
|
});
|
|
275
|
-
}
|
|
276
|
-
if (filters) {
|
|
277
|
-
filteredTraces = filteredTraces.filter(
|
|
278
|
-
(record) => Object.entries(filters).every(([key, value]) => record[key] === value)
|
|
279
|
-
);
|
|
280
162
|
}
|
|
281
163
|
if (fromDate) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
164
|
+
filteredEvals = filteredEvals.filter((record) => {
|
|
165
|
+
const createdAt = new Date(record.created_at || record.createdAt || 0);
|
|
166
|
+
return createdAt.getTime() >= fromDate.getTime();
|
|
167
|
+
});
|
|
285
168
|
}
|
|
286
169
|
if (toDate) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
170
|
+
filteredEvals = filteredEvals.filter((record) => {
|
|
171
|
+
const createdAt = new Date(record.created_at || record.createdAt || 0);
|
|
172
|
+
return createdAt.getTime() <= toDate.getTime();
|
|
173
|
+
});
|
|
290
174
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
events: this.parseJSON(record.events),
|
|
301
|
-
links: this.parseJSON(record.links),
|
|
302
|
-
attributes: this.parseJSON(record.attributes),
|
|
303
|
-
startTime: record.startTime,
|
|
304
|
-
endTime: record.endTime,
|
|
305
|
-
other: this.parseJSON(record.other),
|
|
306
|
-
createdAt: this.ensureDate(record.createdAt)
|
|
307
|
-
}));
|
|
308
|
-
const total = transformedTraces.length;
|
|
309
|
-
const resolvedPerPage = perPage || 100;
|
|
310
|
-
const start = page * resolvedPerPage;
|
|
311
|
-
const end = start + resolvedPerPage;
|
|
312
|
-
const paginatedTraces = transformedTraces.slice(start, end);
|
|
175
|
+
filteredEvals.sort((a, b) => {
|
|
176
|
+
const dateA = new Date(a.created_at || a.createdAt || 0).getTime();
|
|
177
|
+
const dateB = new Date(b.created_at || b.createdAt || 0).getTime();
|
|
178
|
+
return dateB - dateA;
|
|
179
|
+
});
|
|
180
|
+
const total = filteredEvals.length;
|
|
181
|
+
const start = page * perPage;
|
|
182
|
+
const end = start + perPage;
|
|
183
|
+
const paginatedEvals = filteredEvals.slice(start, end);
|
|
313
184
|
const hasMore = end < total;
|
|
185
|
+
const evals = paginatedEvals.map((record) => transformEvalRecord(record));
|
|
314
186
|
return {
|
|
315
|
-
|
|
187
|
+
evals,
|
|
316
188
|
total,
|
|
317
189
|
page,
|
|
318
|
-
perPage
|
|
190
|
+
perPage,
|
|
319
191
|
hasMore
|
|
320
192
|
};
|
|
321
193
|
} catch (error) {
|
|
194
|
+
const { page = 0, perPage = 100 } = options || {};
|
|
322
195
|
const mastraError = new MastraError(
|
|
323
196
|
{
|
|
324
|
-
id: "
|
|
197
|
+
id: "STORAGE_UPSTASH_STORAGE_GET_EVALS_FAILED",
|
|
325
198
|
domain: ErrorDomain.STORAGE,
|
|
326
199
|
category: ErrorCategory.THIRD_PARTY,
|
|
327
200
|
details: {
|
|
328
|
-
|
|
329
|
-
|
|
201
|
+
page,
|
|
202
|
+
perPage
|
|
330
203
|
}
|
|
331
204
|
},
|
|
332
205
|
error
|
|
333
206
|
);
|
|
334
|
-
this.logger?.trackException(mastraError);
|
|
335
207
|
this.logger.error(mastraError.toString());
|
|
208
|
+
this.logger?.trackException(mastraError);
|
|
336
209
|
return {
|
|
337
|
-
|
|
210
|
+
evals: [],
|
|
338
211
|
total: 0,
|
|
339
212
|
page,
|
|
340
|
-
perPage
|
|
213
|
+
perPage,
|
|
341
214
|
hasMore: false
|
|
342
215
|
};
|
|
343
216
|
}
|
|
344
217
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
218
|
+
};
|
|
219
|
+
function ensureDate(value) {
|
|
220
|
+
if (!value) return null;
|
|
221
|
+
if (value instanceof Date) return value;
|
|
222
|
+
if (typeof value === "string") return new Date(value);
|
|
223
|
+
if (typeof value === "number") return new Date(value);
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
function parseJSON(value) {
|
|
227
|
+
if (typeof value === "string") {
|
|
228
|
+
try {
|
|
229
|
+
return JSON.parse(value);
|
|
230
|
+
} catch {
|
|
231
|
+
return value;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
function getKey(tableName, keys) {
|
|
237
|
+
const keyParts = Object.entries(keys).filter(([_, value]) => value !== void 0).map(([key, value]) => `${key}:${value}`);
|
|
238
|
+
return `${tableName}:${keyParts.join(":")}`;
|
|
239
|
+
}
|
|
240
|
+
function processRecord(tableName, record) {
|
|
241
|
+
let key;
|
|
242
|
+
if (tableName === TABLE_MESSAGES) {
|
|
243
|
+
key = getKey(tableName, { threadId: record.threadId, id: record.id });
|
|
244
|
+
} else if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
245
|
+
key = getKey(tableName, {
|
|
246
|
+
namespace: record.namespace || "workflows",
|
|
247
|
+
workflow_name: record.workflow_name,
|
|
248
|
+
run_id: record.run_id,
|
|
249
|
+
...record.resourceId ? { resourceId: record.resourceId } : {}
|
|
250
|
+
});
|
|
251
|
+
} else if (tableName === TABLE_EVALS) {
|
|
252
|
+
key = getKey(tableName, { id: record.run_id });
|
|
253
|
+
} else {
|
|
254
|
+
key = getKey(tableName, { id: record.id });
|
|
255
|
+
}
|
|
256
|
+
const processedRecord = {
|
|
257
|
+
...record,
|
|
258
|
+
createdAt: serializeDate(record.createdAt),
|
|
259
|
+
updatedAt: serializeDate(record.updatedAt)
|
|
260
|
+
};
|
|
261
|
+
return { key, processedRecord };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/storage/domains/memory/index.ts
|
|
265
|
+
function getThreadMessagesKey(threadId) {
|
|
266
|
+
return `thread:${threadId}:messages`;
|
|
267
|
+
}
|
|
268
|
+
function getMessageKey(threadId, messageId) {
|
|
269
|
+
const key = getKey(TABLE_MESSAGES, { threadId, id: messageId });
|
|
270
|
+
return key;
|
|
271
|
+
}
|
|
272
|
+
var StoreMemoryUpstash = class extends MemoryStorage {
|
|
273
|
+
client;
|
|
274
|
+
operations;
|
|
275
|
+
constructor({ client, operations }) {
|
|
276
|
+
super();
|
|
277
|
+
this.client = client;
|
|
278
|
+
this.operations = operations;
|
|
279
|
+
}
|
|
280
|
+
async getThreadById({ threadId }) {
|
|
349
281
|
try {
|
|
350
|
-
await this.
|
|
282
|
+
const thread = await this.operations.load({
|
|
283
|
+
tableName: TABLE_THREADS,
|
|
284
|
+
keys: { id: threadId }
|
|
285
|
+
});
|
|
286
|
+
if (!thread) return null;
|
|
287
|
+
return {
|
|
288
|
+
...thread,
|
|
289
|
+
createdAt: ensureDate(thread.createdAt),
|
|
290
|
+
updatedAt: ensureDate(thread.updatedAt),
|
|
291
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
|
|
292
|
+
};
|
|
351
293
|
} catch (error) {
|
|
352
294
|
throw new MastraError(
|
|
353
295
|
{
|
|
354
|
-
id: "
|
|
296
|
+
id: "STORAGE_UPSTASH_STORAGE_GET_THREAD_BY_ID_FAILED",
|
|
355
297
|
domain: ErrorDomain.STORAGE,
|
|
356
298
|
category: ErrorCategory.THIRD_PARTY,
|
|
357
299
|
details: {
|
|
358
|
-
|
|
300
|
+
threadId
|
|
359
301
|
}
|
|
360
302
|
},
|
|
361
303
|
error
|
|
@@ -363,135 +305,17 @@ var UpstashStore = class extends MastraStorage {
|
|
|
363
305
|
}
|
|
364
306
|
}
|
|
365
307
|
/**
|
|
366
|
-
*
|
|
367
|
-
* @param tableName Name of the table
|
|
368
|
-
* @param schema Schema of the table
|
|
369
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
308
|
+
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
370
309
|
*/
|
|
371
|
-
async
|
|
372
|
-
}
|
|
373
|
-
async clearTable({ tableName }) {
|
|
374
|
-
const pattern = `${tableName}:*`;
|
|
375
|
-
try {
|
|
376
|
-
await this.scanAndDelete(pattern);
|
|
377
|
-
} catch (error) {
|
|
378
|
-
throw new MastraError(
|
|
379
|
-
{
|
|
380
|
-
id: "STORAGE_UPSTASH_STORAGE_CLEAR_TABLE_FAILED",
|
|
381
|
-
domain: ErrorDomain.STORAGE,
|
|
382
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
383
|
-
details: {
|
|
384
|
-
tableName
|
|
385
|
-
}
|
|
386
|
-
},
|
|
387
|
-
error
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
async insert({ tableName, record }) {
|
|
392
|
-
const { key, processedRecord } = this.processRecord(tableName, record);
|
|
393
|
-
try {
|
|
394
|
-
await this.redis.set(key, processedRecord);
|
|
395
|
-
} catch (error) {
|
|
396
|
-
throw new MastraError(
|
|
397
|
-
{
|
|
398
|
-
id: "STORAGE_UPSTASH_STORAGE_INSERT_FAILED",
|
|
399
|
-
domain: ErrorDomain.STORAGE,
|
|
400
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
401
|
-
details: {
|
|
402
|
-
tableName
|
|
403
|
-
}
|
|
404
|
-
},
|
|
405
|
-
error
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
async batchInsert(input) {
|
|
410
|
-
const { tableName, records } = input;
|
|
411
|
-
if (!records.length) return;
|
|
412
|
-
const batchSize = 1e3;
|
|
413
|
-
try {
|
|
414
|
-
for (let i = 0; i < records.length; i += batchSize) {
|
|
415
|
-
const batch = records.slice(i, i + batchSize);
|
|
416
|
-
const pipeline = this.redis.pipeline();
|
|
417
|
-
for (const record of batch) {
|
|
418
|
-
const { key, processedRecord } = this.processRecord(tableName, record);
|
|
419
|
-
pipeline.set(key, processedRecord);
|
|
420
|
-
}
|
|
421
|
-
await pipeline.exec();
|
|
422
|
-
}
|
|
423
|
-
} catch (error) {
|
|
424
|
-
throw new MastraError(
|
|
425
|
-
{
|
|
426
|
-
id: "STORAGE_UPSTASH_STORAGE_BATCH_INSERT_FAILED",
|
|
427
|
-
domain: ErrorDomain.STORAGE,
|
|
428
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
429
|
-
details: {
|
|
430
|
-
tableName
|
|
431
|
-
}
|
|
432
|
-
},
|
|
433
|
-
error
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
async load({ tableName, keys }) {
|
|
438
|
-
const key = this.getKey(tableName, keys);
|
|
439
|
-
try {
|
|
440
|
-
const data = await this.redis.get(key);
|
|
441
|
-
return data || null;
|
|
442
|
-
} catch (error) {
|
|
443
|
-
throw new MastraError(
|
|
444
|
-
{
|
|
445
|
-
id: "STORAGE_UPSTASH_STORAGE_LOAD_FAILED",
|
|
446
|
-
domain: ErrorDomain.STORAGE,
|
|
447
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
448
|
-
details: {
|
|
449
|
-
tableName
|
|
450
|
-
}
|
|
451
|
-
},
|
|
452
|
-
error
|
|
453
|
-
);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
async getThreadById({ threadId }) {
|
|
457
|
-
try {
|
|
458
|
-
const thread = await this.load({
|
|
459
|
-
tableName: TABLE_THREADS,
|
|
460
|
-
keys: { id: threadId }
|
|
461
|
-
});
|
|
462
|
-
if (!thread) return null;
|
|
463
|
-
return {
|
|
464
|
-
...thread,
|
|
465
|
-
createdAt: this.ensureDate(thread.createdAt),
|
|
466
|
-
updatedAt: this.ensureDate(thread.updatedAt),
|
|
467
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
|
|
468
|
-
};
|
|
469
|
-
} catch (error) {
|
|
470
|
-
throw new MastraError(
|
|
471
|
-
{
|
|
472
|
-
id: "STORAGE_UPSTASH_STORAGE_GET_THREAD_BY_ID_FAILED",
|
|
473
|
-
domain: ErrorDomain.STORAGE,
|
|
474
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
475
|
-
details: {
|
|
476
|
-
threadId
|
|
477
|
-
}
|
|
478
|
-
},
|
|
479
|
-
error
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
485
|
-
*/
|
|
486
|
-
async getThreadsByResourceId({ resourceId }) {
|
|
310
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
487
311
|
try {
|
|
488
312
|
const pattern = `${TABLE_THREADS}:*`;
|
|
489
|
-
const keys = await this.scanKeys(pattern);
|
|
313
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
490
314
|
if (keys.length === 0) {
|
|
491
315
|
return [];
|
|
492
316
|
}
|
|
493
317
|
const allThreads = [];
|
|
494
|
-
const pipeline = this.
|
|
318
|
+
const pipeline = this.client.pipeline();
|
|
495
319
|
keys.forEach((key) => pipeline.get(key));
|
|
496
320
|
const results = await pipeline.exec();
|
|
497
321
|
for (let i = 0; i < results.length; i++) {
|
|
@@ -499,8 +323,8 @@ var UpstashStore = class extends MastraStorage {
|
|
|
499
323
|
if (thread && thread.resourceId === resourceId) {
|
|
500
324
|
allThreads.push({
|
|
501
325
|
...thread,
|
|
502
|
-
createdAt:
|
|
503
|
-
updatedAt:
|
|
326
|
+
createdAt: ensureDate(thread.createdAt),
|
|
327
|
+
updatedAt: ensureDate(thread.updatedAt),
|
|
504
328
|
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
|
|
505
329
|
});
|
|
506
330
|
}
|
|
@@ -567,7 +391,7 @@ var UpstashStore = class extends MastraStorage {
|
|
|
567
391
|
}
|
|
568
392
|
async saveThread({ thread }) {
|
|
569
393
|
try {
|
|
570
|
-
await this.insert({
|
|
394
|
+
await this.operations.insert({
|
|
571
395
|
tableName: TABLE_THREADS,
|
|
572
396
|
record: thread
|
|
573
397
|
});
|
|
@@ -632,20 +456,20 @@ var UpstashStore = class extends MastraStorage {
|
|
|
632
456
|
}
|
|
633
457
|
}
|
|
634
458
|
async deleteThread({ threadId }) {
|
|
635
|
-
const threadKey =
|
|
636
|
-
const threadMessagesKey =
|
|
459
|
+
const threadKey = getKey(TABLE_THREADS, { id: threadId });
|
|
460
|
+
const threadMessagesKey = getThreadMessagesKey(threadId);
|
|
637
461
|
try {
|
|
638
|
-
const messageIds = await this.
|
|
639
|
-
const pipeline = this.
|
|
462
|
+
const messageIds = await this.client.zrange(threadMessagesKey, 0, -1);
|
|
463
|
+
const pipeline = this.client.pipeline();
|
|
640
464
|
pipeline.del(threadKey);
|
|
641
465
|
pipeline.del(threadMessagesKey);
|
|
642
466
|
for (let i = 0; i < messageIds.length; i++) {
|
|
643
467
|
const messageId = messageIds[i];
|
|
644
|
-
const messageKey =
|
|
468
|
+
const messageKey = getMessageKey(threadId, messageId);
|
|
645
469
|
pipeline.del(messageKey);
|
|
646
470
|
}
|
|
647
471
|
await pipeline.exec();
|
|
648
|
-
await this.scanAndDelete(
|
|
472
|
+
await this.operations.scanAndDelete(getMessageKey(threadId, "*"));
|
|
649
473
|
} catch (error) {
|
|
650
474
|
throw new MastraError(
|
|
651
475
|
{
|
|
@@ -682,40 +506,52 @@ var UpstashStore = class extends MastraStorage {
|
|
|
682
506
|
error
|
|
683
507
|
);
|
|
684
508
|
}
|
|
685
|
-
const messagesWithIndex = messages.map((message, index) =>
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
509
|
+
const messagesWithIndex = messages.map((message, index) => {
|
|
510
|
+
if (!message.threadId) {
|
|
511
|
+
throw new Error(
|
|
512
|
+
`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
if (!message.resourceId) {
|
|
516
|
+
throw new Error(
|
|
517
|
+
`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
...message,
|
|
522
|
+
_index: index
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
const threadKey = getKey(TABLE_THREADS, { id: threadId });
|
|
526
|
+
const existingThread = await this.client.get(threadKey);
|
|
691
527
|
try {
|
|
692
528
|
const batchSize = 1e3;
|
|
693
529
|
for (let i = 0; i < messagesWithIndex.length; i += batchSize) {
|
|
694
530
|
const batch = messagesWithIndex.slice(i, i + batchSize);
|
|
695
|
-
const pipeline = this.
|
|
531
|
+
const pipeline = this.client.pipeline();
|
|
696
532
|
for (const message of batch) {
|
|
697
|
-
const key =
|
|
533
|
+
const key = getMessageKey(message.threadId, message.id);
|
|
698
534
|
const createdAtScore = new Date(message.createdAt).getTime();
|
|
699
535
|
const score = message._index !== void 0 ? message._index : createdAtScore;
|
|
700
|
-
const existingKeyPattern =
|
|
701
|
-
const keys = await this.scanKeys(existingKeyPattern);
|
|
536
|
+
const existingKeyPattern = getMessageKey("*", message.id);
|
|
537
|
+
const keys = await this.operations.scanKeys(existingKeyPattern);
|
|
702
538
|
if (keys.length > 0) {
|
|
703
|
-
const pipeline2 = this.
|
|
539
|
+
const pipeline2 = this.client.pipeline();
|
|
704
540
|
keys.forEach((key2) => pipeline2.get(key2));
|
|
705
541
|
const results = await pipeline2.exec();
|
|
706
542
|
const existingMessages = results.filter(
|
|
707
543
|
(msg) => msg !== null
|
|
708
544
|
);
|
|
709
545
|
for (const existingMessage of existingMessages) {
|
|
710
|
-
const existingMessageKey =
|
|
546
|
+
const existingMessageKey = getMessageKey(existingMessage.threadId, existingMessage.id);
|
|
711
547
|
if (existingMessage && existingMessage.threadId !== message.threadId) {
|
|
712
548
|
pipeline.del(existingMessageKey);
|
|
713
|
-
pipeline.zrem(
|
|
549
|
+
pipeline.zrem(getThreadMessagesKey(existingMessage.threadId), existingMessage.id);
|
|
714
550
|
}
|
|
715
551
|
}
|
|
716
552
|
}
|
|
717
553
|
pipeline.set(key, message);
|
|
718
|
-
pipeline.zadd(
|
|
554
|
+
pipeline.zadd(getThreadMessagesKey(message.threadId), {
|
|
719
555
|
score,
|
|
720
556
|
member: message.id
|
|
721
557
|
});
|
|
@@ -725,7 +561,7 @@ var UpstashStore = class extends MastraStorage {
|
|
|
725
561
|
...existingThread,
|
|
726
562
|
updatedAt: /* @__PURE__ */ new Date()
|
|
727
563
|
};
|
|
728
|
-
pipeline.set(threadKey,
|
|
564
|
+
pipeline.set(threadKey, processRecord(TABLE_THREADS, updatedThread).processedRecord);
|
|
729
565
|
}
|
|
730
566
|
await pipeline.exec();
|
|
731
567
|
}
|
|
@@ -754,29 +590,29 @@ var UpstashStore = class extends MastraStorage {
|
|
|
754
590
|
messageIds.add(item.id);
|
|
755
591
|
const itemThreadId = item.threadId || threadId;
|
|
756
592
|
messageIdToThreadIds[item.id] = itemThreadId;
|
|
757
|
-
const itemThreadMessagesKey =
|
|
758
|
-
const rank = await this.
|
|
593
|
+
const itemThreadMessagesKey = getThreadMessagesKey(itemThreadId);
|
|
594
|
+
const rank = await this.client.zrank(itemThreadMessagesKey, item.id);
|
|
759
595
|
if (rank === null) continue;
|
|
760
596
|
if (item.withPreviousMessages) {
|
|
761
597
|
const start = Math.max(0, rank - item.withPreviousMessages);
|
|
762
|
-
const prevIds = rank === 0 ? [] : await this.
|
|
598
|
+
const prevIds = rank === 0 ? [] : await this.client.zrange(itemThreadMessagesKey, start, rank - 1);
|
|
763
599
|
prevIds.forEach((id) => {
|
|
764
600
|
messageIds.add(id);
|
|
765
601
|
messageIdToThreadIds[id] = itemThreadId;
|
|
766
602
|
});
|
|
767
603
|
}
|
|
768
604
|
if (item.withNextMessages) {
|
|
769
|
-
const nextIds = await this.
|
|
605
|
+
const nextIds = await this.client.zrange(itemThreadMessagesKey, rank + 1, rank + item.withNextMessages);
|
|
770
606
|
nextIds.forEach((id) => {
|
|
771
607
|
messageIds.add(id);
|
|
772
608
|
messageIdToThreadIds[id] = itemThreadId;
|
|
773
609
|
});
|
|
774
610
|
}
|
|
775
611
|
}
|
|
776
|
-
const pipeline = this.
|
|
612
|
+
const pipeline = this.client.pipeline();
|
|
777
613
|
Array.from(messageIds).forEach((id) => {
|
|
778
614
|
const tId = messageIdToThreadIds[id] || threadId;
|
|
779
|
-
pipeline.get(
|
|
615
|
+
pipeline.get(getMessageKey(tId, id));
|
|
780
616
|
});
|
|
781
617
|
const results = await pipeline.exec();
|
|
782
618
|
return results.filter((result) => result !== null);
|
|
@@ -788,23 +624,23 @@ var UpstashStore = class extends MastraStorage {
|
|
|
788
624
|
selectBy,
|
|
789
625
|
format
|
|
790
626
|
}) {
|
|
791
|
-
const threadMessagesKey =
|
|
627
|
+
const threadMessagesKey = getThreadMessagesKey(threadId);
|
|
792
628
|
try {
|
|
793
|
-
const allMessageIds = await this.
|
|
794
|
-
const limit =
|
|
629
|
+
const allMessageIds = await this.client.zrange(threadMessagesKey, 0, -1);
|
|
630
|
+
const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
|
|
795
631
|
const messageIds = /* @__PURE__ */ new Set();
|
|
796
632
|
const messageIdToThreadIds = {};
|
|
797
633
|
if (limit === 0 && !selectBy?.include) {
|
|
798
634
|
return [];
|
|
799
635
|
}
|
|
800
636
|
if (limit === Number.MAX_SAFE_INTEGER) {
|
|
801
|
-
const allIds = await this.
|
|
637
|
+
const allIds = await this.client.zrange(threadMessagesKey, 0, -1);
|
|
802
638
|
allIds.forEach((id) => {
|
|
803
639
|
messageIds.add(id);
|
|
804
640
|
messageIdToThreadIds[id] = threadId;
|
|
805
641
|
});
|
|
806
642
|
} else if (limit > 0) {
|
|
807
|
-
const latestIds = await this.
|
|
643
|
+
const latestIds = await this.client.zrange(threadMessagesKey, -limit, -1);
|
|
808
644
|
latestIds.forEach((id) => {
|
|
809
645
|
messageIds.add(id);
|
|
810
646
|
messageIdToThreadIds[id] = threadId;
|
|
@@ -816,9 +652,7 @@ var UpstashStore = class extends MastraStorage {
|
|
|
816
652
|
...(await Promise.all(
|
|
817
653
|
Array.from(messageIds).map(async (id) => {
|
|
818
654
|
const tId = messageIdToThreadIds[id] || threadId;
|
|
819
|
-
const byThreadId = await this.
|
|
820
|
-
this.getMessageKey(tId, id)
|
|
821
|
-
);
|
|
655
|
+
const byThreadId = await this.client.get(getMessageKey(tId, id));
|
|
822
656
|
if (byThreadId) return byThreadId;
|
|
823
657
|
return null;
|
|
824
658
|
})
|
|
@@ -838,10 +672,14 @@ var UpstashStore = class extends MastraStorage {
|
|
|
838
672
|
if (format === "v2") {
|
|
839
673
|
return prepared.map((msg) => ({
|
|
840
674
|
...msg,
|
|
675
|
+
createdAt: new Date(msg.createdAt),
|
|
841
676
|
content: msg.content || { format: 2, parts: [{ type: "text", text: "" }] }
|
|
842
677
|
}));
|
|
843
678
|
}
|
|
844
|
-
return prepared
|
|
679
|
+
return prepared.map((msg) => ({
|
|
680
|
+
...msg,
|
|
681
|
+
createdAt: new Date(msg.createdAt)
|
|
682
|
+
}));
|
|
845
683
|
} catch (error) {
|
|
846
684
|
throw new MastraError(
|
|
847
685
|
{
|
|
@@ -861,12 +699,16 @@ var UpstashStore = class extends MastraStorage {
|
|
|
861
699
|
const { page = 0, perPage = 40, dateRange } = selectBy?.pagination || {};
|
|
862
700
|
const fromDate = dateRange?.start;
|
|
863
701
|
const toDate = dateRange?.end;
|
|
864
|
-
const threadMessagesKey =
|
|
702
|
+
const threadMessagesKey = getThreadMessagesKey(threadId);
|
|
865
703
|
const messages = [];
|
|
866
704
|
try {
|
|
867
705
|
const includedMessages = await this._getIncludedMessages(threadId, selectBy);
|
|
868
706
|
messages.push(...includedMessages);
|
|
869
|
-
const allMessageIds = await this.
|
|
707
|
+
const allMessageIds = await this.client.zrange(
|
|
708
|
+
threadMessagesKey,
|
|
709
|
+
args?.selectBy?.last ? -args.selectBy.last : 0,
|
|
710
|
+
-1
|
|
711
|
+
);
|
|
870
712
|
if (allMessageIds.length === 0) {
|
|
871
713
|
return {
|
|
872
714
|
messages: [],
|
|
@@ -876,8 +718,8 @@ var UpstashStore = class extends MastraStorage {
|
|
|
876
718
|
hasMore: false
|
|
877
719
|
};
|
|
878
720
|
}
|
|
879
|
-
const pipeline = this.
|
|
880
|
-
allMessageIds.forEach((id) => pipeline.get(
|
|
721
|
+
const pipeline = this.client.pipeline();
|
|
722
|
+
allMessageIds.forEach((id) => pipeline.get(getMessageKey(threadId, id)));
|
|
881
723
|
const results = await pipeline.exec();
|
|
882
724
|
let messagesData = results.filter((msg) => msg !== null);
|
|
883
725
|
if (fromDate) {
|
|
@@ -925,206 +767,795 @@ var UpstashStore = class extends MastraStorage {
|
|
|
925
767
|
};
|
|
926
768
|
}
|
|
927
769
|
}
|
|
928
|
-
async
|
|
929
|
-
const { namespace = "workflows", workflowName, runId, snapshot } = params;
|
|
770
|
+
async getResourceById({ resourceId }) {
|
|
930
771
|
try {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
772
|
+
const key = `${TABLE_RESOURCES}:${resourceId}`;
|
|
773
|
+
const data = await this.client.get(key);
|
|
774
|
+
if (!data) {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
return {
|
|
778
|
+
...data,
|
|
779
|
+
createdAt: new Date(data.createdAt),
|
|
780
|
+
updatedAt: new Date(data.updatedAt),
|
|
781
|
+
// Ensure workingMemory is always returned as a string, regardless of automatic parsing
|
|
782
|
+
workingMemory: typeof data.workingMemory === "object" ? JSON.stringify(data.workingMemory) : data.workingMemory,
|
|
783
|
+
metadata: typeof data.metadata === "string" ? JSON.parse(data.metadata) : data.metadata
|
|
784
|
+
};
|
|
785
|
+
} catch (error) {
|
|
786
|
+
this.logger.error("Error getting resource by ID:", error);
|
|
787
|
+
throw error;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
async saveResource({ resource }) {
|
|
791
|
+
try {
|
|
792
|
+
const key = `${TABLE_RESOURCES}:${resource.id}`;
|
|
793
|
+
const serializedResource = {
|
|
794
|
+
...resource,
|
|
795
|
+
metadata: JSON.stringify(resource.metadata),
|
|
796
|
+
createdAt: resource.createdAt.toISOString(),
|
|
797
|
+
updatedAt: resource.updatedAt.toISOString()
|
|
798
|
+
};
|
|
799
|
+
await this.client.set(key, serializedResource);
|
|
800
|
+
return resource;
|
|
801
|
+
} catch (error) {
|
|
802
|
+
this.logger.error("Error saving resource:", error);
|
|
803
|
+
throw error;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
async updateResource({
|
|
807
|
+
resourceId,
|
|
808
|
+
workingMemory,
|
|
809
|
+
metadata
|
|
810
|
+
}) {
|
|
811
|
+
try {
|
|
812
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
813
|
+
if (!existingResource) {
|
|
814
|
+
const newResource = {
|
|
815
|
+
id: resourceId,
|
|
816
|
+
workingMemory,
|
|
817
|
+
metadata: metadata || {},
|
|
938
818
|
createdAt: /* @__PURE__ */ new Date(),
|
|
939
819
|
updatedAt: /* @__PURE__ */ new Date()
|
|
820
|
+
};
|
|
821
|
+
return this.saveResource({ resource: newResource });
|
|
822
|
+
}
|
|
823
|
+
const updatedResource = {
|
|
824
|
+
...existingResource,
|
|
825
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
826
|
+
metadata: {
|
|
827
|
+
...existingResource.metadata,
|
|
828
|
+
...metadata
|
|
829
|
+
},
|
|
830
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
831
|
+
};
|
|
832
|
+
await this.saveResource({ resource: updatedResource });
|
|
833
|
+
return updatedResource;
|
|
834
|
+
} catch (error) {
|
|
835
|
+
this.logger.error("Error updating resource:", error);
|
|
836
|
+
throw error;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
async updateMessages(args) {
|
|
840
|
+
const { messages } = args;
|
|
841
|
+
if (messages.length === 0) {
|
|
842
|
+
return [];
|
|
843
|
+
}
|
|
844
|
+
try {
|
|
845
|
+
const messageIds = messages.map((m) => m.id);
|
|
846
|
+
const existingMessages = [];
|
|
847
|
+
const messageIdToKey = {};
|
|
848
|
+
for (const messageId of messageIds) {
|
|
849
|
+
const pattern = getMessageKey("*", messageId);
|
|
850
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
851
|
+
for (const key of keys) {
|
|
852
|
+
const message = await this.client.get(key);
|
|
853
|
+
if (message && message.id === messageId) {
|
|
854
|
+
existingMessages.push(message);
|
|
855
|
+
messageIdToKey[messageId] = key;
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
940
858
|
}
|
|
941
|
-
}
|
|
859
|
+
}
|
|
860
|
+
if (existingMessages.length === 0) {
|
|
861
|
+
return [];
|
|
862
|
+
}
|
|
863
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
864
|
+
const pipeline = this.client.pipeline();
|
|
865
|
+
for (const existingMessage of existingMessages) {
|
|
866
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
867
|
+
if (!updatePayload) continue;
|
|
868
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
869
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
870
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
871
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
872
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
873
|
+
}
|
|
874
|
+
const updatedMessage = { ...existingMessage };
|
|
875
|
+
if (fieldsToUpdate.content) {
|
|
876
|
+
const existingContent = existingMessage.content;
|
|
877
|
+
const newContent = {
|
|
878
|
+
...existingContent,
|
|
879
|
+
...fieldsToUpdate.content,
|
|
880
|
+
// Deep merge metadata if it exists on both
|
|
881
|
+
...existingContent?.metadata && fieldsToUpdate.content.metadata ? {
|
|
882
|
+
metadata: {
|
|
883
|
+
...existingContent.metadata,
|
|
884
|
+
...fieldsToUpdate.content.metadata
|
|
885
|
+
}
|
|
886
|
+
} : {}
|
|
887
|
+
};
|
|
888
|
+
updatedMessage.content = newContent;
|
|
889
|
+
}
|
|
890
|
+
for (const key2 in fieldsToUpdate) {
|
|
891
|
+
if (Object.prototype.hasOwnProperty.call(fieldsToUpdate, key2) && key2 !== "content") {
|
|
892
|
+
updatedMessage[key2] = fieldsToUpdate[key2];
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
const key = messageIdToKey[id];
|
|
896
|
+
if (key) {
|
|
897
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
898
|
+
const oldThreadMessagesKey = getThreadMessagesKey(existingMessage.threadId);
|
|
899
|
+
pipeline.zrem(oldThreadMessagesKey, id);
|
|
900
|
+
pipeline.del(key);
|
|
901
|
+
const newKey = getMessageKey(updatePayload.threadId, id);
|
|
902
|
+
pipeline.set(newKey, updatedMessage);
|
|
903
|
+
const newThreadMessagesKey = getThreadMessagesKey(updatePayload.threadId);
|
|
904
|
+
const score = updatedMessage._index !== void 0 ? updatedMessage._index : new Date(updatedMessage.createdAt).getTime();
|
|
905
|
+
pipeline.zadd(newThreadMessagesKey, { score, member: id });
|
|
906
|
+
} else {
|
|
907
|
+
pipeline.set(key, updatedMessage);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
const now = /* @__PURE__ */ new Date();
|
|
912
|
+
for (const threadId of threadIdsToUpdate) {
|
|
913
|
+
if (threadId) {
|
|
914
|
+
const threadKey = getKey(TABLE_THREADS, { id: threadId });
|
|
915
|
+
const existingThread = await this.client.get(threadKey);
|
|
916
|
+
if (existingThread) {
|
|
917
|
+
const updatedThread = {
|
|
918
|
+
...existingThread,
|
|
919
|
+
updatedAt: now
|
|
920
|
+
};
|
|
921
|
+
pipeline.set(threadKey, processRecord(TABLE_THREADS, updatedThread).processedRecord);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
await pipeline.exec();
|
|
926
|
+
const updatedMessages = [];
|
|
927
|
+
for (const messageId of messageIds) {
|
|
928
|
+
const key = messageIdToKey[messageId];
|
|
929
|
+
if (key) {
|
|
930
|
+
const updatedMessage = await this.client.get(key);
|
|
931
|
+
if (updatedMessage) {
|
|
932
|
+
const v2e = updatedMessage;
|
|
933
|
+
updatedMessages.push(v2e);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return updatedMessages;
|
|
942
938
|
} catch (error) {
|
|
943
939
|
throw new MastraError(
|
|
944
940
|
{
|
|
945
|
-
id: "
|
|
941
|
+
id: "STORAGE_UPSTASH_STORAGE_UPDATE_MESSAGES_FAILED",
|
|
946
942
|
domain: ErrorDomain.STORAGE,
|
|
947
943
|
category: ErrorCategory.THIRD_PARTY,
|
|
948
944
|
details: {
|
|
949
|
-
|
|
950
|
-
workflowName,
|
|
951
|
-
runId
|
|
945
|
+
messageIds: messages.map((m) => m.id).join(",")
|
|
952
946
|
}
|
|
953
947
|
},
|
|
954
948
|
error
|
|
955
949
|
);
|
|
956
950
|
}
|
|
957
951
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
952
|
+
};
|
|
953
|
+
var StoreOperationsUpstash = class extends StoreOperations {
|
|
954
|
+
client;
|
|
955
|
+
constructor({ client }) {
|
|
956
|
+
super();
|
|
957
|
+
this.client = client;
|
|
958
|
+
}
|
|
959
|
+
async createTable({
|
|
960
|
+
tableName: _tableName,
|
|
961
|
+
schema: _schema
|
|
962
|
+
}) {
|
|
963
|
+
}
|
|
964
|
+
async alterTable({
|
|
965
|
+
tableName: _tableName,
|
|
966
|
+
schema: _schema,
|
|
967
|
+
ifNotExists: _ifNotExists
|
|
968
|
+
}) {
|
|
969
|
+
}
|
|
970
|
+
async clearTable({ tableName }) {
|
|
971
|
+
const pattern = `${tableName}:*`;
|
|
965
972
|
try {
|
|
966
|
-
|
|
967
|
-
if (!data) return null;
|
|
968
|
-
return data.snapshot;
|
|
973
|
+
await this.scanAndDelete(pattern);
|
|
969
974
|
} catch (error) {
|
|
970
975
|
throw new MastraError(
|
|
971
976
|
{
|
|
972
|
-
id: "
|
|
977
|
+
id: "STORAGE_UPSTASH_STORAGE_CLEAR_TABLE_FAILED",
|
|
973
978
|
domain: ErrorDomain.STORAGE,
|
|
974
979
|
category: ErrorCategory.THIRD_PARTY,
|
|
975
980
|
details: {
|
|
976
|
-
|
|
977
|
-
workflowName,
|
|
978
|
-
runId
|
|
981
|
+
tableName
|
|
979
982
|
}
|
|
980
983
|
},
|
|
981
984
|
error
|
|
982
985
|
);
|
|
983
986
|
}
|
|
984
987
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
async getEvals(options) {
|
|
988
|
+
async dropTable({ tableName }) {
|
|
989
|
+
return this.clearTable({ tableName });
|
|
990
|
+
}
|
|
991
|
+
async insert({ tableName, record }) {
|
|
992
|
+
const { key, processedRecord } = processRecord(tableName, record);
|
|
991
993
|
try {
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
994
|
+
await this.client.set(key, processedRecord);
|
|
995
|
+
} catch (error) {
|
|
996
|
+
throw new MastraError(
|
|
997
|
+
{
|
|
998
|
+
id: "STORAGE_UPSTASH_STORAGE_INSERT_FAILED",
|
|
999
|
+
domain: ErrorDomain.STORAGE,
|
|
1000
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1001
|
+
details: {
|
|
1002
|
+
tableName
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
error
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
async batchInsert(input) {
|
|
1010
|
+
const { tableName, records } = input;
|
|
1011
|
+
if (!records.length) return;
|
|
1012
|
+
const batchSize = 1e3;
|
|
1013
|
+
try {
|
|
1014
|
+
for (let i = 0; i < records.length; i += batchSize) {
|
|
1015
|
+
const batch = records.slice(i, i + batchSize);
|
|
1016
|
+
const pipeline = this.client.pipeline();
|
|
1017
|
+
for (const record of batch) {
|
|
1018
|
+
const { key, processedRecord } = processRecord(tableName, record);
|
|
1019
|
+
pipeline.set(key, processedRecord);
|
|
1020
|
+
}
|
|
1021
|
+
await pipeline.exec();
|
|
1022
|
+
}
|
|
1023
|
+
} catch (error) {
|
|
1024
|
+
throw new MastraError(
|
|
1025
|
+
{
|
|
1026
|
+
id: "STORAGE_UPSTASH_STORAGE_BATCH_INSERT_FAILED",
|
|
1027
|
+
domain: ErrorDomain.STORAGE,
|
|
1028
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1029
|
+
details: {
|
|
1030
|
+
tableName
|
|
1031
|
+
}
|
|
1032
|
+
},
|
|
1033
|
+
error
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
async load({ tableName, keys }) {
|
|
1038
|
+
const key = getKey(tableName, keys);
|
|
1039
|
+
try {
|
|
1040
|
+
const data = await this.client.get(key);
|
|
1041
|
+
return data || null;
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
throw new MastraError(
|
|
1044
|
+
{
|
|
1045
|
+
id: "STORAGE_UPSTASH_STORAGE_LOAD_FAILED",
|
|
1046
|
+
domain: ErrorDomain.STORAGE,
|
|
1047
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1048
|
+
details: {
|
|
1049
|
+
tableName
|
|
1050
|
+
}
|
|
1051
|
+
},
|
|
1052
|
+
error
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
async hasColumn(_tableName, _column) {
|
|
1057
|
+
return true;
|
|
1058
|
+
}
|
|
1059
|
+
async scanKeys(pattern, batchSize = 1e4) {
|
|
1060
|
+
let cursor = "0";
|
|
1061
|
+
let keys = [];
|
|
1062
|
+
do {
|
|
1063
|
+
const [nextCursor, batch] = await this.client.scan(cursor, {
|
|
1064
|
+
match: pattern,
|
|
1065
|
+
count: batchSize
|
|
1066
|
+
});
|
|
1067
|
+
keys.push(...batch);
|
|
1068
|
+
cursor = nextCursor;
|
|
1069
|
+
} while (cursor !== "0");
|
|
1070
|
+
return keys;
|
|
1071
|
+
}
|
|
1072
|
+
async scanAndDelete(pattern, batchSize = 1e4) {
|
|
1073
|
+
let cursor = "0";
|
|
1074
|
+
let totalDeleted = 0;
|
|
1075
|
+
do {
|
|
1076
|
+
const [nextCursor, keys] = await this.client.scan(cursor, {
|
|
1077
|
+
match: pattern,
|
|
1078
|
+
count: batchSize
|
|
1079
|
+
});
|
|
1080
|
+
if (keys.length > 0) {
|
|
1081
|
+
await this.client.del(...keys);
|
|
1082
|
+
totalDeleted += keys.length;
|
|
1083
|
+
}
|
|
1084
|
+
cursor = nextCursor;
|
|
1085
|
+
} while (cursor !== "0");
|
|
1086
|
+
return totalDeleted;
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
function transformScoreRow(row) {
|
|
1090
|
+
const parseField = (v) => {
|
|
1091
|
+
if (typeof v === "string") {
|
|
1092
|
+
try {
|
|
1093
|
+
return JSON.parse(v);
|
|
1094
|
+
} catch {
|
|
1095
|
+
return v;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
return v;
|
|
1099
|
+
};
|
|
1100
|
+
return {
|
|
1101
|
+
...row,
|
|
1102
|
+
scorer: parseField(row.scorer),
|
|
1103
|
+
extractStepResult: parseField(row.extractStepResult),
|
|
1104
|
+
analyzeStepResult: parseField(row.analyzeStepResult),
|
|
1105
|
+
metadata: parseField(row.metadata),
|
|
1106
|
+
input: parseField(row.input),
|
|
1107
|
+
output: parseField(row.output),
|
|
1108
|
+
additionalContext: parseField(row.additionalContext),
|
|
1109
|
+
runtimeContext: parseField(row.runtimeContext),
|
|
1110
|
+
entity: parseField(row.entity),
|
|
1111
|
+
createdAt: row.createdAt,
|
|
1112
|
+
updatedAt: row.updatedAt
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
var ScoresUpstash = class extends ScoresStorage {
|
|
1116
|
+
client;
|
|
1117
|
+
operations;
|
|
1118
|
+
constructor({ client, operations }) {
|
|
1119
|
+
super();
|
|
1120
|
+
this.client = client;
|
|
1121
|
+
this.operations = operations;
|
|
1122
|
+
}
|
|
1123
|
+
async getScoreById({ id }) {
|
|
1124
|
+
try {
|
|
1125
|
+
const data = await this.operations.load({
|
|
1126
|
+
tableName: TABLE_SCORERS,
|
|
1127
|
+
keys: { id }
|
|
1128
|
+
});
|
|
1129
|
+
if (!data) return null;
|
|
1130
|
+
return transformScoreRow(data);
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
throw new MastraError(
|
|
1133
|
+
{
|
|
1134
|
+
id: "STORAGE_UPSTASH_STORAGE_GET_SCORE_BY_ID_FAILED",
|
|
1135
|
+
domain: ErrorDomain.STORAGE,
|
|
1136
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1137
|
+
details: { id }
|
|
1138
|
+
},
|
|
1139
|
+
error
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
async getScoresByScorerId({
|
|
1144
|
+
scorerId,
|
|
1145
|
+
pagination = { page: 0, perPage: 20 }
|
|
1146
|
+
}) {
|
|
1147
|
+
const pattern = `${TABLE_SCORERS}:*`;
|
|
1148
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
1149
|
+
if (keys.length === 0) {
|
|
1150
|
+
return {
|
|
1151
|
+
scores: [],
|
|
1152
|
+
pagination: { total: 0, page: pagination.page, perPage: pagination.perPage, hasMore: false }
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
const pipeline = this.client.pipeline();
|
|
1156
|
+
keys.forEach((key) => pipeline.get(key));
|
|
1157
|
+
const results = await pipeline.exec();
|
|
1158
|
+
const filtered = results.map((row) => row).filter((row) => !!row && typeof row === "object" && row.scorerId === scorerId);
|
|
1159
|
+
const total = filtered.length;
|
|
1160
|
+
const { page, perPage } = pagination;
|
|
1161
|
+
const start = page * perPage;
|
|
1162
|
+
const end = start + perPage;
|
|
1163
|
+
const paged = filtered.slice(start, end);
|
|
1164
|
+
const scores = paged.map((row) => transformScoreRow(row));
|
|
1165
|
+
return {
|
|
1166
|
+
scores,
|
|
1167
|
+
pagination: {
|
|
1168
|
+
total,
|
|
1169
|
+
page,
|
|
1170
|
+
perPage,
|
|
1171
|
+
hasMore: end < total
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
async saveScore(score) {
|
|
1176
|
+
const { key, processedRecord } = processRecord(TABLE_SCORERS, score);
|
|
1177
|
+
try {
|
|
1178
|
+
await this.client.set(key, processedRecord);
|
|
1179
|
+
return { score };
|
|
1180
|
+
} catch (error) {
|
|
1181
|
+
throw new MastraError(
|
|
1182
|
+
{
|
|
1183
|
+
id: "STORAGE_UPSTASH_STORAGE_SAVE_SCORE_FAILED",
|
|
1184
|
+
domain: ErrorDomain.STORAGE,
|
|
1185
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1186
|
+
details: { id: score.id }
|
|
1187
|
+
},
|
|
1188
|
+
error
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
async getScoresByRunId({
|
|
1193
|
+
runId,
|
|
1194
|
+
pagination = { page: 0, perPage: 20 }
|
|
1195
|
+
}) {
|
|
1196
|
+
const pattern = `${TABLE_SCORERS}:*`;
|
|
1197
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
1198
|
+
if (keys.length === 0) {
|
|
1199
|
+
return {
|
|
1200
|
+
scores: [],
|
|
1201
|
+
pagination: { total: 0, page: pagination.page, perPage: pagination.perPage, hasMore: false }
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
const pipeline = this.client.pipeline();
|
|
1205
|
+
keys.forEach((key) => pipeline.get(key));
|
|
1206
|
+
const results = await pipeline.exec();
|
|
1207
|
+
const filtered = results.map((row) => row).filter((row) => !!row && typeof row === "object" && row.runId === runId);
|
|
1208
|
+
const total = filtered.length;
|
|
1209
|
+
const { page, perPage } = pagination;
|
|
1210
|
+
const start = page * perPage;
|
|
1211
|
+
const end = start + perPage;
|
|
1212
|
+
const paged = filtered.slice(start, end);
|
|
1213
|
+
const scores = paged.map((row) => transformScoreRow(row));
|
|
1214
|
+
return {
|
|
1215
|
+
scores,
|
|
1216
|
+
pagination: {
|
|
1217
|
+
total,
|
|
1218
|
+
page,
|
|
1219
|
+
perPage,
|
|
1220
|
+
hasMore: end < total
|
|
1221
|
+
}
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
async getScoresByEntityId({
|
|
1225
|
+
entityId,
|
|
1226
|
+
entityType,
|
|
1227
|
+
pagination = { page: 0, perPage: 20 }
|
|
1228
|
+
}) {
|
|
1229
|
+
const pattern = `${TABLE_SCORERS}:*`;
|
|
1230
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
1231
|
+
if (keys.length === 0) {
|
|
1232
|
+
return {
|
|
1233
|
+
scores: [],
|
|
1234
|
+
pagination: { total: 0, page: pagination.page, perPage: pagination.perPage, hasMore: false }
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
const pipeline = this.client.pipeline();
|
|
1238
|
+
keys.forEach((key) => pipeline.get(key));
|
|
1239
|
+
const results = await pipeline.exec();
|
|
1240
|
+
const filtered = results.map((row) => row).filter((row) => {
|
|
1241
|
+
if (!row || typeof row !== "object") return false;
|
|
1242
|
+
if (row.entityId !== entityId) return false;
|
|
1243
|
+
if (entityType && row.entityType !== entityType) return false;
|
|
1244
|
+
return true;
|
|
1245
|
+
});
|
|
1246
|
+
const total = filtered.length;
|
|
1247
|
+
const { page, perPage } = pagination;
|
|
1248
|
+
const start = page * perPage;
|
|
1249
|
+
const end = start + perPage;
|
|
1250
|
+
const paged = filtered.slice(start, end);
|
|
1251
|
+
const scores = paged.map((row) => transformScoreRow(row));
|
|
1252
|
+
return {
|
|
1253
|
+
scores,
|
|
1254
|
+
pagination: {
|
|
1255
|
+
total,
|
|
1256
|
+
page,
|
|
1257
|
+
perPage,
|
|
1258
|
+
hasMore: end < total
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
};
|
|
1263
|
+
var TracesUpstash = class extends TracesStorage {
|
|
1264
|
+
client;
|
|
1265
|
+
operations;
|
|
1266
|
+
constructor({ client, operations }) {
|
|
1267
|
+
super();
|
|
1268
|
+
this.client = client;
|
|
1269
|
+
this.operations = operations;
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* @deprecated use getTracesPaginated instead
|
|
1273
|
+
*/
|
|
1274
|
+
async getTraces(args) {
|
|
1275
|
+
if (args.fromDate || args.toDate) {
|
|
1276
|
+
args.dateRange = {
|
|
1277
|
+
start: args.fromDate,
|
|
1278
|
+
end: args.toDate
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
try {
|
|
1282
|
+
const { traces } = await this.getTracesPaginated(args);
|
|
1283
|
+
return traces;
|
|
1284
|
+
} catch (error) {
|
|
1285
|
+
throw new MastraError(
|
|
1286
|
+
{
|
|
1287
|
+
id: "STORAGE_UPSTASH_STORAGE_GET_TRACES_FAILED",
|
|
1288
|
+
domain: ErrorDomain.STORAGE,
|
|
1289
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1290
|
+
},
|
|
1291
|
+
error
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
async getTracesPaginated(args) {
|
|
1296
|
+
const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
|
|
1297
|
+
const fromDate = dateRange?.start;
|
|
1298
|
+
const toDate = dateRange?.end;
|
|
1299
|
+
try {
|
|
1300
|
+
const pattern = `${TABLE_TRACES}:*`;
|
|
1301
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
1302
|
+
if (keys.length === 0) {
|
|
1303
|
+
return {
|
|
1304
|
+
traces: [],
|
|
1305
|
+
total: 0,
|
|
1001
1306
|
page,
|
|
1002
|
-
perPage,
|
|
1307
|
+
perPage: perPage || 100,
|
|
1003
1308
|
hasMore: false
|
|
1004
1309
|
};
|
|
1005
1310
|
}
|
|
1006
|
-
const pipeline = this.
|
|
1311
|
+
const pipeline = this.client.pipeline();
|
|
1007
1312
|
keys.forEach((key) => pipeline.get(key));
|
|
1008
1313
|
const results = await pipeline.exec();
|
|
1009
|
-
let
|
|
1010
|
-
|
|
1011
|
-
|
|
1314
|
+
let filteredTraces = results.filter(
|
|
1315
|
+
(record) => record !== null && typeof record === "object"
|
|
1316
|
+
);
|
|
1317
|
+
if (name) {
|
|
1318
|
+
filteredTraces = filteredTraces.filter((record) => record.name?.toLowerCase().startsWith(name.toLowerCase()));
|
|
1012
1319
|
}
|
|
1013
|
-
if (
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
} catch {
|
|
1023
|
-
return false;
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
} else if (type === "live") {
|
|
1027
|
-
filteredEvals = filteredEvals.filter((record) => {
|
|
1028
|
-
if (!record.test_info) return true;
|
|
1029
|
-
try {
|
|
1030
|
-
if (typeof record.test_info === "string") {
|
|
1031
|
-
const parsedTestInfo = JSON.parse(record.test_info);
|
|
1032
|
-
return !(parsedTestInfo && typeof parsedTestInfo === "object" && "testPath" in parsedTestInfo);
|
|
1033
|
-
}
|
|
1034
|
-
return !(typeof record.test_info === "object" && "testPath" in record.test_info);
|
|
1035
|
-
} catch {
|
|
1036
|
-
return true;
|
|
1037
|
-
}
|
|
1320
|
+
if (scope) {
|
|
1321
|
+
filteredTraces = filteredTraces.filter((record) => record.scope === scope);
|
|
1322
|
+
}
|
|
1323
|
+
if (attributes) {
|
|
1324
|
+
filteredTraces = filteredTraces.filter((record) => {
|
|
1325
|
+
const recordAttributes = record.attributes;
|
|
1326
|
+
if (!recordAttributes) return false;
|
|
1327
|
+
const parsedAttributes = typeof recordAttributes === "string" ? JSON.parse(recordAttributes) : recordAttributes;
|
|
1328
|
+
return Object.entries(attributes).every(([key, value]) => parsedAttributes[key] === value);
|
|
1038
1329
|
});
|
|
1039
1330
|
}
|
|
1331
|
+
if (filters) {
|
|
1332
|
+
filteredTraces = filteredTraces.filter(
|
|
1333
|
+
(record) => Object.entries(filters).every(([key, value]) => record[key] === value)
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1040
1336
|
if (fromDate) {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
});
|
|
1337
|
+
filteredTraces = filteredTraces.filter(
|
|
1338
|
+
(record) => new Date(record.createdAt).getTime() >= new Date(fromDate).getTime()
|
|
1339
|
+
);
|
|
1045
1340
|
}
|
|
1046
1341
|
if (toDate) {
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
});
|
|
1342
|
+
filteredTraces = filteredTraces.filter(
|
|
1343
|
+
(record) => new Date(record.createdAt).getTime() <= new Date(toDate).getTime()
|
|
1344
|
+
);
|
|
1051
1345
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1346
|
+
filteredTraces.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
1347
|
+
const transformedTraces = filteredTraces.map((record) => ({
|
|
1348
|
+
id: record.id,
|
|
1349
|
+
parentSpanId: record.parentSpanId,
|
|
1350
|
+
traceId: record.traceId,
|
|
1351
|
+
name: record.name,
|
|
1352
|
+
scope: record.scope,
|
|
1353
|
+
kind: record.kind,
|
|
1354
|
+
status: parseJSON(record.status),
|
|
1355
|
+
events: parseJSON(record.events),
|
|
1356
|
+
links: parseJSON(record.links),
|
|
1357
|
+
attributes: parseJSON(record.attributes),
|
|
1358
|
+
startTime: record.startTime,
|
|
1359
|
+
endTime: record.endTime,
|
|
1360
|
+
other: parseJSON(record.other),
|
|
1361
|
+
createdAt: ensureDate(record.createdAt)
|
|
1362
|
+
}));
|
|
1363
|
+
const total = transformedTraces.length;
|
|
1364
|
+
const resolvedPerPage = perPage || 100;
|
|
1365
|
+
const start = page * resolvedPerPage;
|
|
1366
|
+
const end = start + resolvedPerPage;
|
|
1367
|
+
const paginatedTraces = transformedTraces.slice(start, end);
|
|
1061
1368
|
const hasMore = end < total;
|
|
1062
|
-
const evals = paginatedEvals.map((record) => this.transformEvalRecord(record));
|
|
1063
1369
|
return {
|
|
1064
|
-
|
|
1370
|
+
traces: paginatedTraces,
|
|
1065
1371
|
total,
|
|
1066
1372
|
page,
|
|
1067
|
-
perPage,
|
|
1373
|
+
perPage: resolvedPerPage,
|
|
1068
1374
|
hasMore
|
|
1069
1375
|
};
|
|
1070
1376
|
} catch (error) {
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1377
|
+
const mastraError = new MastraError(
|
|
1378
|
+
{
|
|
1379
|
+
id: "STORAGE_UPSTASH_STORAGE_GET_TRACES_PAGINATED_FAILED",
|
|
1380
|
+
domain: ErrorDomain.STORAGE,
|
|
1381
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1382
|
+
details: {
|
|
1383
|
+
name: args.name || "",
|
|
1384
|
+
scope: args.scope || ""
|
|
1385
|
+
}
|
|
1386
|
+
},
|
|
1387
|
+
error
|
|
1388
|
+
);
|
|
1389
|
+
this.logger?.trackException(mastraError);
|
|
1390
|
+
this.logger.error(mastraError.toString());
|
|
1391
|
+
return {
|
|
1392
|
+
traces: [],
|
|
1393
|
+
total: 0,
|
|
1394
|
+
page,
|
|
1395
|
+
perPage: perPage || 100,
|
|
1396
|
+
hasMore: false
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
async batchTraceInsert(args) {
|
|
1401
|
+
return this.operations.batchInsert({
|
|
1402
|
+
tableName: TABLE_TRACES,
|
|
1403
|
+
records: args.records
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
function parseWorkflowRun(row) {
|
|
1408
|
+
let parsedSnapshot = row.snapshot;
|
|
1409
|
+
if (typeof parsedSnapshot === "string") {
|
|
1410
|
+
try {
|
|
1411
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1412
|
+
} catch (e) {
|
|
1413
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return {
|
|
1417
|
+
workflowName: row.workflow_name,
|
|
1418
|
+
runId: row.run_id,
|
|
1419
|
+
snapshot: parsedSnapshot,
|
|
1420
|
+
createdAt: ensureDate(row.createdAt),
|
|
1421
|
+
updatedAt: ensureDate(row.updatedAt),
|
|
1422
|
+
resourceId: row.resourceId
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
var WorkflowsUpstash = class extends WorkflowsStorage {
|
|
1426
|
+
client;
|
|
1427
|
+
operations;
|
|
1428
|
+
constructor({ client, operations }) {
|
|
1429
|
+
super();
|
|
1430
|
+
this.client = client;
|
|
1431
|
+
this.operations = operations;
|
|
1432
|
+
}
|
|
1433
|
+
async persistWorkflowSnapshot(params) {
|
|
1434
|
+
const { namespace = "workflows", workflowName, runId, snapshot } = params;
|
|
1435
|
+
try {
|
|
1436
|
+
await this.operations.insert({
|
|
1437
|
+
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
1438
|
+
record: {
|
|
1439
|
+
namespace,
|
|
1440
|
+
workflow_name: workflowName,
|
|
1441
|
+
run_id: runId,
|
|
1442
|
+
snapshot,
|
|
1443
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1444
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
} catch (error) {
|
|
1448
|
+
throw new MastraError(
|
|
1449
|
+
{
|
|
1450
|
+
id: "STORAGE_UPSTASH_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
1451
|
+
domain: ErrorDomain.STORAGE,
|
|
1452
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1453
|
+
details: {
|
|
1454
|
+
namespace,
|
|
1455
|
+
workflowName,
|
|
1456
|
+
runId
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
error
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
async loadWorkflowSnapshot(params) {
|
|
1464
|
+
const { namespace = "workflows", workflowName, runId } = params;
|
|
1465
|
+
const key = getKey(TABLE_WORKFLOW_SNAPSHOT, {
|
|
1466
|
+
namespace,
|
|
1467
|
+
workflow_name: workflowName,
|
|
1468
|
+
run_id: runId
|
|
1469
|
+
});
|
|
1470
|
+
try {
|
|
1471
|
+
const data = await this.client.get(key);
|
|
1472
|
+
if (!data) return null;
|
|
1473
|
+
return data.snapshot;
|
|
1474
|
+
} catch (error) {
|
|
1475
|
+
throw new MastraError(
|
|
1073
1476
|
{
|
|
1074
|
-
id: "
|
|
1477
|
+
id: "STORAGE_UPSTASH_STORAGE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
1075
1478
|
domain: ErrorDomain.STORAGE,
|
|
1076
1479
|
category: ErrorCategory.THIRD_PARTY,
|
|
1077
1480
|
details: {
|
|
1078
|
-
|
|
1079
|
-
|
|
1481
|
+
namespace,
|
|
1482
|
+
workflowName,
|
|
1483
|
+
runId
|
|
1484
|
+
}
|
|
1485
|
+
},
|
|
1486
|
+
error
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
async getWorkflowRunById({
|
|
1491
|
+
runId,
|
|
1492
|
+
workflowName
|
|
1493
|
+
}) {
|
|
1494
|
+
try {
|
|
1495
|
+
const key = getKey(TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows", workflow_name: workflowName, run_id: runId }) + "*";
|
|
1496
|
+
const keys = await this.operations.scanKeys(key);
|
|
1497
|
+
const workflows = await Promise.all(
|
|
1498
|
+
keys.map(async (key2) => {
|
|
1499
|
+
const data2 = await this.client.get(key2);
|
|
1500
|
+
return data2;
|
|
1501
|
+
})
|
|
1502
|
+
);
|
|
1503
|
+
const data = workflows.find((w) => w?.run_id === runId && w?.workflow_name === workflowName);
|
|
1504
|
+
if (!data) return null;
|
|
1505
|
+
return parseWorkflowRun(data);
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
throw new MastraError(
|
|
1508
|
+
{
|
|
1509
|
+
id: "STORAGE_UPSTASH_STORAGE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
1510
|
+
domain: ErrorDomain.STORAGE,
|
|
1511
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1512
|
+
details: {
|
|
1513
|
+
namespace: "workflows",
|
|
1514
|
+
runId,
|
|
1515
|
+
workflowName: workflowName || ""
|
|
1080
1516
|
}
|
|
1081
1517
|
},
|
|
1082
1518
|
error
|
|
1083
1519
|
);
|
|
1084
|
-
this.logger.error(mastraError.toString());
|
|
1085
|
-
this.logger?.trackException(mastraError);
|
|
1086
|
-
return {
|
|
1087
|
-
evals: [],
|
|
1088
|
-
total: 0,
|
|
1089
|
-
page,
|
|
1090
|
-
perPage,
|
|
1091
|
-
hasMore: false
|
|
1092
|
-
};
|
|
1093
1520
|
}
|
|
1094
1521
|
}
|
|
1095
1522
|
async getWorkflowRuns({
|
|
1096
|
-
namespace,
|
|
1097
1523
|
workflowName,
|
|
1098
1524
|
fromDate,
|
|
1099
1525
|
toDate,
|
|
1100
1526
|
limit,
|
|
1101
1527
|
offset,
|
|
1102
1528
|
resourceId
|
|
1103
|
-
}
|
|
1529
|
+
}) {
|
|
1104
1530
|
try {
|
|
1105
|
-
let pattern =
|
|
1531
|
+
let pattern = getKey(TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows" }) + ":*";
|
|
1106
1532
|
if (workflowName && resourceId) {
|
|
1107
|
-
pattern =
|
|
1108
|
-
namespace,
|
|
1533
|
+
pattern = getKey(TABLE_WORKFLOW_SNAPSHOT, {
|
|
1534
|
+
namespace: "workflows",
|
|
1109
1535
|
workflow_name: workflowName,
|
|
1110
1536
|
run_id: "*",
|
|
1111
1537
|
resourceId
|
|
1112
1538
|
});
|
|
1113
1539
|
} else if (workflowName) {
|
|
1114
|
-
pattern =
|
|
1540
|
+
pattern = getKey(TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows", workflow_name: workflowName }) + ":*";
|
|
1115
1541
|
} else if (resourceId) {
|
|
1116
|
-
pattern =
|
|
1542
|
+
pattern = getKey(TABLE_WORKFLOW_SNAPSHOT, {
|
|
1543
|
+
namespace: "workflows",
|
|
1544
|
+
workflow_name: "*",
|
|
1545
|
+
run_id: "*",
|
|
1546
|
+
resourceId
|
|
1547
|
+
});
|
|
1117
1548
|
}
|
|
1118
|
-
const keys = await this.scanKeys(pattern);
|
|
1549
|
+
const keys = await this.operations.scanKeys(pattern);
|
|
1119
1550
|
if (keys.length === 0) {
|
|
1120
1551
|
return { runs: [], total: 0 };
|
|
1121
1552
|
}
|
|
1122
|
-
const pipeline = this.
|
|
1553
|
+
const pipeline = this.client.pipeline();
|
|
1123
1554
|
keys.forEach((key) => pipeline.get(key));
|
|
1124
1555
|
const results = await pipeline.exec();
|
|
1125
1556
|
let runs = results.map((result) => result).filter(
|
|
1126
1557
|
(record) => record !== null && record !== void 0 && typeof record === "object" && "workflow_name" in record
|
|
1127
|
-
).filter((record) => !workflowName || record.workflow_name === workflowName).map((w) =>
|
|
1558
|
+
).filter((record) => !workflowName || record.workflow_name === workflowName).map((w) => parseWorkflowRun(w)).filter((w) => {
|
|
1128
1559
|
if (fromDate && w.createdAt < fromDate) return false;
|
|
1129
1560
|
if (toDate && w.createdAt > toDate) return false;
|
|
1130
1561
|
return true;
|
|
@@ -1141,7 +1572,7 @@ var UpstashStore = class extends MastraStorage {
|
|
|
1141
1572
|
domain: ErrorDomain.STORAGE,
|
|
1142
1573
|
category: ErrorCategory.THIRD_PARTY,
|
|
1143
1574
|
details: {
|
|
1144
|
-
namespace,
|
|
1575
|
+
namespace: "workflows",
|
|
1145
1576
|
workflowName: workflowName || "",
|
|
1146
1577
|
resourceId: resourceId || ""
|
|
1147
1578
|
}
|
|
@@ -1150,113 +1581,203 @@ var UpstashStore = class extends MastraStorage {
|
|
|
1150
1581
|
);
|
|
1151
1582
|
}
|
|
1152
1583
|
}
|
|
1584
|
+
};
|
|
1585
|
+
|
|
1586
|
+
// src/storage/index.ts
|
|
1587
|
+
var UpstashStore = class extends MastraStorage {
|
|
1588
|
+
redis;
|
|
1589
|
+
stores;
|
|
1590
|
+
constructor(config) {
|
|
1591
|
+
super({ name: "Upstash" });
|
|
1592
|
+
this.redis = new Redis({
|
|
1593
|
+
url: config.url,
|
|
1594
|
+
token: config.token
|
|
1595
|
+
});
|
|
1596
|
+
const operations = new StoreOperationsUpstash({ client: this.redis });
|
|
1597
|
+
const traces = new TracesUpstash({ client: this.redis, operations });
|
|
1598
|
+
const scores = new ScoresUpstash({ client: this.redis, operations });
|
|
1599
|
+
const workflows = new WorkflowsUpstash({ client: this.redis, operations });
|
|
1600
|
+
const memory = new StoreMemoryUpstash({ client: this.redis, operations });
|
|
1601
|
+
const legacyEvals = new StoreLegacyEvalsUpstash({ client: this.redis, operations });
|
|
1602
|
+
this.stores = {
|
|
1603
|
+
operations,
|
|
1604
|
+
traces,
|
|
1605
|
+
scores,
|
|
1606
|
+
workflows,
|
|
1607
|
+
memory,
|
|
1608
|
+
legacyEvals
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
get supports() {
|
|
1612
|
+
return {
|
|
1613
|
+
selectByIncludeResourceScope: true,
|
|
1614
|
+
resourceWorkingMemory: true,
|
|
1615
|
+
hasColumn: false,
|
|
1616
|
+
createTable: false
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* @deprecated Use getEvals instead
|
|
1621
|
+
*/
|
|
1622
|
+
async getEvalsByAgentName(agentName, type) {
|
|
1623
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
1624
|
+
}
|
|
1625
|
+
/**
|
|
1626
|
+
* Get all evaluations with pagination and total count
|
|
1627
|
+
* @param options Pagination and filtering options
|
|
1628
|
+
* @returns Object with evals array and total count
|
|
1629
|
+
*/
|
|
1630
|
+
async getEvals(options) {
|
|
1631
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
1632
|
+
}
|
|
1633
|
+
/**
|
|
1634
|
+
* @deprecated use getTracesPaginated instead
|
|
1635
|
+
*/
|
|
1636
|
+
async getTraces(args) {
|
|
1637
|
+
return this.stores.traces.getTraces(args);
|
|
1638
|
+
}
|
|
1639
|
+
async getTracesPaginated(args) {
|
|
1640
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
1641
|
+
}
|
|
1642
|
+
async batchTraceInsert(args) {
|
|
1643
|
+
return this.stores.traces.batchTraceInsert(args);
|
|
1644
|
+
}
|
|
1645
|
+
async createTable({
|
|
1646
|
+
tableName,
|
|
1647
|
+
schema
|
|
1648
|
+
}) {
|
|
1649
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
1653
|
+
* @param tableName Name of the table
|
|
1654
|
+
* @param schema Schema of the table
|
|
1655
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
1656
|
+
*/
|
|
1657
|
+
async alterTable(args) {
|
|
1658
|
+
return this.stores.operations.alterTable(args);
|
|
1659
|
+
}
|
|
1660
|
+
async clearTable({ tableName }) {
|
|
1661
|
+
return this.stores.operations.clearTable({ tableName });
|
|
1662
|
+
}
|
|
1663
|
+
async dropTable({ tableName }) {
|
|
1664
|
+
return this.stores.operations.dropTable({ tableName });
|
|
1665
|
+
}
|
|
1666
|
+
async insert({ tableName, record }) {
|
|
1667
|
+
return this.stores.operations.insert({ tableName, record });
|
|
1668
|
+
}
|
|
1669
|
+
async batchInsert(input) {
|
|
1670
|
+
return this.stores.operations.batchInsert(input);
|
|
1671
|
+
}
|
|
1672
|
+
async load({ tableName, keys }) {
|
|
1673
|
+
return this.stores.operations.load({ tableName, keys });
|
|
1674
|
+
}
|
|
1675
|
+
async getThreadById({ threadId }) {
|
|
1676
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
1680
|
+
*/
|
|
1681
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
1682
|
+
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
1683
|
+
}
|
|
1684
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
1685
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
1686
|
+
}
|
|
1687
|
+
async saveThread({ thread }) {
|
|
1688
|
+
return this.stores.memory.saveThread({ thread });
|
|
1689
|
+
}
|
|
1690
|
+
async updateThread({
|
|
1691
|
+
id,
|
|
1692
|
+
title,
|
|
1693
|
+
metadata
|
|
1694
|
+
}) {
|
|
1695
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
1696
|
+
}
|
|
1697
|
+
async deleteThread({ threadId }) {
|
|
1698
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
1699
|
+
}
|
|
1700
|
+
async saveMessages(args) {
|
|
1701
|
+
return this.stores.memory.saveMessages(args);
|
|
1702
|
+
}
|
|
1703
|
+
async getMessages({
|
|
1704
|
+
threadId,
|
|
1705
|
+
selectBy,
|
|
1706
|
+
format
|
|
1707
|
+
}) {
|
|
1708
|
+
return this.stores.memory.getMessages({ threadId, selectBy, format });
|
|
1709
|
+
}
|
|
1710
|
+
async getMessagesPaginated(args) {
|
|
1711
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
1712
|
+
}
|
|
1713
|
+
async persistWorkflowSnapshot(params) {
|
|
1714
|
+
return this.stores.workflows.persistWorkflowSnapshot(params);
|
|
1715
|
+
}
|
|
1716
|
+
async loadWorkflowSnapshot(params) {
|
|
1717
|
+
return this.stores.workflows.loadWorkflowSnapshot(params);
|
|
1718
|
+
}
|
|
1719
|
+
async getWorkflowRuns({
|
|
1720
|
+
workflowName,
|
|
1721
|
+
fromDate,
|
|
1722
|
+
toDate,
|
|
1723
|
+
limit,
|
|
1724
|
+
offset,
|
|
1725
|
+
resourceId
|
|
1726
|
+
} = {}) {
|
|
1727
|
+
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
1728
|
+
}
|
|
1153
1729
|
async getWorkflowRunById({
|
|
1154
|
-
namespace = "workflows",
|
|
1155
1730
|
runId,
|
|
1156
1731
|
workflowName
|
|
1157
1732
|
}) {
|
|
1158
|
-
|
|
1159
|
-
const key = this.getKey(TABLE_WORKFLOW_SNAPSHOT, { namespace, workflow_name: workflowName, run_id: runId }) + "*";
|
|
1160
|
-
const keys = await this.scanKeys(key);
|
|
1161
|
-
const workflows = await Promise.all(
|
|
1162
|
-
keys.map(async (key2) => {
|
|
1163
|
-
const data2 = await this.redis.get(key2);
|
|
1164
|
-
return data2;
|
|
1165
|
-
})
|
|
1166
|
-
);
|
|
1167
|
-
const data = workflows.find((w) => w?.run_id === runId && w?.workflow_name === workflowName);
|
|
1168
|
-
if (!data) return null;
|
|
1169
|
-
return this.parseWorkflowRun(data);
|
|
1170
|
-
} catch (error) {
|
|
1171
|
-
throw new MastraError(
|
|
1172
|
-
{
|
|
1173
|
-
id: "STORAGE_UPSTASH_STORAGE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
1174
|
-
domain: ErrorDomain.STORAGE,
|
|
1175
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1176
|
-
details: {
|
|
1177
|
-
namespace,
|
|
1178
|
-
runId,
|
|
1179
|
-
workflowName: workflowName || ""
|
|
1180
|
-
}
|
|
1181
|
-
},
|
|
1182
|
-
error
|
|
1183
|
-
);
|
|
1184
|
-
}
|
|
1733
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
1185
1734
|
}
|
|
1186
1735
|
async close() {
|
|
1187
1736
|
}
|
|
1188
|
-
async updateMessages(
|
|
1189
|
-
this.
|
|
1190
|
-
throw new Error("Method not implemented");
|
|
1737
|
+
async updateMessages(args) {
|
|
1738
|
+
return this.stores.memory.updateMessages(args);
|
|
1191
1739
|
}
|
|
1192
1740
|
async getResourceById({ resourceId }) {
|
|
1193
|
-
|
|
1194
|
-
const key = `${TABLE_RESOURCES}:${resourceId}`;
|
|
1195
|
-
const data = await this.redis.get(key);
|
|
1196
|
-
if (!data) {
|
|
1197
|
-
return null;
|
|
1198
|
-
}
|
|
1199
|
-
return {
|
|
1200
|
-
...data,
|
|
1201
|
-
createdAt: new Date(data.createdAt),
|
|
1202
|
-
updatedAt: new Date(data.updatedAt),
|
|
1203
|
-
// Ensure workingMemory is always returned as a string, regardless of automatic parsing
|
|
1204
|
-
workingMemory: typeof data.workingMemory === "object" ? JSON.stringify(data.workingMemory) : data.workingMemory,
|
|
1205
|
-
metadata: typeof data.metadata === "string" ? JSON.parse(data.metadata) : data.metadata
|
|
1206
|
-
};
|
|
1207
|
-
} catch (error) {
|
|
1208
|
-
this.logger.error("Error getting resource by ID:", error);
|
|
1209
|
-
throw error;
|
|
1210
|
-
}
|
|
1741
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
1211
1742
|
}
|
|
1212
1743
|
async saveResource({ resource }) {
|
|
1213
|
-
|
|
1214
|
-
const key = `${TABLE_RESOURCES}:${resource.id}`;
|
|
1215
|
-
const serializedResource = {
|
|
1216
|
-
...resource,
|
|
1217
|
-
metadata: JSON.stringify(resource.metadata),
|
|
1218
|
-
createdAt: resource.createdAt.toISOString(),
|
|
1219
|
-
updatedAt: resource.updatedAt.toISOString()
|
|
1220
|
-
};
|
|
1221
|
-
await this.redis.set(key, serializedResource);
|
|
1222
|
-
return resource;
|
|
1223
|
-
} catch (error) {
|
|
1224
|
-
this.logger.error("Error saving resource:", error);
|
|
1225
|
-
throw error;
|
|
1226
|
-
}
|
|
1744
|
+
return this.stores.memory.saveResource({ resource });
|
|
1227
1745
|
}
|
|
1228
1746
|
async updateResource({
|
|
1229
1747
|
resourceId,
|
|
1230
1748
|
workingMemory,
|
|
1231
1749
|
metadata
|
|
1232
1750
|
}) {
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1751
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
1752
|
+
}
|
|
1753
|
+
async getScoreById({ id: _id }) {
|
|
1754
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
1755
|
+
}
|
|
1756
|
+
async saveScore(score) {
|
|
1757
|
+
return this.stores.scores.saveScore(score);
|
|
1758
|
+
}
|
|
1759
|
+
async getScoresByRunId({
|
|
1760
|
+
runId,
|
|
1761
|
+
pagination
|
|
1762
|
+
}) {
|
|
1763
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
1764
|
+
}
|
|
1765
|
+
async getScoresByEntityId({
|
|
1766
|
+
entityId,
|
|
1767
|
+
entityType,
|
|
1768
|
+
pagination
|
|
1769
|
+
}) {
|
|
1770
|
+
return this.stores.scores.getScoresByEntityId({
|
|
1771
|
+
entityId,
|
|
1772
|
+
entityType,
|
|
1773
|
+
pagination
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
async getScoresByScorerId({
|
|
1777
|
+
scorerId,
|
|
1778
|
+
pagination
|
|
1779
|
+
}) {
|
|
1780
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
|
|
1260
1781
|
}
|
|
1261
1782
|
};
|
|
1262
1783
|
var UpstashFilterTranslator = class extends BaseFilterTranslator {
|