@mastra/cloudflare 0.11.1 → 0.11.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/dist/_tsup-dts-rollup.d.cts +353 -93
- package/dist/_tsup-dts-rollup.d.ts +353 -93
- package/dist/index.cjs +1851 -982
- package/dist/index.js +1850 -981
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -1,200 +1,999 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var agent = require('@mastra/core/agent');
|
|
4
3
|
var error = require('@mastra/core/error');
|
|
5
4
|
var storage = require('@mastra/core/storage');
|
|
6
5
|
var Cloudflare = require('cloudflare');
|
|
6
|
+
var agent = require('@mastra/core/agent');
|
|
7
7
|
|
|
8
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
9
|
|
|
10
10
|
var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
|
|
11
11
|
|
|
12
12
|
// src/storage/index.ts
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
var LegacyEvalsStorageCloudflare = class extends storage.LegacyEvalsStorage {
|
|
14
|
+
operations;
|
|
15
|
+
constructor({ operations }) {
|
|
16
|
+
super();
|
|
17
|
+
this.operations = operations;
|
|
18
|
+
}
|
|
19
|
+
async getEvalsByAgentName(agentName, type) {
|
|
20
|
+
try {
|
|
21
|
+
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
22
|
+
const keyObjs = await this.operations.listKV(storage.TABLE_EVALS, { prefix: `${prefix}${storage.TABLE_EVALS}` });
|
|
23
|
+
const evals = [];
|
|
24
|
+
for (const { name: key } of keyObjs) {
|
|
25
|
+
const data = await this.operations.getKV(storage.TABLE_EVALS, key);
|
|
26
|
+
if (!data) continue;
|
|
27
|
+
if (data.agent_name !== agentName) continue;
|
|
28
|
+
if (type) {
|
|
29
|
+
const isTest = data.test_info !== null && data.test_info !== void 0;
|
|
30
|
+
const evalType = isTest ? "test" : "live";
|
|
31
|
+
if (evalType !== type) continue;
|
|
32
|
+
}
|
|
33
|
+
const mappedData = {
|
|
34
|
+
...data,
|
|
35
|
+
runId: data.run_id,
|
|
36
|
+
testInfo: data.test_info
|
|
37
|
+
};
|
|
38
|
+
evals.push(mappedData);
|
|
39
|
+
}
|
|
40
|
+
evals.sort((a, b) => {
|
|
41
|
+
const aTime = new Date(a.createdAt || 0).getTime();
|
|
42
|
+
const bTime = new Date(b.createdAt || 0).getTime();
|
|
43
|
+
return bTime - aTime;
|
|
44
|
+
});
|
|
45
|
+
return evals;
|
|
46
|
+
} catch (error$1) {
|
|
47
|
+
throw new error.MastraError(
|
|
48
|
+
{
|
|
49
|
+
id: "CLOUDFLARE_STORAGE_GET_EVALS_BY_AGENT_NAME_FAILED",
|
|
50
|
+
domain: error.ErrorDomain.STORAGE,
|
|
51
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
52
|
+
text: "Failed to get evals by agent name"
|
|
53
|
+
},
|
|
54
|
+
error$1
|
|
55
|
+
);
|
|
28
56
|
}
|
|
29
|
-
|
|
30
|
-
|
|
57
|
+
}
|
|
58
|
+
async getEvals(options) {
|
|
59
|
+
try {
|
|
60
|
+
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
61
|
+
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
62
|
+
const keyObjs = await this.operations.listKV(storage.TABLE_EVALS, { prefix: `${prefix}${storage.TABLE_EVALS}` });
|
|
63
|
+
const evals = [];
|
|
64
|
+
for (const { name: key } of keyObjs) {
|
|
65
|
+
const data = await this.operations.getKV(storage.TABLE_EVALS, key);
|
|
66
|
+
if (!data) continue;
|
|
67
|
+
if (agentName && data.agent_name !== agentName) continue;
|
|
68
|
+
if (type) {
|
|
69
|
+
const isTest = data.test_info !== null && data.test_info !== void 0;
|
|
70
|
+
const evalType = isTest ? "test" : "live";
|
|
71
|
+
if (evalType !== type) continue;
|
|
72
|
+
}
|
|
73
|
+
if (dateRange?.start || dateRange?.end) {
|
|
74
|
+
const evalDate = new Date(data.createdAt || data.created_at || 0);
|
|
75
|
+
if (dateRange.start && evalDate < dateRange.start) continue;
|
|
76
|
+
if (dateRange.end && evalDate > dateRange.end) continue;
|
|
77
|
+
}
|
|
78
|
+
const mappedData = {
|
|
79
|
+
...data,
|
|
80
|
+
runId: data.run_id,
|
|
81
|
+
testInfo: data.test_info
|
|
82
|
+
};
|
|
83
|
+
evals.push(mappedData);
|
|
84
|
+
}
|
|
85
|
+
evals.sort((a, b) => {
|
|
86
|
+
const aTime = new Date(a.createdAt || 0).getTime();
|
|
87
|
+
const bTime = new Date(b.createdAt || 0).getTime();
|
|
88
|
+
return bTime - aTime;
|
|
89
|
+
});
|
|
90
|
+
const start = page * perPage;
|
|
91
|
+
const end = start + perPage;
|
|
92
|
+
const paginatedEvals = evals.slice(start, end);
|
|
93
|
+
return {
|
|
94
|
+
page,
|
|
95
|
+
perPage,
|
|
96
|
+
total: evals.length,
|
|
97
|
+
hasMore: start + perPage < evals.length,
|
|
98
|
+
evals: paginatedEvals
|
|
99
|
+
};
|
|
100
|
+
} catch (error$1) {
|
|
101
|
+
throw new error.MastraError(
|
|
102
|
+
{
|
|
103
|
+
id: "CLOUDFLARE_STORAGE_GET_EVALS_FAILED",
|
|
104
|
+
domain: error.ErrorDomain.STORAGE,
|
|
105
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
106
|
+
text: "Failed to get evals"
|
|
107
|
+
},
|
|
108
|
+
error$1
|
|
109
|
+
);
|
|
31
110
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
114
|
+
operations;
|
|
115
|
+
constructor({ operations }) {
|
|
116
|
+
super();
|
|
117
|
+
this.operations = operations;
|
|
118
|
+
}
|
|
119
|
+
ensureMetadata(metadata) {
|
|
120
|
+
if (!metadata) return void 0;
|
|
121
|
+
return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
|
|
122
|
+
}
|
|
123
|
+
async getThreadById({ threadId }) {
|
|
124
|
+
const thread = await this.operations.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
|
|
125
|
+
if (!thread) return null;
|
|
126
|
+
try {
|
|
127
|
+
return {
|
|
128
|
+
...thread,
|
|
129
|
+
createdAt: storage.ensureDate(thread.createdAt),
|
|
130
|
+
updatedAt: storage.ensureDate(thread.updatedAt),
|
|
131
|
+
metadata: this.ensureMetadata(thread.metadata)
|
|
132
|
+
};
|
|
133
|
+
} catch (error$1) {
|
|
134
|
+
const mastraError = new error.MastraError(
|
|
135
|
+
{
|
|
136
|
+
id: "CLOUDFLARE_STORAGE_GET_THREAD_BY_ID_FAILED",
|
|
137
|
+
domain: error.ErrorDomain.STORAGE,
|
|
138
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
139
|
+
details: {
|
|
140
|
+
threadId
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
error$1
|
|
144
|
+
);
|
|
145
|
+
this.logger?.trackException(mastraError);
|
|
146
|
+
this.logger?.error(mastraError.toString());
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
151
|
+
try {
|
|
152
|
+
const keyList = await this.operations.listKV(storage.TABLE_THREADS);
|
|
153
|
+
const threads = await Promise.all(
|
|
154
|
+
keyList.map(async (keyObj) => {
|
|
155
|
+
try {
|
|
156
|
+
const data = await this.operations.getKV(storage.TABLE_THREADS, keyObj.name);
|
|
157
|
+
if (!data) return null;
|
|
158
|
+
const thread = typeof data === "string" ? JSON.parse(data) : data;
|
|
159
|
+
if (!thread || !thread.resourceId || thread.resourceId !== resourceId) return null;
|
|
160
|
+
return {
|
|
161
|
+
...thread,
|
|
162
|
+
createdAt: storage.ensureDate(thread.createdAt),
|
|
163
|
+
updatedAt: storage.ensureDate(thread.updatedAt),
|
|
164
|
+
metadata: this.ensureMetadata(thread.metadata)
|
|
165
|
+
};
|
|
166
|
+
} catch (error$1) {
|
|
167
|
+
const mastraError = new error.MastraError(
|
|
168
|
+
{
|
|
169
|
+
id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
170
|
+
domain: error.ErrorDomain.STORAGE,
|
|
171
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
172
|
+
details: {
|
|
173
|
+
resourceId
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
error$1
|
|
177
|
+
);
|
|
178
|
+
this.logger?.trackException(mastraError);
|
|
179
|
+
this.logger?.error(mastraError.toString());
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
return threads.filter((thread) => thread !== null);
|
|
185
|
+
} catch (error$1) {
|
|
186
|
+
const mastraError = new error.MastraError(
|
|
187
|
+
{
|
|
188
|
+
id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
189
|
+
domain: error.ErrorDomain.STORAGE,
|
|
190
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
191
|
+
details: {
|
|
192
|
+
resourceId
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
error$1
|
|
196
|
+
);
|
|
197
|
+
this.logger?.trackException(mastraError);
|
|
198
|
+
this.logger?.error(mastraError.toString());
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
203
|
+
try {
|
|
204
|
+
const { resourceId, page = 0, perPage = 100 } = args;
|
|
205
|
+
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
206
|
+
const keyObjs = await this.operations.listKV(storage.TABLE_THREADS, { prefix: `${prefix}${storage.TABLE_THREADS}` });
|
|
207
|
+
const threads = [];
|
|
208
|
+
for (const { name: key } of keyObjs) {
|
|
209
|
+
const data = await this.operations.getKV(storage.TABLE_THREADS, key);
|
|
210
|
+
if (!data) continue;
|
|
211
|
+
if (data.resourceId !== resourceId) continue;
|
|
212
|
+
threads.push(data);
|
|
36
213
|
}
|
|
214
|
+
threads.sort((a, b) => {
|
|
215
|
+
const aTime = new Date(a.createdAt || 0).getTime();
|
|
216
|
+
const bTime = new Date(b.createdAt || 0).getTime();
|
|
217
|
+
return bTime - aTime;
|
|
218
|
+
});
|
|
219
|
+
const start = page * perPage;
|
|
220
|
+
const end = start + perPage;
|
|
221
|
+
const paginatedThreads = threads.slice(start, end);
|
|
222
|
+
return {
|
|
223
|
+
page,
|
|
224
|
+
perPage,
|
|
225
|
+
total: threads.length,
|
|
226
|
+
hasMore: start + perPage < threads.length,
|
|
227
|
+
threads: paginatedThreads
|
|
228
|
+
};
|
|
229
|
+
} catch (error$1) {
|
|
230
|
+
throw new error.MastraError(
|
|
231
|
+
{
|
|
232
|
+
id: "CLOUDFLARE_STORAGE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
|
|
233
|
+
domain: error.ErrorDomain.STORAGE,
|
|
234
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
235
|
+
text: "Failed to get threads by resource ID with pagination"
|
|
236
|
+
},
|
|
237
|
+
error$1
|
|
238
|
+
);
|
|
37
239
|
}
|
|
38
240
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
241
|
+
async saveThread({ thread }) {
|
|
242
|
+
try {
|
|
243
|
+
await this.operations.insert({ tableName: storage.TABLE_THREADS, record: thread });
|
|
244
|
+
return thread;
|
|
245
|
+
} catch (error$1) {
|
|
246
|
+
throw new error.MastraError(
|
|
247
|
+
{
|
|
248
|
+
id: "CLOUDFLARE_STORAGE_SAVE_THREAD_FAILED",
|
|
249
|
+
domain: error.ErrorDomain.STORAGE,
|
|
250
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
251
|
+
details: {
|
|
252
|
+
threadId: thread.id
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
error$1
|
|
256
|
+
);
|
|
42
257
|
}
|
|
43
|
-
|
|
44
|
-
|
|
258
|
+
}
|
|
259
|
+
async updateThread({
|
|
260
|
+
id,
|
|
261
|
+
title,
|
|
262
|
+
metadata
|
|
263
|
+
}) {
|
|
264
|
+
try {
|
|
265
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
266
|
+
if (!thread) {
|
|
267
|
+
throw new Error(`Thread ${id} not found`);
|
|
268
|
+
}
|
|
269
|
+
const updatedThread = {
|
|
270
|
+
...thread,
|
|
271
|
+
title,
|
|
272
|
+
metadata: this.ensureMetadata({
|
|
273
|
+
...thread.metadata ?? {},
|
|
274
|
+
...metadata
|
|
275
|
+
}),
|
|
276
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
277
|
+
};
|
|
278
|
+
await this.operations.insert({ tableName: storage.TABLE_THREADS, record: updatedThread });
|
|
279
|
+
return updatedThread;
|
|
280
|
+
} catch (error$1) {
|
|
281
|
+
throw new error.MastraError(
|
|
282
|
+
{
|
|
283
|
+
id: "CLOUDFLARE_STORAGE_UPDATE_THREAD_FAILED",
|
|
284
|
+
domain: error.ErrorDomain.STORAGE,
|
|
285
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
286
|
+
details: {
|
|
287
|
+
threadId: id,
|
|
288
|
+
title
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
error$1
|
|
292
|
+
);
|
|
45
293
|
}
|
|
46
|
-
|
|
47
|
-
|
|
294
|
+
}
|
|
295
|
+
getMessageKey(threadId, messageId) {
|
|
296
|
+
try {
|
|
297
|
+
return this.operations.getKey(storage.TABLE_MESSAGES, { threadId, id: messageId });
|
|
298
|
+
} catch (error) {
|
|
299
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
300
|
+
this.logger.error(`Error getting message key for thread ${threadId} and message ${messageId}:`, { message });
|
|
301
|
+
throw error;
|
|
48
302
|
}
|
|
49
303
|
}
|
|
50
|
-
|
|
51
|
-
super({ name: "Cloudflare" });
|
|
304
|
+
getThreadMessagesKey(threadId) {
|
|
52
305
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
|
|
306
|
+
return this.operations.getKey(storage.TABLE_MESSAGES, { threadId, id: "messages" });
|
|
307
|
+
} catch (error) {
|
|
308
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
309
|
+
this.logger.error(`Error getting thread messages key for thread ${threadId}:`, { message });
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
async deleteThread({ threadId }) {
|
|
314
|
+
try {
|
|
315
|
+
const thread = await this.getThreadById({ threadId });
|
|
316
|
+
if (!thread) {
|
|
317
|
+
throw new Error(`Thread ${threadId} not found`);
|
|
318
|
+
}
|
|
319
|
+
const messageKeys = await this.operations.listKV(storage.TABLE_MESSAGES);
|
|
320
|
+
const threadMessageKeys = messageKeys.filter((key) => key.name.includes(`${storage.TABLE_MESSAGES}:${threadId}:`));
|
|
321
|
+
await Promise.all([
|
|
322
|
+
// Delete message order
|
|
323
|
+
this.operations.deleteKV(storage.TABLE_MESSAGES, this.getThreadMessagesKey(threadId)),
|
|
324
|
+
// Delete all messages
|
|
325
|
+
...threadMessageKeys.map((key) => this.operations.deleteKV(storage.TABLE_MESSAGES, key.name)),
|
|
326
|
+
// Delete thread
|
|
327
|
+
this.operations.deleteKV(storage.TABLE_THREADS, this.operations.getKey(storage.TABLE_THREADS, { id: threadId }))
|
|
328
|
+
]);
|
|
329
|
+
} catch (error$1) {
|
|
330
|
+
throw new error.MastraError(
|
|
331
|
+
{
|
|
332
|
+
id: "CLOUDFLARE_STORAGE_DELETE_THREAD_FAILED",
|
|
333
|
+
domain: error.ErrorDomain.STORAGE,
|
|
334
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
335
|
+
details: {
|
|
336
|
+
threadId
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
error$1
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async findMessageInAnyThread(messageId) {
|
|
344
|
+
try {
|
|
345
|
+
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
346
|
+
const threadKeys = await this.operations.listKV(storage.TABLE_THREADS, { prefix: `${prefix}${storage.TABLE_THREADS}` });
|
|
347
|
+
for (const { name: threadKey } of threadKeys) {
|
|
348
|
+
const threadId = threadKey.split(":").pop();
|
|
349
|
+
if (!threadId || threadId === "messages") continue;
|
|
350
|
+
const messageKey = this.getMessageKey(threadId, messageId);
|
|
351
|
+
const message = await this.operations.getKV(storage.TABLE_MESSAGES, messageKey);
|
|
352
|
+
if (message) {
|
|
353
|
+
return { ...message, threadId };
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return null;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
this.logger?.error(`Error finding message ${messageId} in any thread:`, error);
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Queue for serializing sorted order updates.
|
|
364
|
+
* Updates the sorted order for a given key. This operation is eventually consistent.
|
|
365
|
+
*/
|
|
366
|
+
updateQueue = /* @__PURE__ */ new Map();
|
|
367
|
+
async updateSorting(threadMessages) {
|
|
368
|
+
return threadMessages.map((msg) => ({
|
|
369
|
+
message: msg,
|
|
370
|
+
// Use _index if available, otherwise timestamp, matching Upstash
|
|
371
|
+
score: msg._index !== void 0 ? msg._index : msg.createdAt.getTime()
|
|
372
|
+
})).sort((a, b) => a.score - b.score).map((item) => ({
|
|
373
|
+
id: item.message.id,
|
|
374
|
+
score: item.score
|
|
375
|
+
}));
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Updates the sorted order for a given key. This operation is eventually consistent.
|
|
379
|
+
* Note: Operations on the same orderKey are serialized using a queue to prevent
|
|
380
|
+
* concurrent updates from conflicting with each other.
|
|
381
|
+
*/
|
|
382
|
+
async updateSortedMessages(orderKey, newEntries) {
|
|
383
|
+
const currentPromise = this.updateQueue.get(orderKey) || Promise.resolve();
|
|
384
|
+
const nextPromise = currentPromise.then(async () => {
|
|
385
|
+
try {
|
|
386
|
+
const currentOrder = await this.getSortedMessages(orderKey);
|
|
387
|
+
const orderMap = new Map(currentOrder.map((entry) => [entry.id, entry]));
|
|
388
|
+
for (const entry of newEntries) {
|
|
389
|
+
orderMap.set(entry.id, entry);
|
|
390
|
+
}
|
|
391
|
+
const updatedOrder = Array.from(orderMap.values()).sort((a, b) => a.score - b.score);
|
|
392
|
+
await this.operations.putKV({
|
|
393
|
+
tableName: storage.TABLE_MESSAGES,
|
|
394
|
+
key: orderKey,
|
|
395
|
+
value: JSON.stringify(updatedOrder)
|
|
396
|
+
});
|
|
397
|
+
} catch (error) {
|
|
398
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
399
|
+
this.logger.error(`Error updating sorted order for key ${orderKey}:`, { message });
|
|
400
|
+
throw error;
|
|
401
|
+
} finally {
|
|
402
|
+
if (this.updateQueue.get(orderKey) === nextPromise) {
|
|
403
|
+
this.updateQueue.delete(orderKey);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
this.updateQueue.set(orderKey, nextPromise);
|
|
408
|
+
return nextPromise;
|
|
409
|
+
}
|
|
410
|
+
async getSortedMessages(orderKey) {
|
|
411
|
+
const raw = await this.operations.getKV(storage.TABLE_MESSAGES, orderKey);
|
|
412
|
+
if (!raw) return [];
|
|
413
|
+
try {
|
|
414
|
+
const arr = JSON.parse(typeof raw === "string" ? raw : JSON.stringify(raw));
|
|
415
|
+
return Array.isArray(arr) ? arr : [];
|
|
416
|
+
} catch (e) {
|
|
417
|
+
this.logger.error(`Error parsing order data for key ${orderKey}:`, { e });
|
|
418
|
+
return [];
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
async migrateMessage(messageId, fromThreadId, toThreadId) {
|
|
422
|
+
try {
|
|
423
|
+
const oldMessageKey = this.getMessageKey(fromThreadId, messageId);
|
|
424
|
+
const message = await this.operations.getKV(storage.TABLE_MESSAGES, oldMessageKey);
|
|
425
|
+
if (!message) return;
|
|
426
|
+
const updatedMessage = {
|
|
427
|
+
...message,
|
|
428
|
+
threadId: toThreadId
|
|
429
|
+
};
|
|
430
|
+
const newMessageKey = this.getMessageKey(toThreadId, messageId);
|
|
431
|
+
await this.operations.putKV({ tableName: storage.TABLE_MESSAGES, key: newMessageKey, value: updatedMessage });
|
|
432
|
+
const oldOrderKey = this.getThreadMessagesKey(fromThreadId);
|
|
433
|
+
const oldEntries = await this.getSortedMessages(oldOrderKey);
|
|
434
|
+
const filteredEntries = oldEntries.filter((entry) => entry.id !== messageId);
|
|
435
|
+
await this.updateSortedMessages(oldOrderKey, filteredEntries);
|
|
436
|
+
const newOrderKey = this.getThreadMessagesKey(toThreadId);
|
|
437
|
+
const newEntries = await this.getSortedMessages(newOrderKey);
|
|
438
|
+
const newEntry = { id: messageId, score: Date.now() };
|
|
439
|
+
newEntries.push(newEntry);
|
|
440
|
+
await this.updateSortedMessages(newOrderKey, newEntries);
|
|
441
|
+
await this.operations.deleteKV(storage.TABLE_MESSAGES, oldMessageKey);
|
|
442
|
+
} catch (error) {
|
|
443
|
+
this.logger?.error(`Error migrating message ${messageId} from ${fromThreadId} to ${toThreadId}:`, error);
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
async saveMessages(args) {
|
|
448
|
+
const { messages, format = "v1" } = args;
|
|
449
|
+
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
450
|
+
try {
|
|
451
|
+
const validatedMessages = messages.map((message, index) => {
|
|
452
|
+
const errors = [];
|
|
453
|
+
if (!message.id) errors.push("id is required");
|
|
454
|
+
if (!message.threadId) errors.push("threadId is required");
|
|
455
|
+
if (!message.content) errors.push("content is required");
|
|
456
|
+
if (!message.role) errors.push("role is required");
|
|
457
|
+
if (!message.createdAt) errors.push("createdAt is required");
|
|
458
|
+
if (message.resourceId === null || message.resourceId === void 0) errors.push("resourceId is required");
|
|
459
|
+
if (errors.length > 0) {
|
|
460
|
+
throw new Error(`Invalid message at index ${index}: ${errors.join(", ")}`);
|
|
461
|
+
}
|
|
462
|
+
return {
|
|
463
|
+
...message,
|
|
464
|
+
createdAt: storage.ensureDate(message.createdAt),
|
|
465
|
+
type: message.type || "v2",
|
|
466
|
+
_index: index
|
|
467
|
+
};
|
|
468
|
+
}).filter((m) => !!m);
|
|
469
|
+
const messageMigrationTasks = [];
|
|
470
|
+
for (const message of validatedMessages) {
|
|
471
|
+
const existingMessage = await this.findMessageInAnyThread(message.id);
|
|
472
|
+
console.log(`Checking message ${message.id}: existing=${existingMessage?.threadId}, new=${message.threadId}`);
|
|
473
|
+
if (existingMessage && existingMessage.threadId && existingMessage.threadId !== message.threadId) {
|
|
474
|
+
console.log(`Migrating message ${message.id} from ${existingMessage.threadId} to ${message.threadId}`);
|
|
475
|
+
messageMigrationTasks.push(this.migrateMessage(message.id, existingMessage.threadId, message.threadId));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
await Promise.all(messageMigrationTasks);
|
|
479
|
+
const messagesByThread = validatedMessages.reduce((acc, message) => {
|
|
480
|
+
if (message.threadId && !acc.has(message.threadId)) {
|
|
481
|
+
acc.set(message.threadId, []);
|
|
482
|
+
}
|
|
483
|
+
if (message.threadId) {
|
|
484
|
+
acc.get(message.threadId).push(message);
|
|
485
|
+
}
|
|
486
|
+
return acc;
|
|
487
|
+
}, /* @__PURE__ */ new Map());
|
|
488
|
+
await Promise.all(
|
|
489
|
+
Array.from(messagesByThread.entries()).map(async ([threadId, threadMessages]) => {
|
|
490
|
+
try {
|
|
491
|
+
const thread = await this.getThreadById({ threadId });
|
|
492
|
+
if (!thread) {
|
|
493
|
+
throw new Error(`Thread ${threadId} not found`);
|
|
494
|
+
}
|
|
495
|
+
await Promise.all(
|
|
496
|
+
threadMessages.map(async (message) => {
|
|
497
|
+
const key = this.getMessageKey(threadId, message.id);
|
|
498
|
+
const { _index, ...cleanMessage } = message;
|
|
499
|
+
const serializedMessage = {
|
|
500
|
+
...cleanMessage,
|
|
501
|
+
createdAt: storage.serializeDate(cleanMessage.createdAt)
|
|
502
|
+
};
|
|
503
|
+
console.log(`Saving message ${message.id} with content:`, {
|
|
504
|
+
content: serializedMessage.content,
|
|
505
|
+
contentType: typeof serializedMessage.content,
|
|
506
|
+
isArray: Array.isArray(serializedMessage.content)
|
|
507
|
+
});
|
|
508
|
+
await this.operations.putKV({ tableName: storage.TABLE_MESSAGES, key, value: serializedMessage });
|
|
509
|
+
})
|
|
510
|
+
);
|
|
511
|
+
const orderKey = this.getThreadMessagesKey(threadId);
|
|
512
|
+
const entries = await this.updateSorting(threadMessages);
|
|
513
|
+
await this.updateSortedMessages(orderKey, entries);
|
|
514
|
+
const updatedThread = {
|
|
515
|
+
...thread,
|
|
516
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
517
|
+
};
|
|
518
|
+
await this.operations.putKV({
|
|
519
|
+
tableName: storage.TABLE_THREADS,
|
|
520
|
+
key: this.operations.getKey(storage.TABLE_THREADS, { id: threadId }),
|
|
521
|
+
value: updatedThread
|
|
522
|
+
});
|
|
523
|
+
} catch (error$1) {
|
|
524
|
+
throw new error.MastraError(
|
|
525
|
+
{
|
|
526
|
+
id: "CLOUDFLARE_STORAGE_SAVE_MESSAGES_FAILED",
|
|
527
|
+
domain: error.ErrorDomain.STORAGE,
|
|
528
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
529
|
+
details: {
|
|
530
|
+
threadId
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
error$1
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
})
|
|
537
|
+
);
|
|
538
|
+
const prepared = validatedMessages.map(
|
|
539
|
+
({ _index, ...message }) => ({ ...message, type: message.type !== "v2" ? message.type : void 0 })
|
|
540
|
+
);
|
|
541
|
+
const list = new agent.MessageList().add(prepared, "memory");
|
|
542
|
+
if (format === `v2`) return list.get.all.v2();
|
|
543
|
+
return list.get.all.v1();
|
|
544
|
+
} catch (error$1) {
|
|
545
|
+
throw new error.MastraError(
|
|
546
|
+
{
|
|
547
|
+
id: "CLOUDFLARE_STORAGE_SAVE_MESSAGES_FAILED",
|
|
548
|
+
domain: error.ErrorDomain.STORAGE,
|
|
549
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
550
|
+
},
|
|
551
|
+
error$1
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
async getRank(orderKey, id) {
|
|
556
|
+
const order = await this.getSortedMessages(orderKey);
|
|
557
|
+
const index = order.findIndex((item) => item.id === id);
|
|
558
|
+
return index >= 0 ? index : null;
|
|
559
|
+
}
|
|
560
|
+
async getRange(orderKey, start, end) {
|
|
561
|
+
const order = await this.getSortedMessages(orderKey);
|
|
562
|
+
const actualStart = start < 0 ? Math.max(0, order.length + start) : start;
|
|
563
|
+
const actualEnd = end < 0 ? order.length + end : Math.min(end, order.length - 1);
|
|
564
|
+
const sliced = order.slice(actualStart, actualEnd + 1);
|
|
565
|
+
return sliced.map((item) => item.id);
|
|
566
|
+
}
|
|
567
|
+
async getLastN(orderKey, n) {
|
|
568
|
+
return this.getRange(orderKey, -n, -1);
|
|
569
|
+
}
|
|
570
|
+
async getFullOrder(orderKey) {
|
|
571
|
+
return this.getRange(orderKey, 0, -1);
|
|
572
|
+
}
|
|
573
|
+
async getIncludedMessagesWithContext(threadId, include, messageIds) {
|
|
574
|
+
await Promise.all(
|
|
575
|
+
include.map(async (item) => {
|
|
576
|
+
const targetThreadId = item.threadId || threadId;
|
|
577
|
+
if (!targetThreadId) return;
|
|
578
|
+
const threadMessagesKey = this.getThreadMessagesKey(targetThreadId);
|
|
579
|
+
messageIds.add(item.id);
|
|
580
|
+
if (!item.withPreviousMessages && !item.withNextMessages) return;
|
|
581
|
+
const rank = await this.getRank(threadMessagesKey, item.id);
|
|
582
|
+
if (rank === null) return;
|
|
583
|
+
if (item.withPreviousMessages) {
|
|
584
|
+
const prevIds = await this.getRange(
|
|
585
|
+
threadMessagesKey,
|
|
586
|
+
Math.max(0, rank - item.withPreviousMessages),
|
|
587
|
+
rank - 1
|
|
588
|
+
);
|
|
589
|
+
prevIds.forEach((id) => messageIds.add(id));
|
|
590
|
+
}
|
|
591
|
+
if (item.withNextMessages) {
|
|
592
|
+
const nextIds = await this.getRange(threadMessagesKey, rank + 1, rank + item.withNextMessages);
|
|
593
|
+
nextIds.forEach((id) => messageIds.add(id));
|
|
594
|
+
}
|
|
595
|
+
})
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
async getRecentMessages(threadId, limit, messageIds) {
|
|
599
|
+
if (limit <= 0) return;
|
|
600
|
+
try {
|
|
601
|
+
const threadMessagesKey = this.getThreadMessagesKey(threadId);
|
|
602
|
+
const latestIds = await this.getLastN(threadMessagesKey, limit);
|
|
603
|
+
latestIds.forEach((id) => messageIds.add(id));
|
|
604
|
+
} catch {
|
|
605
|
+
console.log(`No message order found for thread ${threadId}, skipping latest messages`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
async fetchAndParseMessagesFromMultipleThreads(messageIds, include, targetThreadId) {
|
|
609
|
+
const messageIdToThreadId = /* @__PURE__ */ new Map();
|
|
610
|
+
if (include) {
|
|
611
|
+
for (const item of include) {
|
|
612
|
+
if (item.threadId) {
|
|
613
|
+
messageIdToThreadId.set(item.id, item.threadId);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
const messages = await Promise.all(
|
|
618
|
+
messageIds.map(async (id) => {
|
|
619
|
+
try {
|
|
620
|
+
let threadId = messageIdToThreadId.get(id);
|
|
621
|
+
if (!threadId) {
|
|
622
|
+
if (targetThreadId) {
|
|
623
|
+
threadId = targetThreadId;
|
|
624
|
+
} else {
|
|
625
|
+
const foundMessage = await this.findMessageInAnyThread(id);
|
|
626
|
+
if (foundMessage) {
|
|
627
|
+
threadId = foundMessage.threadId;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (!threadId) return null;
|
|
632
|
+
const key = this.getMessageKey(threadId, id);
|
|
633
|
+
const data = await this.operations.getKV(storage.TABLE_MESSAGES, key);
|
|
634
|
+
if (!data) return null;
|
|
635
|
+
const parsed = typeof data === "string" ? JSON.parse(data) : data;
|
|
636
|
+
console.log(`Retrieved message ${id} from thread ${threadId} with content:`, {
|
|
637
|
+
content: parsed.content,
|
|
638
|
+
contentType: typeof parsed.content,
|
|
639
|
+
isArray: Array.isArray(parsed.content)
|
|
640
|
+
});
|
|
641
|
+
return parsed;
|
|
642
|
+
} catch (error) {
|
|
643
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
644
|
+
this.logger.error(`Error retrieving message ${id}:`, { message });
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
})
|
|
648
|
+
);
|
|
649
|
+
return messages.filter((msg) => msg !== null);
|
|
650
|
+
}
|
|
651
|
+
async getMessages({
|
|
652
|
+
threadId,
|
|
653
|
+
resourceId,
|
|
654
|
+
selectBy,
|
|
655
|
+
format
|
|
656
|
+
}) {
|
|
657
|
+
console.log(`getMessages called with format: ${format}, threadId: ${threadId}`);
|
|
658
|
+
if (!threadId) throw new Error("threadId is required");
|
|
659
|
+
const actualFormat = format || "v1";
|
|
660
|
+
console.log(`Using format: ${actualFormat}`);
|
|
661
|
+
if (!threadId) throw new Error("threadId is required");
|
|
662
|
+
const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
663
|
+
const messageIds = /* @__PURE__ */ new Set();
|
|
664
|
+
if (limit === 0 && !selectBy?.include?.length) return [];
|
|
665
|
+
try {
|
|
666
|
+
await Promise.all([
|
|
667
|
+
selectBy?.include?.length ? this.getIncludedMessagesWithContext(threadId, selectBy.include, messageIds) : Promise.resolve(),
|
|
668
|
+
limit > 0 ? this.getRecentMessages(threadId, limit, messageIds) : Promise.resolve()
|
|
669
|
+
]);
|
|
670
|
+
const targetThreadId = selectBy?.include?.length ? void 0 : threadId;
|
|
671
|
+
const messages = await this.fetchAndParseMessagesFromMultipleThreads(
|
|
672
|
+
Array.from(messageIds),
|
|
673
|
+
selectBy?.include,
|
|
674
|
+
targetThreadId
|
|
675
|
+
);
|
|
676
|
+
if (!messages.length) return [];
|
|
677
|
+
try {
|
|
678
|
+
const threadMessagesKey = this.getThreadMessagesKey(threadId);
|
|
679
|
+
const messageOrder = await this.getFullOrder(threadMessagesKey);
|
|
680
|
+
const orderMap = new Map(messageOrder.map((id, index) => [id, index]));
|
|
681
|
+
messages.sort((a, b) => {
|
|
682
|
+
const indexA = orderMap.get(a.id);
|
|
683
|
+
const indexB = orderMap.get(b.id);
|
|
684
|
+
if (indexA !== void 0 && indexB !== void 0) return orderMap.get(a.id) - orderMap.get(b.id);
|
|
685
|
+
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
|
686
|
+
});
|
|
687
|
+
} catch (error$1) {
|
|
688
|
+
const mastraError = new error.MastraError(
|
|
689
|
+
{
|
|
690
|
+
id: "CLOUDFLARE_STORAGE_SORT_MESSAGES_FAILED",
|
|
691
|
+
domain: error.ErrorDomain.STORAGE,
|
|
692
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
693
|
+
text: `Error sorting messages for thread ${threadId} falling back to creation time`,
|
|
694
|
+
details: {
|
|
695
|
+
threadId
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
error$1
|
|
699
|
+
);
|
|
700
|
+
this.logger?.trackException(mastraError);
|
|
701
|
+
this.logger?.error(mastraError.toString());
|
|
702
|
+
messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
703
|
+
}
|
|
704
|
+
const prepared = messages.map(({ _index, ...message }) => ({
|
|
705
|
+
...message,
|
|
706
|
+
type: message.type === `v2` ? void 0 : message.type,
|
|
707
|
+
createdAt: storage.ensureDate(message.createdAt)
|
|
708
|
+
}));
|
|
709
|
+
if (actualFormat === `v1`) {
|
|
710
|
+
console.log(`Processing ${prepared.length} messages for v1 format - returning directly without MessageList`);
|
|
711
|
+
return prepared.map((msg) => ({
|
|
712
|
+
...msg,
|
|
713
|
+
createdAt: new Date(msg.createdAt)
|
|
714
|
+
}));
|
|
715
|
+
}
|
|
716
|
+
const list = new agent.MessageList({ threadId, resourceId }).add(prepared, "memory");
|
|
717
|
+
return list.get.all.v2();
|
|
718
|
+
} catch (error$1) {
|
|
719
|
+
const mastraError = new error.MastraError(
|
|
720
|
+
{
|
|
721
|
+
id: "CLOUDFLARE_STORAGE_GET_MESSAGES_FAILED",
|
|
722
|
+
domain: error.ErrorDomain.STORAGE,
|
|
723
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
724
|
+
text: `Error retrieving messages for thread ${threadId}`,
|
|
725
|
+
details: {
|
|
726
|
+
threadId
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
error$1
|
|
730
|
+
);
|
|
731
|
+
this.logger?.trackException(mastraError);
|
|
732
|
+
this.logger?.error(mastraError.toString());
|
|
733
|
+
return [];
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async getMessagesPaginated(args) {
|
|
737
|
+
try {
|
|
738
|
+
const { threadId, selectBy, format = "v1" } = args;
|
|
739
|
+
const { page = 0, perPage = 100 } = selectBy?.pagination || {};
|
|
740
|
+
const messages = format === "v2" ? await this.getMessages({ threadId, selectBy, format: "v2" }) : await this.getMessages({ threadId, selectBy, format: "v1" });
|
|
741
|
+
let filteredMessages = messages;
|
|
742
|
+
if (selectBy?.pagination?.dateRange) {
|
|
743
|
+
const { start: dateStart, end: dateEnd } = selectBy.pagination.dateRange;
|
|
744
|
+
filteredMessages = messages.filter((message) => {
|
|
745
|
+
const messageDate = new Date(message.createdAt);
|
|
746
|
+
if (dateStart && messageDate < dateStart) return false;
|
|
747
|
+
if (dateEnd && messageDate > dateEnd) return false;
|
|
748
|
+
return true;
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
const start = page * perPage;
|
|
752
|
+
const end = start + perPage;
|
|
753
|
+
const paginatedMessages = filteredMessages.slice(start, end);
|
|
754
|
+
return {
|
|
755
|
+
page,
|
|
756
|
+
perPage,
|
|
757
|
+
total: filteredMessages.length,
|
|
758
|
+
hasMore: start + perPage < filteredMessages.length,
|
|
759
|
+
messages: paginatedMessages
|
|
760
|
+
};
|
|
761
|
+
} catch (error$1) {
|
|
762
|
+
throw new error.MastraError(
|
|
763
|
+
{
|
|
764
|
+
id: "CLOUDFLARE_STORAGE_GET_MESSAGES_PAGINATED_FAILED",
|
|
765
|
+
domain: error.ErrorDomain.STORAGE,
|
|
766
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
767
|
+
text: "Failed to get messages with pagination"
|
|
768
|
+
},
|
|
769
|
+
error$1
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
async updateMessages(args) {
|
|
774
|
+
try {
|
|
775
|
+
const { messages } = args;
|
|
776
|
+
const updatedMessages = [];
|
|
777
|
+
for (const messageUpdate of messages) {
|
|
778
|
+
const { id, content, ...otherFields } = messageUpdate;
|
|
779
|
+
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
780
|
+
const keyObjs = await this.operations.listKV(storage.TABLE_MESSAGES, { prefix: `${prefix}${storage.TABLE_MESSAGES}` });
|
|
781
|
+
let existingMessage = null;
|
|
782
|
+
let messageKey = "";
|
|
783
|
+
for (const { name: key } of keyObjs) {
|
|
784
|
+
const data = await this.operations.getKV(storage.TABLE_MESSAGES, key);
|
|
785
|
+
if (data && data.id === id) {
|
|
786
|
+
existingMessage = data;
|
|
787
|
+
messageKey = key;
|
|
788
|
+
break;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
if (!existingMessage) {
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
const updatedMessage = {
|
|
795
|
+
...existingMessage,
|
|
796
|
+
...otherFields,
|
|
797
|
+
id
|
|
798
|
+
};
|
|
799
|
+
if (content) {
|
|
800
|
+
if (content.metadata !== void 0) {
|
|
801
|
+
updatedMessage.content = {
|
|
802
|
+
...updatedMessage.content,
|
|
803
|
+
metadata: {
|
|
804
|
+
...updatedMessage.content?.metadata,
|
|
805
|
+
...content.metadata
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
if (content.content !== void 0) {
|
|
810
|
+
updatedMessage.content = {
|
|
811
|
+
...updatedMessage.content,
|
|
812
|
+
content: content.content
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
|
|
817
|
+
await this.operations.deleteKV(storage.TABLE_MESSAGES, messageKey);
|
|
818
|
+
updatedMessage.threadId = messageUpdate.threadId;
|
|
819
|
+
const newMessageKey = this.getMessageKey(messageUpdate.threadId, id);
|
|
820
|
+
await this.operations.putKV({
|
|
821
|
+
tableName: storage.TABLE_MESSAGES,
|
|
822
|
+
key: newMessageKey,
|
|
823
|
+
value: updatedMessage
|
|
824
|
+
});
|
|
825
|
+
if (existingMessage.threadId) {
|
|
826
|
+
const sourceOrderKey = this.getThreadMessagesKey(existingMessage.threadId);
|
|
827
|
+
const sourceEntries = await this.getSortedMessages(sourceOrderKey);
|
|
828
|
+
const filteredEntries = sourceEntries.filter((entry) => entry.id !== id);
|
|
829
|
+
await this.updateSortedMessages(sourceOrderKey, filteredEntries);
|
|
830
|
+
}
|
|
831
|
+
const destOrderKey = this.getThreadMessagesKey(messageUpdate.threadId);
|
|
832
|
+
const destEntries = await this.getSortedMessages(destOrderKey);
|
|
833
|
+
const newEntry = { id, score: Date.now() };
|
|
834
|
+
destEntries.push(newEntry);
|
|
835
|
+
await this.updateSortedMessages(destOrderKey, destEntries);
|
|
836
|
+
} else {
|
|
837
|
+
await this.operations.putKV({
|
|
838
|
+
tableName: storage.TABLE_MESSAGES,
|
|
839
|
+
key: messageKey,
|
|
840
|
+
value: updatedMessage
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
const threadsToUpdate = /* @__PURE__ */ new Set();
|
|
844
|
+
if (updatedMessage.threadId) {
|
|
845
|
+
threadsToUpdate.add(updatedMessage.threadId);
|
|
846
|
+
}
|
|
847
|
+
if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
|
|
848
|
+
if (existingMessage.threadId) {
|
|
849
|
+
threadsToUpdate.add(existingMessage.threadId);
|
|
850
|
+
}
|
|
851
|
+
threadsToUpdate.add(messageUpdate.threadId);
|
|
852
|
+
}
|
|
853
|
+
for (const threadId of threadsToUpdate) {
|
|
854
|
+
const thread = await this.getThreadById({ threadId });
|
|
855
|
+
if (thread) {
|
|
856
|
+
const updatedThread = {
|
|
857
|
+
...thread,
|
|
858
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
859
|
+
};
|
|
860
|
+
await this.operations.putKV({
|
|
861
|
+
tableName: storage.TABLE_THREADS,
|
|
862
|
+
key: this.operations.getKey(storage.TABLE_THREADS, { id: threadId }),
|
|
863
|
+
value: updatedThread
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
updatedMessages.push(updatedMessage);
|
|
66
868
|
}
|
|
869
|
+
return updatedMessages;
|
|
67
870
|
} catch (error$1) {
|
|
68
871
|
throw new error.MastraError(
|
|
69
872
|
{
|
|
70
|
-
id: "
|
|
873
|
+
id: "CLOUDFLARE_STORAGE_UPDATE_MESSAGES_FAILED",
|
|
71
874
|
domain: error.ErrorDomain.STORAGE,
|
|
72
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
875
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
876
|
+
text: "Failed to update messages"
|
|
73
877
|
},
|
|
74
878
|
error$1
|
|
75
879
|
);
|
|
76
880
|
}
|
|
77
881
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (!binding) throw new Error(`No binding found for namespace ${tableName}`);
|
|
84
|
-
return binding;
|
|
85
|
-
}
|
|
86
|
-
async listNamespaces() {
|
|
87
|
-
if (this.bindings) {
|
|
882
|
+
async getResourceById({ resourceId }) {
|
|
883
|
+
try {
|
|
884
|
+
const data = await this.operations.getKV(storage.TABLE_RESOURCES, resourceId);
|
|
885
|
+
if (!data) return null;
|
|
886
|
+
const resource = typeof data === "string" ? JSON.parse(data) : data;
|
|
88
887
|
return {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}))
|
|
888
|
+
...resource,
|
|
889
|
+
createdAt: storage.ensureDate(resource.createdAt),
|
|
890
|
+
updatedAt: storage.ensureDate(resource.updatedAt),
|
|
891
|
+
metadata: this.ensureMetadata(resource.metadata)
|
|
94
892
|
};
|
|
893
|
+
} catch (error$1) {
|
|
894
|
+
const mastraError = new error.MastraError(
|
|
895
|
+
{
|
|
896
|
+
id: "CLOUDFLARE_STORAGE_GET_RESOURCE_BY_ID_FAILED",
|
|
897
|
+
domain: error.ErrorDomain.STORAGE,
|
|
898
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
899
|
+
details: {
|
|
900
|
+
resourceId
|
|
901
|
+
}
|
|
902
|
+
},
|
|
903
|
+
error$1
|
|
904
|
+
);
|
|
905
|
+
this.logger?.trackException(mastraError);
|
|
906
|
+
this.logger?.error(mastraError.toString());
|
|
907
|
+
return null;
|
|
95
908
|
}
|
|
96
|
-
let allNamespaces = [];
|
|
97
|
-
let currentPage = 1;
|
|
98
|
-
const perPage = 50;
|
|
99
|
-
let morePagesExist = true;
|
|
100
|
-
while (morePagesExist) {
|
|
101
|
-
const response = await this.client.kv.namespaces.list({
|
|
102
|
-
account_id: this.accountId,
|
|
103
|
-
page: currentPage,
|
|
104
|
-
per_page: perPage
|
|
105
|
-
});
|
|
106
|
-
if (response.result) {
|
|
107
|
-
allNamespaces = allNamespaces.concat(response.result);
|
|
108
|
-
}
|
|
109
|
-
morePagesExist = response.result ? response.result.length === perPage : false;
|
|
110
|
-
if (morePagesExist) {
|
|
111
|
-
currentPage++;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return { result: allNamespaces };
|
|
115
909
|
}
|
|
116
|
-
async
|
|
910
|
+
async saveResource({ resource }) {
|
|
117
911
|
try {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
912
|
+
const resourceToSave = {
|
|
913
|
+
...resource,
|
|
914
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : null
|
|
915
|
+
};
|
|
916
|
+
await this.operations.putKV({
|
|
917
|
+
tableName: storage.TABLE_RESOURCES,
|
|
918
|
+
key: resource.id,
|
|
919
|
+
value: resourceToSave
|
|
920
|
+
});
|
|
921
|
+
return resource;
|
|
922
|
+
} catch (error$1) {
|
|
923
|
+
throw new error.MastraError(
|
|
924
|
+
{
|
|
925
|
+
id: "CLOUDFLARE_STORAGE_SAVE_RESOURCE_FAILED",
|
|
926
|
+
domain: error.ErrorDomain.STORAGE,
|
|
927
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
928
|
+
details: {
|
|
929
|
+
resourceId: resource.id
|
|
930
|
+
}
|
|
931
|
+
},
|
|
932
|
+
error$1
|
|
933
|
+
);
|
|
137
934
|
}
|
|
138
935
|
}
|
|
139
|
-
async
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
value,
|
|
936
|
+
async updateResource({
|
|
937
|
+
resourceId,
|
|
938
|
+
workingMemory,
|
|
143
939
|
metadata
|
|
144
940
|
}) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
value: serializedValue,
|
|
156
|
-
metadata: serializedMetadata
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
} catch (error) {
|
|
160
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
161
|
-
this.logger.error(`Failed to put value for ${tableName} ${key}:`, { message });
|
|
162
|
-
throw error;
|
|
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 });
|
|
163
951
|
}
|
|
952
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
953
|
+
const updatedResource = {
|
|
954
|
+
...existingResource,
|
|
955
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
956
|
+
metadata: {
|
|
957
|
+
...existingResource.metadata,
|
|
958
|
+
...metadata
|
|
959
|
+
},
|
|
960
|
+
updatedAt
|
|
961
|
+
};
|
|
962
|
+
return this.saveResource({ resource: updatedResource });
|
|
164
963
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
964
|
+
};
|
|
965
|
+
var StoreOperationsCloudflare = class extends storage.StoreOperations {
|
|
966
|
+
bindings;
|
|
967
|
+
client;
|
|
968
|
+
accountId;
|
|
969
|
+
namespacePrefix;
|
|
970
|
+
constructor({
|
|
971
|
+
namespacePrefix,
|
|
972
|
+
bindings,
|
|
973
|
+
client,
|
|
974
|
+
accountId
|
|
975
|
+
}) {
|
|
976
|
+
super();
|
|
977
|
+
this.bindings = bindings;
|
|
978
|
+
this.namespacePrefix = namespacePrefix;
|
|
979
|
+
this.client = client;
|
|
980
|
+
this.accountId = accountId;
|
|
175
981
|
}
|
|
176
|
-
async
|
|
982
|
+
async hasColumn() {
|
|
983
|
+
return true;
|
|
984
|
+
}
|
|
985
|
+
async alterTable(_args) {
|
|
986
|
+
}
|
|
987
|
+
async clearTable({ tableName }) {
|
|
177
988
|
try {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
limit: options?.limit || 1e3,
|
|
182
|
-
prefix: options?.prefix
|
|
183
|
-
});
|
|
184
|
-
return response.keys;
|
|
185
|
-
} else {
|
|
186
|
-
const namespaceId = await this.getNamespaceId(tableName);
|
|
187
|
-
const response = await this.client.kv.namespaces.keys.list(namespaceId, {
|
|
188
|
-
account_id: this.accountId,
|
|
189
|
-
limit: options?.limit || 1e3,
|
|
190
|
-
prefix: options?.prefix
|
|
191
|
-
});
|
|
192
|
-
return response.result;
|
|
989
|
+
const keys = await this.listKV(tableName);
|
|
990
|
+
if (keys.length > 0) {
|
|
991
|
+
await Promise.all(keys.map((keyObj) => this.deleteKV(tableName, keyObj.name)));
|
|
193
992
|
}
|
|
194
993
|
} catch (error$1) {
|
|
195
994
|
throw new error.MastraError(
|
|
196
995
|
{
|
|
197
|
-
id: "
|
|
996
|
+
id: "CLOUDFLARE_STORAGE_CLEAR_TABLE_FAILED",
|
|
198
997
|
domain: error.ErrorDomain.STORAGE,
|
|
199
998
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
200
999
|
details: {
|
|
@@ -205,110 +1004,69 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
205
1004
|
);
|
|
206
1005
|
}
|
|
207
1006
|
}
|
|
208
|
-
async
|
|
209
|
-
if (this.bindings) {
|
|
210
|
-
return {
|
|
211
|
-
id: title,
|
|
212
|
-
// Use title as ID since that's what we need
|
|
213
|
-
title,
|
|
214
|
-
supports_url_encoding: true
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
return await this.client.kv.namespaces.create({
|
|
218
|
-
account_id: this.accountId,
|
|
219
|
-
title
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
async getNamespaceIdByName(namespaceName) {
|
|
223
|
-
try {
|
|
224
|
-
const response = await this.listNamespaces();
|
|
225
|
-
const namespace = response.result.find((ns) => ns.title === namespaceName);
|
|
226
|
-
return namespace ? namespace.id : null;
|
|
227
|
-
} catch (error) {
|
|
228
|
-
this.logger.error(`Failed to get namespace ID for ${namespaceName}:`, error);
|
|
229
|
-
return null;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
async createNamespace(namespaceName) {
|
|
1007
|
+
async dropTable({ tableName }) {
|
|
233
1008
|
try {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (error.message && error.message.includes("already exists")) {
|
|
238
|
-
const namespaces = await this.listNamespaces();
|
|
239
|
-
const namespace = namespaces.result.find((ns) => ns.title === namespaceName);
|
|
240
|
-
if (namespace) return namespace.id;
|
|
1009
|
+
const keys = await this.listKV(tableName);
|
|
1010
|
+
if (keys.length > 0) {
|
|
1011
|
+
await Promise.all(keys.map((keyObj) => this.deleteKV(tableName, keyObj.name)));
|
|
241
1012
|
}
|
|
242
|
-
|
|
243
|
-
throw new
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
1013
|
+
} catch (error$1) {
|
|
1014
|
+
throw new error.MastraError(
|
|
1015
|
+
{
|
|
1016
|
+
id: "CLOUDFLARE_STORAGE_DROP_TABLE_FAILED",
|
|
1017
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1018
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1019
|
+
details: {
|
|
1020
|
+
tableName
|
|
1021
|
+
}
|
|
1022
|
+
},
|
|
1023
|
+
error$1
|
|
1024
|
+
);
|
|
250
1025
|
}
|
|
251
|
-
return namespaceId;
|
|
252
1026
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const legacyNamespaceId = await this.checkLegacyNamespace(tableName, prefix);
|
|
257
|
-
if (legacyNamespaceId) {
|
|
258
|
-
return legacyNamespaceId;
|
|
259
|
-
}
|
|
260
|
-
return await this.getOrCreateNamespaceId(`${prefix}${tableName}`);
|
|
261
|
-
} catch (error) {
|
|
262
|
-
this.logger.error("Error fetching namespace ID:", error);
|
|
263
|
-
throw new Error(`Failed to fetch namespace ID for table ${tableName}: ${error.message}`);
|
|
1027
|
+
getBinding(tableName) {
|
|
1028
|
+
if (!this.bindings) {
|
|
1029
|
+
throw new Error(`Cannot use Workers API binding for ${tableName}: Store initialized with REST API configuration`);
|
|
264
1030
|
}
|
|
1031
|
+
const binding = this.bindings[tableName];
|
|
1032
|
+
if (!binding) throw new Error(`No binding found for namespace ${tableName}`);
|
|
1033
|
+
return binding;
|
|
265
1034
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
*
|
|
279
|
-
* @param tableName The table name to check for legacy data
|
|
280
|
-
* @param prefix The namespace prefix
|
|
281
|
-
* @returns The legacy namespace ID if data exists; otherwise, null
|
|
282
|
-
*/
|
|
283
|
-
async checkLegacyNamespace(tableName, prefix) {
|
|
284
|
-
const legacyNamespaceBase = this.LEGACY_NAMESPACE_MAP[tableName];
|
|
285
|
-
if (legacyNamespaceBase) {
|
|
286
|
-
const legacyNamespace = `${prefix}${legacyNamespaceBase}`;
|
|
287
|
-
const keyPrefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
288
|
-
const prefixKey = `${keyPrefix}${tableName}:`;
|
|
289
|
-
const legacyId = await this.getNamespaceIdByName(legacyNamespace);
|
|
290
|
-
if (legacyId) {
|
|
291
|
-
const response = await this.client.kv.namespaces.keys.list(legacyId, {
|
|
292
|
-
account_id: this.accountId,
|
|
293
|
-
prefix: prefixKey
|
|
294
|
-
});
|
|
295
|
-
const keys = response.result;
|
|
296
|
-
const hasTableData = keys.length > 0;
|
|
297
|
-
if (hasTableData) {
|
|
298
|
-
this.logger.warn(
|
|
299
|
-
`Using legacy namespace "${legacyNamespace}" for ${tableName}. Consider migrating to a dedicated namespace "${prefix}${tableName}".`
|
|
300
|
-
);
|
|
301
|
-
return legacyId;
|
|
1035
|
+
getKey(tableName, record) {
|
|
1036
|
+
const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
1037
|
+
switch (tableName) {
|
|
1038
|
+
case storage.TABLE_THREADS:
|
|
1039
|
+
if (!record.id) throw new Error("Thread ID is required");
|
|
1040
|
+
return `${prefix}${tableName}:${record.id}`;
|
|
1041
|
+
case storage.TABLE_MESSAGES:
|
|
1042
|
+
if (!record.threadId || !record.id) throw new Error("Thread ID and Message ID are required");
|
|
1043
|
+
return `${prefix}${tableName}:${record.threadId}:${record.id}`;
|
|
1044
|
+
case storage.TABLE_WORKFLOW_SNAPSHOT:
|
|
1045
|
+
if (!record.workflow_name || !record.run_id) {
|
|
1046
|
+
throw new Error("Workflow name, and run ID are required");
|
|
302
1047
|
}
|
|
303
|
-
|
|
1048
|
+
let key = `${prefix}${tableName}:${record.workflow_name}:${record.run_id}`;
|
|
1049
|
+
if (record.resourceId) {
|
|
1050
|
+
key = `${key}:${record.resourceId}`;
|
|
1051
|
+
}
|
|
1052
|
+
return key;
|
|
1053
|
+
case storage.TABLE_TRACES:
|
|
1054
|
+
if (!record.id) throw new Error("Trace ID is required");
|
|
1055
|
+
return `${prefix}${tableName}:${record.id}`;
|
|
1056
|
+
case storage.TABLE_EVALS:
|
|
1057
|
+
const evalId = record.id || record.run_id;
|
|
1058
|
+
if (!evalId) throw new Error("Eval ID or run_id is required");
|
|
1059
|
+
return `${prefix}${tableName}:${evalId}`;
|
|
1060
|
+
case storage.TABLE_SCORERS:
|
|
1061
|
+
if (!record.id) throw new Error("Score ID is required");
|
|
1062
|
+
return `${prefix}${tableName}:${record.id}`;
|
|
1063
|
+
default:
|
|
1064
|
+
throw new Error(`Unsupported table: ${tableName}`);
|
|
304
1065
|
}
|
|
305
|
-
return null;
|
|
306
1066
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
safeSerialize(data) {
|
|
311
|
-
return typeof data === "string" ? data : JSON.stringify(data);
|
|
1067
|
+
getSchemaKey(tableName) {
|
|
1068
|
+
const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
1069
|
+
return `${prefix}schema:${tableName}`;
|
|
312
1070
|
}
|
|
313
1071
|
/**
|
|
314
1072
|
* Helper to safely parse data from KV storage
|
|
@@ -334,203 +1092,121 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
334
1092
|
return null;
|
|
335
1093
|
}
|
|
336
1094
|
}
|
|
337
|
-
async
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
} catch (error) {
|
|
346
|
-
this.logger.error(`Failed to put KV value for ${tableName}:${key}:`, error);
|
|
347
|
-
throw new Error(`Failed to put KV value: ${error.message}`);
|
|
1095
|
+
async createNamespaceById(title) {
|
|
1096
|
+
if (this.bindings) {
|
|
1097
|
+
return {
|
|
1098
|
+
id: title,
|
|
1099
|
+
// Use title as ID since that's what we need
|
|
1100
|
+
title,
|
|
1101
|
+
supports_url_encoding: true
|
|
1102
|
+
};
|
|
348
1103
|
}
|
|
1104
|
+
return await this.client.kv.namespaces.create({
|
|
1105
|
+
account_id: this.accountId,
|
|
1106
|
+
title
|
|
1107
|
+
});
|
|
349
1108
|
}
|
|
350
|
-
async
|
|
1109
|
+
async createNamespace(namespaceName) {
|
|
351
1110
|
try {
|
|
352
|
-
const
|
|
353
|
-
return
|
|
1111
|
+
const response = await this.createNamespaceById(namespaceName);
|
|
1112
|
+
return response.id;
|
|
354
1113
|
} catch (error) {
|
|
355
|
-
|
|
356
|
-
|
|
1114
|
+
if (error.message && error.message.includes("already exists")) {
|
|
1115
|
+
const namespaces = await this.listNamespaces();
|
|
1116
|
+
const namespace = namespaces.result.find((ns) => ns.title === namespaceName);
|
|
1117
|
+
if (namespace) return namespace.id;
|
|
1118
|
+
}
|
|
1119
|
+
this.logger.error("Error creating namespace:", error);
|
|
1120
|
+
throw new Error(`Failed to create namespace ${namespaceName}: ${error.message}`);
|
|
357
1121
|
}
|
|
358
1122
|
}
|
|
359
|
-
async
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
1123
|
+
async listNamespaces() {
|
|
1124
|
+
if (this.bindings) {
|
|
1125
|
+
return {
|
|
1126
|
+
result: Object.keys(this.bindings).map((name) => ({
|
|
1127
|
+
id: name,
|
|
1128
|
+
title: name,
|
|
1129
|
+
supports_url_encoding: true
|
|
1130
|
+
}))
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
let allNamespaces = [];
|
|
1134
|
+
let currentPage = 1;
|
|
1135
|
+
const perPage = 50;
|
|
1136
|
+
let morePagesExist = true;
|
|
1137
|
+
while (morePagesExist) {
|
|
1138
|
+
const response = await this.client.kv.namespaces.list({
|
|
1139
|
+
account_id: this.accountId,
|
|
1140
|
+
page: currentPage,
|
|
1141
|
+
per_page: perPage
|
|
1142
|
+
});
|
|
1143
|
+
if (response.result) {
|
|
1144
|
+
allNamespaces = allNamespaces.concat(response.result);
|
|
1145
|
+
}
|
|
1146
|
+
morePagesExist = response.result ? response.result.length === perPage : false;
|
|
1147
|
+
if (morePagesExist) {
|
|
1148
|
+
currentPage++;
|
|
1149
|
+
}
|
|
365
1150
|
}
|
|
1151
|
+
return { result: allNamespaces };
|
|
366
1152
|
}
|
|
367
|
-
async
|
|
1153
|
+
async getNamespaceIdByName(namespaceName) {
|
|
368
1154
|
try {
|
|
369
|
-
|
|
1155
|
+
const response = await this.listNamespaces();
|
|
1156
|
+
const namespace = response.result.find((ns) => ns.title === namespaceName);
|
|
1157
|
+
return namespace ? namespace.id : null;
|
|
370
1158
|
} catch (error) {
|
|
371
|
-
this.logger.error(`Failed to
|
|
372
|
-
|
|
1159
|
+
this.logger.error(`Failed to get namespace ID for ${namespaceName}:`, error);
|
|
1160
|
+
return null;
|
|
373
1161
|
}
|
|
374
1162
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
async getSortedMessages(orderKey) {
|
|
380
|
-
const raw = await this.getKV(storage.TABLE_MESSAGES, orderKey);
|
|
381
|
-
if (!raw) return [];
|
|
382
|
-
try {
|
|
383
|
-
const arr = JSON.parse(typeof raw === "string" ? raw : JSON.stringify(raw));
|
|
384
|
-
return Array.isArray(arr) ? arr : [];
|
|
385
|
-
} catch (e) {
|
|
386
|
-
this.logger.error(`Error parsing order data for key ${orderKey}:`, { e });
|
|
387
|
-
return [];
|
|
1163
|
+
async getOrCreateNamespaceId(namespaceName) {
|
|
1164
|
+
let namespaceId = await this.getNamespaceIdByName(namespaceName);
|
|
1165
|
+
if (!namespaceId) {
|
|
1166
|
+
namespaceId = await this.createNamespace(namespaceName);
|
|
388
1167
|
}
|
|
1168
|
+
return namespaceId;
|
|
389
1169
|
}
|
|
390
|
-
async
|
|
391
|
-
|
|
392
|
-
message: msg,
|
|
393
|
-
// Use _index if available, otherwise timestamp, matching Upstash
|
|
394
|
-
score: msg._index !== void 0 ? msg._index : msg.createdAt.getTime()
|
|
395
|
-
})).sort((a, b) => a.score - b.score).map((item) => ({
|
|
396
|
-
id: item.message.id,
|
|
397
|
-
score: item.score
|
|
398
|
-
}));
|
|
399
|
-
}
|
|
400
|
-
async getIncludedMessagesWithContext(threadId, include, messageIds) {
|
|
401
|
-
const threadMessagesKey = this.getThreadMessagesKey(threadId);
|
|
402
|
-
await Promise.all(
|
|
403
|
-
include.map(async (item) => {
|
|
404
|
-
messageIds.add(item.id);
|
|
405
|
-
if (!item.withPreviousMessages && !item.withNextMessages) return;
|
|
406
|
-
const rank = await this.getRank(threadMessagesKey, item.id);
|
|
407
|
-
if (rank === null) return;
|
|
408
|
-
if (item.withPreviousMessages) {
|
|
409
|
-
const prevIds = await this.getRange(
|
|
410
|
-
threadMessagesKey,
|
|
411
|
-
Math.max(0, rank - item.withPreviousMessages),
|
|
412
|
-
rank - 1
|
|
413
|
-
);
|
|
414
|
-
prevIds.forEach((id) => messageIds.add(id));
|
|
415
|
-
}
|
|
416
|
-
if (item.withNextMessages) {
|
|
417
|
-
const nextIds = await this.getRange(threadMessagesKey, rank + 1, rank + item.withNextMessages);
|
|
418
|
-
nextIds.forEach((id) => messageIds.add(id));
|
|
419
|
-
}
|
|
420
|
-
})
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
async getRecentMessages(threadId, limit, messageIds) {
|
|
424
|
-
if (limit <= 0) return;
|
|
1170
|
+
async getNamespaceId(tableName) {
|
|
1171
|
+
const prefix = this.namespacePrefix ? `${this.namespacePrefix}_` : "";
|
|
425
1172
|
try {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
console.log(`No message order found for thread ${threadId}, skipping latest messages`);
|
|
1173
|
+
return await this.getOrCreateNamespaceId(`${prefix}${tableName}`);
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
this.logger.error("Error fetching namespace ID:", error);
|
|
1176
|
+
throw new Error(`Failed to fetch namespace ID for table ${tableName}: ${error.message}`);
|
|
431
1177
|
}
|
|
432
1178
|
}
|
|
433
|
-
async
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
this.
|
|
444
|
-
return null;
|
|
445
|
-
}
|
|
446
|
-
})
|
|
447
|
-
);
|
|
448
|
-
return messages.filter((msg) => msg !== null);
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Queue for serializing sorted order updates.
|
|
452
|
-
* Updates the sorted order for a given key. This operation is eventually consistent.
|
|
453
|
-
*/
|
|
454
|
-
updateQueue = /* @__PURE__ */ new Map();
|
|
455
|
-
/**
|
|
456
|
-
* Updates the sorted order for a given key. This operation is eventually consistent.
|
|
457
|
-
* Note: Operations on the same orderKey are serialized using a queue to prevent
|
|
458
|
-
* concurrent updates from conflicting with each other.
|
|
459
|
-
*/
|
|
460
|
-
async updateSortedMessages(orderKey, newEntries) {
|
|
461
|
-
const currentPromise = this.updateQueue.get(orderKey) || Promise.resolve();
|
|
462
|
-
const nextPromise = currentPromise.then(async () => {
|
|
463
|
-
try {
|
|
464
|
-
const currentOrder = await this.getSortedMessages(orderKey);
|
|
465
|
-
const orderMap = new Map(currentOrder.map((entry) => [entry.id, entry]));
|
|
466
|
-
for (const entry of newEntries) {
|
|
467
|
-
orderMap.set(entry.id, entry);
|
|
468
|
-
}
|
|
469
|
-
const updatedOrder = Array.from(orderMap.values()).sort((a, b) => a.score - b.score);
|
|
470
|
-
await this.putKV({
|
|
471
|
-
tableName: storage.TABLE_MESSAGES,
|
|
472
|
-
key: orderKey,
|
|
473
|
-
value: JSON.stringify(updatedOrder)
|
|
1179
|
+
async getNamespaceValue(tableName, key) {
|
|
1180
|
+
try {
|
|
1181
|
+
if (this.bindings) {
|
|
1182
|
+
const binding = this.getBinding(tableName);
|
|
1183
|
+
const result = await binding.getWithMetadata(key, "text");
|
|
1184
|
+
if (!result) return null;
|
|
1185
|
+
return JSON.stringify(result);
|
|
1186
|
+
} else {
|
|
1187
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
1188
|
+
const response = await this.client.kv.namespaces.values.get(namespaceId, key, {
|
|
1189
|
+
account_id: this.accountId
|
|
474
1190
|
});
|
|
475
|
-
|
|
476
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
477
|
-
this.logger.error(`Error updating sorted order for key ${orderKey}:`, { message });
|
|
478
|
-
throw error;
|
|
479
|
-
} finally {
|
|
480
|
-
if (this.updateQueue.get(orderKey) === nextPromise) {
|
|
481
|
-
this.updateQueue.delete(orderKey);
|
|
482
|
-
}
|
|
1191
|
+
return await response.text();
|
|
483
1192
|
}
|
|
484
|
-
})
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
return index >= 0 ? index : null;
|
|
492
|
-
}
|
|
493
|
-
async getRange(orderKey, start, end) {
|
|
494
|
-
const order = await this.getSortedMessages(orderKey);
|
|
495
|
-
const actualStart = start < 0 ? Math.max(0, order.length + start) : start;
|
|
496
|
-
const actualEnd = end < 0 ? order.length + end : Math.min(end, order.length - 1);
|
|
497
|
-
const sliced = order.slice(actualStart, actualEnd + 1);
|
|
498
|
-
return sliced.map((item) => item.id);
|
|
499
|
-
}
|
|
500
|
-
async getLastN(orderKey, n) {
|
|
501
|
-
return this.getRange(orderKey, -n, -1);
|
|
502
|
-
}
|
|
503
|
-
async getFullOrder(orderKey) {
|
|
504
|
-
return this.getRange(orderKey, 0, -1);
|
|
505
|
-
}
|
|
506
|
-
getKey(tableName, record) {
|
|
507
|
-
const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
508
|
-
switch (tableName) {
|
|
509
|
-
case storage.TABLE_THREADS:
|
|
510
|
-
if (!record.id) throw new Error("Thread ID is required");
|
|
511
|
-
return `${prefix}${tableName}:${record.id}`;
|
|
512
|
-
case storage.TABLE_MESSAGES:
|
|
513
|
-
if (!record.threadId || !record.id) throw new Error("Thread ID and Message ID are required");
|
|
514
|
-
return `${prefix}${tableName}:${record.threadId}:${record.id}`;
|
|
515
|
-
case storage.TABLE_WORKFLOW_SNAPSHOT:
|
|
516
|
-
if (!record.namespace || !record.workflow_name || !record.run_id) {
|
|
517
|
-
throw new Error("Namespace, workflow name, and run ID are required");
|
|
518
|
-
}
|
|
519
|
-
let key = `${prefix}${tableName}:${record.namespace}:${record.workflow_name}:${record.run_id}`;
|
|
520
|
-
if (record.resourceId) {
|
|
521
|
-
key = `${key}:${record.resourceId}`;
|
|
522
|
-
}
|
|
523
|
-
return key;
|
|
524
|
-
case storage.TABLE_TRACES:
|
|
525
|
-
if (!record.id) throw new Error("Trace ID is required");
|
|
526
|
-
return `${prefix}${tableName}:${record.id}`;
|
|
527
|
-
default:
|
|
528
|
-
throw new Error(`Unsupported table: ${tableName}`);
|
|
1193
|
+
} catch (error) {
|
|
1194
|
+
if (error.message && error.message.includes("key not found")) {
|
|
1195
|
+
return null;
|
|
1196
|
+
}
|
|
1197
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1198
|
+
this.logger.error(`Failed to get value for ${tableName} ${key}:`, { message });
|
|
1199
|
+
throw error;
|
|
529
1200
|
}
|
|
530
1201
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
1202
|
+
async getKV(tableName, key) {
|
|
1203
|
+
try {
|
|
1204
|
+
const text = await this.getNamespaceValue(tableName, key);
|
|
1205
|
+
return this.safeParse(text);
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
this.logger.error(`Failed to get KV value for ${tableName}:${key}:`, error);
|
|
1208
|
+
throw new Error(`Failed to get KV value: ${error.message}`);
|
|
1209
|
+
}
|
|
534
1210
|
}
|
|
535
1211
|
async getTableSchema(tableName) {
|
|
536
1212
|
try {
|
|
@@ -611,7 +1287,7 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
611
1287
|
}
|
|
612
1288
|
break;
|
|
613
1289
|
case storage.TABLE_WORKFLOW_SNAPSHOT:
|
|
614
|
-
if (!("
|
|
1290
|
+
if (!("workflow_name" in recordTyped) || !("run_id" in recordTyped)) {
|
|
615
1291
|
throw new Error("Workflow record missing required fields");
|
|
616
1292
|
}
|
|
617
1293
|
break;
|
|
@@ -620,6 +1296,16 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
620
1296
|
throw new Error("Trace record missing required fields");
|
|
621
1297
|
}
|
|
622
1298
|
break;
|
|
1299
|
+
case storage.TABLE_EVALS:
|
|
1300
|
+
if (!("agent_name" in recordTyped) || !("run_id" in recordTyped)) {
|
|
1301
|
+
throw new Error("Eval record missing required fields");
|
|
1302
|
+
}
|
|
1303
|
+
break;
|
|
1304
|
+
case storage.TABLE_SCORERS:
|
|
1305
|
+
if (!("id" in recordTyped) || !("scorerId" in recordTyped)) {
|
|
1306
|
+
throw new Error("Score record missing required fields");
|
|
1307
|
+
}
|
|
1308
|
+
break;
|
|
623
1309
|
default:
|
|
624
1310
|
throw new Error(`Unknown table type: ${tableName}`);
|
|
625
1311
|
}
|
|
@@ -629,26 +1315,21 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
629
1315
|
throw error;
|
|
630
1316
|
}
|
|
631
1317
|
}
|
|
632
|
-
|
|
633
|
-
if (!metadata) return {};
|
|
634
|
-
return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
|
|
635
|
-
}
|
|
636
|
-
async createTable({
|
|
637
|
-
tableName,
|
|
638
|
-
schema
|
|
639
|
-
}) {
|
|
1318
|
+
async insert({ tableName, record }) {
|
|
640
1319
|
try {
|
|
641
|
-
const
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
1320
|
+
const key = this.getKey(tableName, record);
|
|
1321
|
+
const processedRecord = {
|
|
1322
|
+
...record,
|
|
1323
|
+
createdAt: record.createdAt ? storage.serializeDate(record.createdAt) : void 0,
|
|
1324
|
+
updatedAt: record.updatedAt ? storage.serializeDate(record.updatedAt) : void 0,
|
|
1325
|
+
metadata: record.metadata ? JSON.stringify(record.metadata) : ""
|
|
646
1326
|
};
|
|
647
|
-
await this.
|
|
1327
|
+
await this.validateRecord(processedRecord, tableName);
|
|
1328
|
+
await this.putKV({ tableName, key, value: processedRecord });
|
|
648
1329
|
} catch (error$1) {
|
|
649
1330
|
throw new error.MastraError(
|
|
650
1331
|
{
|
|
651
|
-
id: "
|
|
1332
|
+
id: "CLOUDFLARE_STORAGE_INSERT_FAILED",
|
|
652
1333
|
domain: error.ErrorDomain.STORAGE,
|
|
653
1334
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
654
1335
|
details: {
|
|
@@ -659,24 +1340,26 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
659
1340
|
);
|
|
660
1341
|
}
|
|
661
1342
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
* @param schema Schema of the table
|
|
666
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
667
|
-
*/
|
|
668
|
-
async alterTable(_args) {
|
|
1343
|
+
ensureMetadata(metadata) {
|
|
1344
|
+
if (!metadata) return {};
|
|
1345
|
+
return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
|
|
669
1346
|
}
|
|
670
|
-
async
|
|
1347
|
+
async load({ tableName, keys }) {
|
|
671
1348
|
try {
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
1349
|
+
const key = this.getKey(tableName, keys);
|
|
1350
|
+
const data = await this.getKV(tableName, key);
|
|
1351
|
+
if (!data) return null;
|
|
1352
|
+
const processed = {
|
|
1353
|
+
...data,
|
|
1354
|
+
createdAt: storage.ensureDate(data.createdAt),
|
|
1355
|
+
updatedAt: storage.ensureDate(data.updatedAt),
|
|
1356
|
+
metadata: this.ensureMetadata(data.metadata)
|
|
1357
|
+
};
|
|
1358
|
+
return processed;
|
|
676
1359
|
} catch (error$1) {
|
|
677
|
-
|
|
1360
|
+
const mastraError = new error.MastraError(
|
|
678
1361
|
{
|
|
679
|
-
id: "
|
|
1362
|
+
id: "CLOUDFLARE_STORAGE_LOAD_FAILED",
|
|
680
1363
|
domain: error.ErrorDomain.STORAGE,
|
|
681
1364
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
682
1365
|
details: {
|
|
@@ -685,52 +1368,102 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
685
1368
|
},
|
|
686
1369
|
error$1
|
|
687
1370
|
);
|
|
1371
|
+
this.logger?.trackException(mastraError);
|
|
1372
|
+
this.logger?.error(mastraError.toString());
|
|
1373
|
+
return null;
|
|
688
1374
|
}
|
|
689
1375
|
}
|
|
690
|
-
async
|
|
691
|
-
|
|
692
|
-
record
|
|
693
|
-
}) {
|
|
1376
|
+
async batchInsert(input) {
|
|
1377
|
+
if (!input.records || input.records.length === 0) return;
|
|
694
1378
|
try {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
1379
|
+
await Promise.all(
|
|
1380
|
+
input.records.map(async (record) => {
|
|
1381
|
+
const key = this.getKey(input.tableName, record);
|
|
1382
|
+
const processedRecord = {
|
|
1383
|
+
...record,
|
|
1384
|
+
createdAt: record.createdAt ? storage.serializeDate(record.createdAt) : void 0,
|
|
1385
|
+
updatedAt: record.updatedAt ? storage.serializeDate(record.updatedAt) : void 0,
|
|
1386
|
+
metadata: record.metadata ? JSON.stringify(record.metadata) : void 0
|
|
1387
|
+
};
|
|
1388
|
+
await this.putKV({ tableName: input.tableName, key, value: processedRecord });
|
|
1389
|
+
})
|
|
1390
|
+
);
|
|
704
1391
|
} catch (error$1) {
|
|
705
1392
|
throw new error.MastraError(
|
|
706
1393
|
{
|
|
707
|
-
id: "
|
|
1394
|
+
id: "CLOUDFLARE_STORAGE_BATCH_INSERT_FAILED",
|
|
708
1395
|
domain: error.ErrorDomain.STORAGE,
|
|
709
1396
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1397
|
+
text: `Error in batch insert for table ${input.tableName}`,
|
|
710
1398
|
details: {
|
|
711
|
-
tableName
|
|
1399
|
+
tableName: input.tableName
|
|
712
1400
|
}
|
|
713
1401
|
},
|
|
714
1402
|
error$1
|
|
715
1403
|
);
|
|
716
1404
|
}
|
|
717
1405
|
}
|
|
718
|
-
|
|
1406
|
+
/**
|
|
1407
|
+
* Helper to safely serialize data for KV storage
|
|
1408
|
+
*/
|
|
1409
|
+
safeSerialize(data) {
|
|
1410
|
+
return typeof data === "string" ? data : JSON.stringify(data);
|
|
1411
|
+
}
|
|
1412
|
+
async putNamespaceValue({
|
|
1413
|
+
tableName,
|
|
1414
|
+
key,
|
|
1415
|
+
value,
|
|
1416
|
+
metadata
|
|
1417
|
+
}) {
|
|
719
1418
|
try {
|
|
720
|
-
const
|
|
721
|
-
const
|
|
722
|
-
if (
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1419
|
+
const serializedValue = this.safeSerialize(value);
|
|
1420
|
+
const serializedMetadata = metadata ? this.safeSerialize(metadata) : "";
|
|
1421
|
+
if (this.bindings) {
|
|
1422
|
+
const binding = this.getBinding(tableName);
|
|
1423
|
+
await binding.put(key, serializedValue, { metadata: serializedMetadata });
|
|
1424
|
+
} else {
|
|
1425
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
1426
|
+
await this.client.kv.namespaces.values.update(namespaceId, key, {
|
|
1427
|
+
account_id: this.accountId,
|
|
1428
|
+
value: serializedValue,
|
|
1429
|
+
metadata: serializedMetadata
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
} catch (error) {
|
|
1433
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1434
|
+
this.logger.error(`Failed to put value for ${tableName} ${key}:`, { message });
|
|
1435
|
+
throw error;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
async putKV({
|
|
1439
|
+
tableName,
|
|
1440
|
+
key,
|
|
1441
|
+
value,
|
|
1442
|
+
metadata
|
|
1443
|
+
}) {
|
|
1444
|
+
try {
|
|
1445
|
+
await this.putNamespaceValue({ tableName, key, value, metadata });
|
|
1446
|
+
} catch (error) {
|
|
1447
|
+
this.logger.error(`Failed to put KV value for ${tableName}:${key}:`, error);
|
|
1448
|
+
throw new Error(`Failed to put KV value: ${error.message}`);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
async createTable({
|
|
1452
|
+
tableName,
|
|
1453
|
+
schema
|
|
1454
|
+
}) {
|
|
1455
|
+
try {
|
|
1456
|
+
const schemaKey = this.getSchemaKey(tableName);
|
|
1457
|
+
const metadata = {
|
|
1458
|
+
type: "table_schema",
|
|
1459
|
+
tableName,
|
|
1460
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
728
1461
|
};
|
|
729
|
-
|
|
1462
|
+
await this.putKV({ tableName, key: schemaKey, value: schema, metadata });
|
|
730
1463
|
} catch (error$1) {
|
|
731
|
-
|
|
1464
|
+
throw new error.MastraError(
|
|
732
1465
|
{
|
|
733
|
-
id: "
|
|
1466
|
+
id: "CLOUDFLARE_STORAGE_CREATE_TABLE_FAILED",
|
|
734
1467
|
domain: error.ErrorDomain.STORAGE,
|
|
735
1468
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
736
1469
|
details: {
|
|
@@ -739,395 +1472,432 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
739
1472
|
},
|
|
740
1473
|
error$1
|
|
741
1474
|
);
|
|
742
|
-
this.logger?.trackException(mastraError);
|
|
743
|
-
this.logger?.error(mastraError.toString());
|
|
744
|
-
return null;
|
|
745
1475
|
}
|
|
746
1476
|
}
|
|
747
|
-
async
|
|
748
|
-
const thread = await this.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
|
|
749
|
-
if (!thread) return null;
|
|
1477
|
+
async listNamespaceKeys(tableName, options) {
|
|
750
1478
|
try {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
1479
|
+
if (this.bindings) {
|
|
1480
|
+
const binding = this.getBinding(tableName);
|
|
1481
|
+
const response = await binding.list({
|
|
1482
|
+
limit: options?.limit || 1e3,
|
|
1483
|
+
prefix: options?.prefix
|
|
1484
|
+
});
|
|
1485
|
+
return response.keys;
|
|
1486
|
+
} else {
|
|
1487
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
1488
|
+
const response = await this.client.kv.namespaces.keys.list(namespaceId, {
|
|
1489
|
+
account_id: this.accountId,
|
|
1490
|
+
limit: options?.limit || 1e3,
|
|
1491
|
+
prefix: options?.prefix
|
|
1492
|
+
});
|
|
1493
|
+
return response.result;
|
|
1494
|
+
}
|
|
757
1495
|
} catch (error$1) {
|
|
758
|
-
|
|
1496
|
+
throw new error.MastraError(
|
|
759
1497
|
{
|
|
760
|
-
id: "
|
|
1498
|
+
id: "CLOUDFLARE_STORAGE_LIST_NAMESPACE_KEYS_FAILED",
|
|
761
1499
|
domain: error.ErrorDomain.STORAGE,
|
|
762
1500
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
763
1501
|
details: {
|
|
764
|
-
|
|
1502
|
+
tableName
|
|
765
1503
|
}
|
|
766
1504
|
},
|
|
767
1505
|
error$1
|
|
768
1506
|
);
|
|
769
|
-
this.logger?.trackException(mastraError);
|
|
770
|
-
this.logger?.error(mastraError.toString());
|
|
771
|
-
return null;
|
|
772
1507
|
}
|
|
773
1508
|
}
|
|
774
|
-
async
|
|
1509
|
+
async deleteNamespaceValue(tableName, key) {
|
|
1510
|
+
if (this.bindings) {
|
|
1511
|
+
const binding = this.getBinding(tableName);
|
|
1512
|
+
await binding.delete(key);
|
|
1513
|
+
} else {
|
|
1514
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
1515
|
+
await this.client.kv.namespaces.values.delete(namespaceId, key, {
|
|
1516
|
+
account_id: this.accountId
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
async deleteKV(tableName, key) {
|
|
775
1521
|
try {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1522
|
+
await this.deleteNamespaceValue(tableName, key);
|
|
1523
|
+
} catch (error) {
|
|
1524
|
+
this.logger.error(`Failed to delete KV value for ${tableName}:${key}:`, error);
|
|
1525
|
+
throw new Error(`Failed to delete KV value: ${error.message}`);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
async listKV(tableName, options) {
|
|
1529
|
+
try {
|
|
1530
|
+
return await this.listNamespaceKeys(tableName, options);
|
|
1531
|
+
} catch (error) {
|
|
1532
|
+
this.logger.error(`Failed to list KV for ${tableName}:`, error);
|
|
1533
|
+
throw new Error(`Failed to list KV: ${error.message}`);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
function transformScoreRow(row) {
|
|
1538
|
+
let input = void 0;
|
|
1539
|
+
if (row.input) {
|
|
1540
|
+
try {
|
|
1541
|
+
input = JSON.parse(row.input);
|
|
1542
|
+
} catch {
|
|
1543
|
+
input = row.input;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
return {
|
|
1547
|
+
...row,
|
|
1548
|
+
input
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
1552
|
+
operations;
|
|
1553
|
+
constructor({ operations }) {
|
|
1554
|
+
super();
|
|
1555
|
+
this.operations = operations;
|
|
1556
|
+
}
|
|
1557
|
+
async getScoreById({ id }) {
|
|
1558
|
+
try {
|
|
1559
|
+
const score = await this.operations.getKV(storage.TABLE_SCORERS, id);
|
|
1560
|
+
if (!score) {
|
|
1561
|
+
return null;
|
|
1562
|
+
}
|
|
1563
|
+
return transformScoreRow(score);
|
|
809
1564
|
} catch (error$1) {
|
|
810
1565
|
const mastraError = new error.MastraError(
|
|
811
1566
|
{
|
|
812
|
-
id: "
|
|
1567
|
+
id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORE_BY_ID_FAILED",
|
|
813
1568
|
domain: error.ErrorDomain.STORAGE,
|
|
814
1569
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
815
|
-
|
|
816
|
-
resourceId
|
|
817
|
-
}
|
|
1570
|
+
text: `Failed to get score by id: ${id}`
|
|
818
1571
|
},
|
|
819
1572
|
error$1
|
|
820
1573
|
);
|
|
821
|
-
this.logger
|
|
822
|
-
this.logger
|
|
823
|
-
return
|
|
1574
|
+
this.logger.trackException(mastraError);
|
|
1575
|
+
this.logger.error(mastraError.toString());
|
|
1576
|
+
return null;
|
|
824
1577
|
}
|
|
825
1578
|
}
|
|
826
|
-
async
|
|
1579
|
+
async saveScore(score) {
|
|
827
1580
|
try {
|
|
828
|
-
|
|
829
|
-
|
|
1581
|
+
const { input, ...rest } = score;
|
|
1582
|
+
const serializedRecord = {};
|
|
1583
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
1584
|
+
if (value !== null && value !== void 0) {
|
|
1585
|
+
if (typeof value === "object") {
|
|
1586
|
+
serializedRecord[key] = JSON.stringify(value);
|
|
1587
|
+
} else {
|
|
1588
|
+
serializedRecord[key] = value;
|
|
1589
|
+
}
|
|
1590
|
+
} else {
|
|
1591
|
+
serializedRecord[key] = null;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
serializedRecord.input = JSON.stringify(input);
|
|
1595
|
+
serializedRecord.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1596
|
+
serializedRecord.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1597
|
+
await this.operations.putKV({
|
|
1598
|
+
tableName: storage.TABLE_SCORERS,
|
|
1599
|
+
key: score.id,
|
|
1600
|
+
value: serializedRecord
|
|
1601
|
+
});
|
|
1602
|
+
const scoreFromDb = await this.getScoreById({ id: score.id });
|
|
1603
|
+
return { score: scoreFromDb };
|
|
830
1604
|
} catch (error$1) {
|
|
831
|
-
|
|
1605
|
+
const mastraError = new error.MastraError(
|
|
832
1606
|
{
|
|
833
|
-
id: "
|
|
1607
|
+
id: "CLOUDFLARE_STORAGE_SCORES_SAVE_SCORE_FAILED",
|
|
834
1608
|
domain: error.ErrorDomain.STORAGE,
|
|
835
1609
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
836
|
-
|
|
837
|
-
threadId: thread.id
|
|
838
|
-
}
|
|
1610
|
+
text: `Failed to save score: ${score.id}`
|
|
839
1611
|
},
|
|
840
1612
|
error$1
|
|
841
1613
|
);
|
|
1614
|
+
this.logger.trackException(mastraError);
|
|
1615
|
+
this.logger.error(mastraError.toString());
|
|
1616
|
+
throw mastraError;
|
|
842
1617
|
}
|
|
843
1618
|
}
|
|
844
|
-
async
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
metadata
|
|
1619
|
+
async getScoresByScorerId({
|
|
1620
|
+
scorerId,
|
|
1621
|
+
pagination
|
|
848
1622
|
}) {
|
|
849
1623
|
try {
|
|
850
|
-
const
|
|
851
|
-
|
|
852
|
-
|
|
1624
|
+
const keys = await this.operations.listKV(storage.TABLE_SCORERS);
|
|
1625
|
+
const scores = [];
|
|
1626
|
+
for (const { name: key } of keys) {
|
|
1627
|
+
const score = await this.operations.getKV(storage.TABLE_SCORERS, key);
|
|
1628
|
+
if (score && score.scorerId === scorerId) {
|
|
1629
|
+
scores.push(transformScoreRow(score));
|
|
1630
|
+
}
|
|
853
1631
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
1632
|
+
scores.sort((a, b) => {
|
|
1633
|
+
const dateA = new Date(a.createdAt || 0).getTime();
|
|
1634
|
+
const dateB = new Date(b.createdAt || 0).getTime();
|
|
1635
|
+
return dateB - dateA;
|
|
1636
|
+
});
|
|
1637
|
+
const total = scores.length;
|
|
1638
|
+
const start = pagination.page * pagination.perPage;
|
|
1639
|
+
const end = start + pagination.perPage;
|
|
1640
|
+
const pagedScores = scores.slice(start, end);
|
|
1641
|
+
return {
|
|
1642
|
+
pagination: {
|
|
1643
|
+
total,
|
|
1644
|
+
page: pagination.page,
|
|
1645
|
+
perPage: pagination.perPage,
|
|
1646
|
+
hasMore: end < total
|
|
1647
|
+
},
|
|
1648
|
+
scores: pagedScores
|
|
862
1649
|
};
|
|
863
|
-
await this.insert({ tableName: storage.TABLE_THREADS, record: updatedThread });
|
|
864
|
-
return updatedThread;
|
|
865
1650
|
} catch (error$1) {
|
|
866
|
-
|
|
1651
|
+
const mastraError = new error.MastraError(
|
|
867
1652
|
{
|
|
868
|
-
id: "
|
|
1653
|
+
id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
869
1654
|
domain: error.ErrorDomain.STORAGE,
|
|
870
1655
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
871
|
-
|
|
872
|
-
threadId: id,
|
|
873
|
-
title
|
|
874
|
-
}
|
|
1656
|
+
text: `Failed to get scores by scorer id: ${scorerId}`
|
|
875
1657
|
},
|
|
876
1658
|
error$1
|
|
877
1659
|
);
|
|
1660
|
+
this.logger?.trackException(mastraError);
|
|
1661
|
+
this.logger?.error(mastraError.toString());
|
|
1662
|
+
return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
|
|
878
1663
|
}
|
|
879
1664
|
}
|
|
880
|
-
async
|
|
1665
|
+
async getScoresByRunId({
|
|
1666
|
+
runId,
|
|
1667
|
+
pagination
|
|
1668
|
+
}) {
|
|
881
1669
|
try {
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
1670
|
+
const keys = await this.operations.listKV(storage.TABLE_SCORERS);
|
|
1671
|
+
const scores = [];
|
|
1672
|
+
for (const { name: key } of keys) {
|
|
1673
|
+
const score = await this.operations.getKV(storage.TABLE_SCORERS, key);
|
|
1674
|
+
if (score && score.runId === runId) {
|
|
1675
|
+
scores.push(transformScoreRow(score));
|
|
1676
|
+
}
|
|
885
1677
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1678
|
+
scores.sort((a, b) => {
|
|
1679
|
+
const dateA = new Date(a.createdAt || 0).getTime();
|
|
1680
|
+
const dateB = new Date(b.createdAt || 0).getTime();
|
|
1681
|
+
return dateB - dateA;
|
|
1682
|
+
});
|
|
1683
|
+
const total = scores.length;
|
|
1684
|
+
const start = pagination.page * pagination.perPage;
|
|
1685
|
+
const end = start + pagination.perPage;
|
|
1686
|
+
const pagedScores = scores.slice(start, end);
|
|
1687
|
+
return {
|
|
1688
|
+
pagination: {
|
|
1689
|
+
total,
|
|
1690
|
+
page: pagination.page,
|
|
1691
|
+
perPage: pagination.perPage,
|
|
1692
|
+
hasMore: end < total
|
|
1693
|
+
},
|
|
1694
|
+
scores: pagedScores
|
|
1695
|
+
};
|
|
896
1696
|
} catch (error$1) {
|
|
897
|
-
|
|
1697
|
+
const mastraError = new error.MastraError(
|
|
898
1698
|
{
|
|
899
|
-
id: "
|
|
1699
|
+
id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORES_BY_RUN_ID_FAILED",
|
|
900
1700
|
domain: error.ErrorDomain.STORAGE,
|
|
901
1701
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
902
|
-
|
|
903
|
-
threadId
|
|
904
|
-
}
|
|
1702
|
+
text: `Failed to get scores by run id: ${runId}`
|
|
905
1703
|
},
|
|
906
1704
|
error$1
|
|
907
1705
|
);
|
|
1706
|
+
this.logger.trackException(mastraError);
|
|
1707
|
+
this.logger.error(mastraError.toString());
|
|
1708
|
+
return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
|
|
908
1709
|
}
|
|
909
1710
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
this.logger.error(`Error getting message key for thread ${threadId} and message ${messageId}:`, { message });
|
|
916
|
-
throw error;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
getThreadMessagesKey(threadId) {
|
|
1711
|
+
async getScoresByEntityId({
|
|
1712
|
+
entityId,
|
|
1713
|
+
entityType,
|
|
1714
|
+
pagination
|
|
1715
|
+
}) {
|
|
920
1716
|
try {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
const
|
|
924
|
-
|
|
925
|
-
|
|
1717
|
+
const keys = await this.operations.listKV(storage.TABLE_SCORERS);
|
|
1718
|
+
const scores = [];
|
|
1719
|
+
for (const { name: key } of keys) {
|
|
1720
|
+
const score = await this.operations.getKV(storage.TABLE_SCORERS, key);
|
|
1721
|
+
if (score && score.entityId === entityId && score.entityType === entityType) {
|
|
1722
|
+
scores.push(transformScoreRow(score));
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
scores.sort((a, b) => {
|
|
1726
|
+
const dateA = new Date(a.createdAt || 0).getTime();
|
|
1727
|
+
const dateB = new Date(b.createdAt || 0).getTime();
|
|
1728
|
+
return dateB - dateA;
|
|
1729
|
+
});
|
|
1730
|
+
const total = scores.length;
|
|
1731
|
+
const start = pagination.page * pagination.perPage;
|
|
1732
|
+
const end = start + pagination.perPage;
|
|
1733
|
+
const pagedScores = scores.slice(start, end);
|
|
1734
|
+
return {
|
|
1735
|
+
pagination: {
|
|
1736
|
+
total,
|
|
1737
|
+
page: pagination.page,
|
|
1738
|
+
perPage: pagination.perPage,
|
|
1739
|
+
hasMore: end < total
|
|
1740
|
+
},
|
|
1741
|
+
scores: pagedScores
|
|
1742
|
+
};
|
|
1743
|
+
} catch (error$1) {
|
|
1744
|
+
const mastraError = new error.MastraError(
|
|
1745
|
+
{
|
|
1746
|
+
id: "CLOUDFLARE_STORAGE_SCORES_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1747
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1748
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1749
|
+
text: `Failed to get scores by entity id: ${entityId}, type: ${entityType}`
|
|
1750
|
+
},
|
|
1751
|
+
error$1
|
|
1752
|
+
);
|
|
1753
|
+
this.logger.trackException(mastraError);
|
|
1754
|
+
this.logger.error(mastraError.toString());
|
|
1755
|
+
return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
|
|
926
1756
|
}
|
|
927
1757
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1758
|
+
};
|
|
1759
|
+
var TracesStorageCloudflare = class extends storage.TracesStorage {
|
|
1760
|
+
operations;
|
|
1761
|
+
constructor({ operations }) {
|
|
1762
|
+
super();
|
|
1763
|
+
this.operations = operations;
|
|
1764
|
+
}
|
|
1765
|
+
async getTraces(args) {
|
|
1766
|
+
const paginatedArgs = {
|
|
1767
|
+
name: args.name,
|
|
1768
|
+
scope: args.scope,
|
|
1769
|
+
page: args.page,
|
|
1770
|
+
perPage: args.perPage,
|
|
1771
|
+
attributes: args.attributes,
|
|
1772
|
+
filters: args.filters,
|
|
1773
|
+
dateRange: args.fromDate || args.toDate ? {
|
|
1774
|
+
start: args.fromDate,
|
|
1775
|
+
end: args.toDate
|
|
1776
|
+
} : void 0
|
|
1777
|
+
};
|
|
931
1778
|
try {
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
if (!message.id) errors.push("id is required");
|
|
935
|
-
if (!message.threadId) errors.push("threadId is required");
|
|
936
|
-
if (!message.content) errors.push("content is required");
|
|
937
|
-
if (!message.role) errors.push("role is required");
|
|
938
|
-
if (!message.createdAt) errors.push("createdAt is required");
|
|
939
|
-
if (errors.length > 0) {
|
|
940
|
-
throw new Error(`Invalid message at index ${index}: ${errors.join(", ")}`);
|
|
941
|
-
}
|
|
942
|
-
return {
|
|
943
|
-
...message,
|
|
944
|
-
createdAt: this.ensureDate(message.createdAt),
|
|
945
|
-
type: message.type || "v2",
|
|
946
|
-
_index: index
|
|
947
|
-
};
|
|
948
|
-
}).filter((m) => !!m);
|
|
949
|
-
const messagesByThread = validatedMessages.reduce((acc, message) => {
|
|
950
|
-
if (message.threadId && !acc.has(message.threadId)) {
|
|
951
|
-
acc.set(message.threadId, []);
|
|
952
|
-
}
|
|
953
|
-
if (message.threadId) {
|
|
954
|
-
acc.get(message.threadId).push(message);
|
|
955
|
-
}
|
|
956
|
-
return acc;
|
|
957
|
-
}, /* @__PURE__ */ new Map());
|
|
958
|
-
await Promise.all(
|
|
959
|
-
Array.from(messagesByThread.entries()).map(async ([threadId, threadMessages]) => {
|
|
960
|
-
try {
|
|
961
|
-
const thread = await this.getThreadById({ threadId });
|
|
962
|
-
if (!thread) {
|
|
963
|
-
throw new Error(`Thread ${threadId} not found`);
|
|
964
|
-
}
|
|
965
|
-
await Promise.all(
|
|
966
|
-
threadMessages.map(async (message) => {
|
|
967
|
-
const key = this.getMessageKey(threadId, message.id);
|
|
968
|
-
const { _index, ...cleanMessage } = message;
|
|
969
|
-
const serializedMessage = {
|
|
970
|
-
...cleanMessage,
|
|
971
|
-
createdAt: this.serializeDate(cleanMessage.createdAt)
|
|
972
|
-
};
|
|
973
|
-
await this.putKV({ tableName: storage.TABLE_MESSAGES, key, value: serializedMessage });
|
|
974
|
-
})
|
|
975
|
-
);
|
|
976
|
-
const orderKey = this.getThreadMessagesKey(threadId);
|
|
977
|
-
const entries = await this.updateSorting(threadMessages);
|
|
978
|
-
await this.updateSortedMessages(orderKey, entries);
|
|
979
|
-
} catch (error$1) {
|
|
980
|
-
throw new error.MastraError(
|
|
981
|
-
{
|
|
982
|
-
id: "CLOUDFLARE_STORAGE_SAVE_MESSAGES_FAILED",
|
|
983
|
-
domain: error.ErrorDomain.STORAGE,
|
|
984
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
985
|
-
details: {
|
|
986
|
-
threadId
|
|
987
|
-
}
|
|
988
|
-
},
|
|
989
|
-
error$1
|
|
990
|
-
);
|
|
991
|
-
}
|
|
992
|
-
})
|
|
993
|
-
);
|
|
994
|
-
const prepared = validatedMessages.map(
|
|
995
|
-
({ _index, ...message }) => ({ ...message, type: message.type !== "v2" ? message.type : void 0 })
|
|
996
|
-
);
|
|
997
|
-
const list = new agent.MessageList().add(prepared, "memory");
|
|
998
|
-
if (format === `v2`) return list.get.all.v2();
|
|
999
|
-
return list.get.all.v1();
|
|
1779
|
+
const result = await this.getTracesPaginated(paginatedArgs);
|
|
1780
|
+
return result.traces;
|
|
1000
1781
|
} catch (error$1) {
|
|
1001
1782
|
throw new error.MastraError(
|
|
1002
1783
|
{
|
|
1003
|
-
id: "
|
|
1784
|
+
id: "CLOUDFLARE_STORAGE_GET_TRACES_ERROR",
|
|
1004
1785
|
domain: error.ErrorDomain.STORAGE,
|
|
1005
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1786
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1787
|
+
text: `Failed to retrieve traces: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
1788
|
+
details: {
|
|
1789
|
+
name: args.name ?? "",
|
|
1790
|
+
scope: args.scope ?? ""
|
|
1791
|
+
}
|
|
1006
1792
|
},
|
|
1007
1793
|
error$1
|
|
1008
1794
|
);
|
|
1009
1795
|
}
|
|
1010
1796
|
}
|
|
1011
|
-
async
|
|
1012
|
-
threadId,
|
|
1013
|
-
resourceId,
|
|
1014
|
-
selectBy,
|
|
1015
|
-
format
|
|
1016
|
-
}) {
|
|
1017
|
-
if (!threadId) throw new Error("threadId is required");
|
|
1018
|
-
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1019
|
-
const messageIds = /* @__PURE__ */ new Set();
|
|
1020
|
-
if (limit === 0 && !selectBy?.include?.length) return [];
|
|
1797
|
+
async getTracesPaginated(args) {
|
|
1021
1798
|
try {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
]
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
{
|
|
1041
|
-
id: "CLOUDFLARE_STORAGE_SORT_MESSAGES_FAILED",
|
|
1042
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1043
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1044
|
-
text: `Error sorting messages for thread ${threadId} falling back to creation time`,
|
|
1045
|
-
details: {
|
|
1046
|
-
threadId
|
|
1799
|
+
const { name, scope, attributes, filters, page = 0, perPage = 100, dateRange } = args;
|
|
1800
|
+
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
1801
|
+
const keyObjs = await this.operations.listKV(storage.TABLE_TRACES, { prefix: `${prefix}${storage.TABLE_TRACES}` });
|
|
1802
|
+
const traces = [];
|
|
1803
|
+
for (const { name: key } of keyObjs) {
|
|
1804
|
+
try {
|
|
1805
|
+
const data = await this.operations.getKV(storage.TABLE_TRACES, key);
|
|
1806
|
+
if (!data) continue;
|
|
1807
|
+
if (name && data.name !== name) continue;
|
|
1808
|
+
if (scope && data.scope !== scope) continue;
|
|
1809
|
+
if (attributes) {
|
|
1810
|
+
const dataAttributes = data.attributes || {};
|
|
1811
|
+
let shouldSkip = false;
|
|
1812
|
+
for (const [key2, value] of Object.entries(attributes)) {
|
|
1813
|
+
if (dataAttributes[key2] !== value) {
|
|
1814
|
+
shouldSkip = true;
|
|
1815
|
+
break;
|
|
1816
|
+
}
|
|
1047
1817
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1818
|
+
if (shouldSkip) continue;
|
|
1819
|
+
}
|
|
1820
|
+
if (dateRange?.start || dateRange?.end) {
|
|
1821
|
+
const traceDate = new Date(data.createdAt || 0);
|
|
1822
|
+
if (dateRange.start && traceDate < dateRange.start) continue;
|
|
1823
|
+
if (dateRange.end && traceDate > dateRange.end) continue;
|
|
1824
|
+
}
|
|
1825
|
+
if (filters) {
|
|
1826
|
+
let shouldSkip = false;
|
|
1827
|
+
for (const [key2, value] of Object.entries(filters)) {
|
|
1828
|
+
if (data[key2] !== value) {
|
|
1829
|
+
shouldSkip = true;
|
|
1830
|
+
break;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
if (shouldSkip) continue;
|
|
1834
|
+
}
|
|
1835
|
+
traces.push(data);
|
|
1836
|
+
} catch (err) {
|
|
1837
|
+
this.logger.error("Failed to parse trace:", { key, error: err });
|
|
1838
|
+
}
|
|
1054
1839
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
})
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
|
|
1840
|
+
traces.sort((a, b) => {
|
|
1841
|
+
const aTime = new Date(a.createdAt || 0).getTime();
|
|
1842
|
+
const bTime = new Date(b.createdAt || 0).getTime();
|
|
1843
|
+
return bTime - aTime;
|
|
1844
|
+
});
|
|
1845
|
+
const total = traces.length;
|
|
1846
|
+
const start = page * perPage;
|
|
1847
|
+
const end = start + perPage;
|
|
1848
|
+
const pagedTraces = traces.slice(start, end);
|
|
1849
|
+
return {
|
|
1850
|
+
traces: pagedTraces,
|
|
1851
|
+
total,
|
|
1852
|
+
page,
|
|
1853
|
+
perPage,
|
|
1854
|
+
hasMore: end < total
|
|
1855
|
+
};
|
|
1063
1856
|
} catch (error$1) {
|
|
1064
1857
|
const mastraError = new error.MastraError(
|
|
1065
1858
|
{
|
|
1066
|
-
id: "
|
|
1859
|
+
id: "CLOUDFLARE_STORAGE_GET_TRACES_PAGINATED_FAILED",
|
|
1067
1860
|
domain: error.ErrorDomain.STORAGE,
|
|
1068
1861
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1069
|
-
text:
|
|
1070
|
-
details: {
|
|
1071
|
-
threadId
|
|
1072
|
-
}
|
|
1862
|
+
text: "Error getting traces with pagination"
|
|
1073
1863
|
},
|
|
1074
1864
|
error$1
|
|
1075
1865
|
);
|
|
1076
|
-
this.logger?.
|
|
1077
|
-
this.logger
|
|
1078
|
-
return [];
|
|
1866
|
+
this.logger.trackException?.(mastraError);
|
|
1867
|
+
this.logger.error(mastraError.toString());
|
|
1868
|
+
return { traces: [], total: 0, page: 0, perPage: 100, hasMore: false };
|
|
1079
1869
|
}
|
|
1080
1870
|
}
|
|
1871
|
+
async batchTraceInsert({ records }) {
|
|
1872
|
+
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1873
|
+
await this.operations.batchInsert({
|
|
1874
|
+
tableName: storage.TABLE_TRACES,
|
|
1875
|
+
records
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
};
|
|
1879
|
+
var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
1880
|
+
operations;
|
|
1881
|
+
constructor({ operations }) {
|
|
1882
|
+
super();
|
|
1883
|
+
this.operations = operations;
|
|
1884
|
+
}
|
|
1081
1885
|
validateWorkflowParams(params) {
|
|
1082
|
-
const {
|
|
1083
|
-
if (!
|
|
1886
|
+
const { workflowName, runId } = params;
|
|
1887
|
+
if (!workflowName || !runId) {
|
|
1084
1888
|
throw new Error("Invalid workflow snapshot parameters");
|
|
1085
1889
|
}
|
|
1086
1890
|
}
|
|
1087
|
-
validateWorkflowState(state) {
|
|
1088
|
-
if (!state?.runId || !state?.value || !state?.context?.input || !state?.activePaths) {
|
|
1089
|
-
throw new Error("Invalid workflow state structure");
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
normalizeSteps(steps) {
|
|
1093
|
-
const normalizedSteps = {};
|
|
1094
|
-
for (const [stepId, step] of Object.entries(steps)) {
|
|
1095
|
-
normalizedSteps[stepId] = {
|
|
1096
|
-
status: step.status,
|
|
1097
|
-
payload: step.payload || step.result,
|
|
1098
|
-
error: step.error
|
|
1099
|
-
};
|
|
1100
|
-
}
|
|
1101
|
-
return normalizedSteps;
|
|
1102
|
-
}
|
|
1103
|
-
normalizeWorkflowState(data) {
|
|
1104
|
-
return {
|
|
1105
|
-
runId: data.runId,
|
|
1106
|
-
value: data.value,
|
|
1107
|
-
context: data.context,
|
|
1108
|
-
serializedStepGraph: data.serializedStepGraph,
|
|
1109
|
-
suspendedPaths: data.suspendedPaths || {},
|
|
1110
|
-
activePaths: data.activePaths || [],
|
|
1111
|
-
timestamp: data.timestamp || Date.now(),
|
|
1112
|
-
status: data.status,
|
|
1113
|
-
result: data.result,
|
|
1114
|
-
error: data.error,
|
|
1115
|
-
runtimeContext: data.runtimeContext || {}
|
|
1116
|
-
};
|
|
1117
|
-
}
|
|
1118
1891
|
async persistWorkflowSnapshot(params) {
|
|
1119
1892
|
try {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
const normalizedState = this.normalizeWorkflowState(snapshot);
|
|
1123
|
-
this.validateWorkflowState(normalizedState);
|
|
1124
|
-
await this.insert({
|
|
1893
|
+
const { workflowName, runId, snapshot } = params;
|
|
1894
|
+
await this.operations.putKV({
|
|
1125
1895
|
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1126
|
-
|
|
1127
|
-
|
|
1896
|
+
key: this.operations.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { workflow_name: workflowName, run_id: runId }),
|
|
1897
|
+
value: {
|
|
1128
1898
|
workflow_name: workflowName,
|
|
1129
1899
|
run_id: runId,
|
|
1130
|
-
snapshot:
|
|
1900
|
+
snapshot: typeof snapshot === "string" ? snapshot : JSON.stringify(snapshot),
|
|
1131
1901
|
createdAt: /* @__PURE__ */ new Date(),
|
|
1132
1902
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1133
1903
|
}
|
|
@@ -1138,9 +1908,8 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
1138
1908
|
id: "CLOUDFLARE_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
1139
1909
|
domain: error.ErrorDomain.STORAGE,
|
|
1140
1910
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1141
|
-
text: `Error persisting workflow snapshot for
|
|
1911
|
+
text: `Error persisting workflow snapshot for workflow ${params.workflowName}, run ${params.runId}`,
|
|
1142
1912
|
details: {
|
|
1143
|
-
namespace: params.namespace,
|
|
1144
1913
|
workflowName: params.workflowName,
|
|
1145
1914
|
runId: params.runId
|
|
1146
1915
|
}
|
|
@@ -1152,172 +1921,31 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
1152
1921
|
async loadWorkflowSnapshot(params) {
|
|
1153
1922
|
try {
|
|
1154
1923
|
this.validateWorkflowParams(params);
|
|
1155
|
-
const {
|
|
1156
|
-
const key = this.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, {
|
|
1157
|
-
const data = await this.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
1924
|
+
const { workflowName, runId } = params;
|
|
1925
|
+
const key = this.operations.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { workflow_name: workflowName, run_id: runId });
|
|
1926
|
+
const data = await this.operations.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
1158
1927
|
if (!data) return null;
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
return state;
|
|
1928
|
+
const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
|
|
1929
|
+
return snapshotData;
|
|
1162
1930
|
} catch (error$1) {
|
|
1163
1931
|
const mastraError = new error.MastraError(
|
|
1164
1932
|
{
|
|
1165
1933
|
id: "CLOUDFLARE_STORAGE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
1166
1934
|
domain: error.ErrorDomain.STORAGE,
|
|
1167
1935
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1168
|
-
text: `Error loading workflow snapshot for
|
|
1936
|
+
text: `Error loading workflow snapshot for workflow ${params.workflowName}, run ${params.runId}`,
|
|
1169
1937
|
details: {
|
|
1170
|
-
namespace: params.namespace,
|
|
1171
1938
|
workflowName: params.workflowName,
|
|
1172
1939
|
runId: params.runId
|
|
1173
1940
|
}
|
|
1174
1941
|
},
|
|
1175
1942
|
error$1
|
|
1176
1943
|
);
|
|
1177
|
-
this.logger?.
|
|
1178
|
-
this.logger
|
|
1944
|
+
this.logger.trackException?.(mastraError);
|
|
1945
|
+
this.logger.error(mastraError.toString());
|
|
1179
1946
|
return null;
|
|
1180
1947
|
}
|
|
1181
1948
|
}
|
|
1182
|
-
async batchInsert(input) {
|
|
1183
|
-
if (!input.records || input.records.length === 0) return;
|
|
1184
|
-
try {
|
|
1185
|
-
await Promise.all(
|
|
1186
|
-
input.records.map(async (record) => {
|
|
1187
|
-
const key = this.getKey(input.tableName, record);
|
|
1188
|
-
const processedRecord = {
|
|
1189
|
-
...record,
|
|
1190
|
-
createdAt: record.createdAt ? this.serializeDate(record.createdAt) : void 0,
|
|
1191
|
-
updatedAt: record.updatedAt ? this.serializeDate(record.updatedAt) : void 0,
|
|
1192
|
-
metadata: record.metadata ? JSON.stringify(record.metadata) : void 0
|
|
1193
|
-
};
|
|
1194
|
-
await this.putKV({ tableName: input.tableName, key, value: processedRecord });
|
|
1195
|
-
})
|
|
1196
|
-
);
|
|
1197
|
-
} catch (error$1) {
|
|
1198
|
-
throw new error.MastraError(
|
|
1199
|
-
{
|
|
1200
|
-
id: "CLOUDFLARE_STORAGE_BATCH_INSERT_FAILED",
|
|
1201
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1202
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1203
|
-
text: `Error in batch insert for table ${input.tableName}`,
|
|
1204
|
-
details: {
|
|
1205
|
-
tableName: input.tableName
|
|
1206
|
-
}
|
|
1207
|
-
},
|
|
1208
|
-
error$1
|
|
1209
|
-
);
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
async getTraces({
|
|
1213
|
-
name,
|
|
1214
|
-
scope,
|
|
1215
|
-
page = 0,
|
|
1216
|
-
perPage = 100,
|
|
1217
|
-
attributes,
|
|
1218
|
-
fromDate,
|
|
1219
|
-
toDate
|
|
1220
|
-
}) {
|
|
1221
|
-
try {
|
|
1222
|
-
let keys;
|
|
1223
|
-
if (this.bindings) {
|
|
1224
|
-
keys = (await this.listKV(storage.TABLE_TRACES))?.map((k) => k.name) || [];
|
|
1225
|
-
} else {
|
|
1226
|
-
const namespaceId = await this.getNamespaceId(storage.TABLE_TRACES);
|
|
1227
|
-
const result = await this.client.kv.namespaces.keys.list(namespaceId, {
|
|
1228
|
-
prefix: "",
|
|
1229
|
-
limit: 1e3,
|
|
1230
|
-
account_id: this.accountId
|
|
1231
|
-
});
|
|
1232
|
-
keys = result.result?.map((k) => k.name) || [];
|
|
1233
|
-
}
|
|
1234
|
-
const traceRecords = await Promise.all(
|
|
1235
|
-
keys.map(async (key) => {
|
|
1236
|
-
const record = await this.getKV(storage.TABLE_TRACES, key);
|
|
1237
|
-
if (!record) return null;
|
|
1238
|
-
return record;
|
|
1239
|
-
})
|
|
1240
|
-
);
|
|
1241
|
-
let filteredTraces = traceRecords.filter(
|
|
1242
|
-
(record) => record !== null && typeof record === "object"
|
|
1243
|
-
);
|
|
1244
|
-
if (name) {
|
|
1245
|
-
filteredTraces = filteredTraces.filter((record) => record.name?.toLowerCase().startsWith(name.toLowerCase()));
|
|
1246
|
-
}
|
|
1247
|
-
if (scope) {
|
|
1248
|
-
filteredTraces = filteredTraces.filter((record) => record.scope === scope);
|
|
1249
|
-
}
|
|
1250
|
-
if (attributes) {
|
|
1251
|
-
filteredTraces = filteredTraces.filter((record) => {
|
|
1252
|
-
if (!record.attributes) return false;
|
|
1253
|
-
const recordAttrs = this.parseJSON(record.attributes);
|
|
1254
|
-
if (!recordAttrs) return false;
|
|
1255
|
-
return Object.entries(attributes).every(([key, value]) => recordAttrs[key] === value);
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
if (fromDate) {
|
|
1259
|
-
filteredTraces = filteredTraces.filter((record) => new Date(record.createdAt).getTime() >= fromDate.getTime());
|
|
1260
|
-
}
|
|
1261
|
-
if (toDate) {
|
|
1262
|
-
filteredTraces = filteredTraces.filter((record) => new Date(record.createdAt).getTime() <= toDate.getTime());
|
|
1263
|
-
}
|
|
1264
|
-
filteredTraces.sort((a, b) => {
|
|
1265
|
-
const dateA = new Date(a.createdAt).getTime();
|
|
1266
|
-
const dateB = new Date(b.createdAt).getTime();
|
|
1267
|
-
return dateB - dateA;
|
|
1268
|
-
});
|
|
1269
|
-
const start = page * perPage;
|
|
1270
|
-
const end = start + perPage;
|
|
1271
|
-
const paginatedTraces = filteredTraces.slice(start, end);
|
|
1272
|
-
return paginatedTraces.map((record) => ({
|
|
1273
|
-
id: record.id,
|
|
1274
|
-
parentSpanId: record.parentSpanId,
|
|
1275
|
-
traceId: record.traceId,
|
|
1276
|
-
name: record.name,
|
|
1277
|
-
scope: record.scope,
|
|
1278
|
-
kind: record.kind,
|
|
1279
|
-
status: this.parseJSON(record.status),
|
|
1280
|
-
events: this.parseJSON(record.events) || [],
|
|
1281
|
-
links: this.parseJSON(record.links) || [],
|
|
1282
|
-
attributes: this.parseJSON(record?.attributes) || {},
|
|
1283
|
-
startTime: record.startTime,
|
|
1284
|
-
endTime: record.endTime,
|
|
1285
|
-
other: this.parseJSON(record.other) || {},
|
|
1286
|
-
createdAt: record.createdAt
|
|
1287
|
-
}));
|
|
1288
|
-
} catch (error$1) {
|
|
1289
|
-
const mastraError = new error.MastraError(
|
|
1290
|
-
{
|
|
1291
|
-
id: "CLOUDFLARE_STORAGE_GET_TRACES_FAILED",
|
|
1292
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1293
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1294
|
-
text: `Failed to get traces`
|
|
1295
|
-
},
|
|
1296
|
-
error$1
|
|
1297
|
-
);
|
|
1298
|
-
this.logger?.trackException(mastraError);
|
|
1299
|
-
this.logger?.error(mastraError.toString());
|
|
1300
|
-
return [];
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
parseJSON(value) {
|
|
1304
|
-
if (typeof value === "string") {
|
|
1305
|
-
try {
|
|
1306
|
-
return JSON.parse(value);
|
|
1307
|
-
} catch {
|
|
1308
|
-
return value;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
return value;
|
|
1312
|
-
}
|
|
1313
|
-
getEvalsByAgentName(_agentName, _type) {
|
|
1314
|
-
throw new error.MastraError({
|
|
1315
|
-
id: "CLOUDFLARE_STORAGE_GET_EVALS_BY_AGENT_NAME_FAILED",
|
|
1316
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1317
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1318
|
-
text: `Failed to get evals by agent name`
|
|
1319
|
-
});
|
|
1320
|
-
}
|
|
1321
1949
|
parseWorkflowRun(row) {
|
|
1322
1950
|
let parsedSnapshot = row.snapshot;
|
|
1323
1951
|
if (typeof parsedSnapshot === "string") {
|
|
@@ -1331,28 +1959,24 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
1331
1959
|
workflowName: row.workflow_name,
|
|
1332
1960
|
runId: row.run_id,
|
|
1333
1961
|
snapshot: parsedSnapshot,
|
|
1334
|
-
createdAt:
|
|
1335
|
-
updatedAt:
|
|
1962
|
+
createdAt: storage.ensureDate(row.createdAt),
|
|
1963
|
+
updatedAt: storage.ensureDate(row.updatedAt),
|
|
1336
1964
|
resourceId: row.resourceId
|
|
1337
1965
|
};
|
|
1338
1966
|
}
|
|
1339
1967
|
buildWorkflowSnapshotPrefix({
|
|
1340
|
-
namespace,
|
|
1341
1968
|
workflowName,
|
|
1342
1969
|
runId,
|
|
1343
1970
|
resourceId
|
|
1344
1971
|
}) {
|
|
1345
|
-
const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
1972
|
+
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
1346
1973
|
let key = `${prefix}${storage.TABLE_WORKFLOW_SNAPSHOT}`;
|
|
1347
|
-
if (namespace) key += `:${namespace}`;
|
|
1348
1974
|
if (workflowName) key += `:${workflowName}`;
|
|
1349
1975
|
if (runId) key += `:${runId}`;
|
|
1350
1976
|
if (resourceId) key += `:${resourceId}`;
|
|
1351
|
-
if (!resourceId && (runId || workflowName || namespace)) key += ":";
|
|
1352
1977
|
return key;
|
|
1353
1978
|
}
|
|
1354
1979
|
async getWorkflowRuns({
|
|
1355
|
-
namespace,
|
|
1356
1980
|
workflowName,
|
|
1357
1981
|
limit = 20,
|
|
1358
1982
|
offset = 0,
|
|
@@ -1361,28 +1985,32 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
1361
1985
|
toDate
|
|
1362
1986
|
} = {}) {
|
|
1363
1987
|
try {
|
|
1364
|
-
const prefix = this.buildWorkflowSnapshotPrefix({
|
|
1365
|
-
const keyObjs = await this.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
|
|
1988
|
+
const prefix = this.buildWorkflowSnapshotPrefix({ workflowName });
|
|
1989
|
+
const keyObjs = await this.operations.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
|
|
1366
1990
|
const runs = [];
|
|
1367
1991
|
for (const { name: key } of keyObjs) {
|
|
1368
1992
|
const parts = key.split(":");
|
|
1369
1993
|
const idx = parts.indexOf(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1370
|
-
if (idx === -1 || parts.length < idx +
|
|
1371
|
-
const
|
|
1372
|
-
const
|
|
1373
|
-
|
|
1374
|
-
if (
|
|
1375
|
-
|
|
1376
|
-
const data = await this.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
1994
|
+
if (idx === -1 || parts.length < idx + 3) continue;
|
|
1995
|
+
const wfName = parts[idx + 1];
|
|
1996
|
+
const keyResourceId = parts.length > idx + 3 ? parts[idx + 3] : void 0;
|
|
1997
|
+
if (workflowName && wfName !== workflowName) continue;
|
|
1998
|
+
if (resourceId && keyResourceId !== resourceId) continue;
|
|
1999
|
+
const data = await this.operations.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
1377
2000
|
if (!data) continue;
|
|
1378
2001
|
try {
|
|
1379
|
-
if (resourceId &&
|
|
1380
|
-
const createdAt =
|
|
2002
|
+
if (resourceId && !keyResourceId) continue;
|
|
2003
|
+
const createdAt = storage.ensureDate(data.createdAt);
|
|
1381
2004
|
if (fromDate && createdAt && createdAt < fromDate) continue;
|
|
1382
2005
|
if (toDate && createdAt && createdAt > toDate) continue;
|
|
1383
|
-
const
|
|
1384
|
-
|
|
1385
|
-
const run = this.parseWorkflowRun({
|
|
2006
|
+
const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
|
|
2007
|
+
const resourceIdToUse = keyResourceId || data.resourceId;
|
|
2008
|
+
const run = this.parseWorkflowRun({
|
|
2009
|
+
...data,
|
|
2010
|
+
workflow_name: wfName,
|
|
2011
|
+
resourceId: resourceIdToUse,
|
|
2012
|
+
snapshot: snapshotData
|
|
2013
|
+
});
|
|
1386
2014
|
runs.push(run);
|
|
1387
2015
|
} catch (err) {
|
|
1388
2016
|
this.logger.error("Failed to parse workflow snapshot:", { key, error: err });
|
|
@@ -1407,29 +2035,35 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
1407
2035
|
},
|
|
1408
2036
|
error$1
|
|
1409
2037
|
);
|
|
1410
|
-
this.logger?.
|
|
1411
|
-
this.logger
|
|
2038
|
+
this.logger.trackException?.(mastraError);
|
|
2039
|
+
this.logger.error(mastraError.toString());
|
|
1412
2040
|
return { runs: [], total: 0 };
|
|
1413
2041
|
}
|
|
1414
2042
|
}
|
|
1415
2043
|
async getWorkflowRunById({
|
|
1416
|
-
namespace,
|
|
1417
2044
|
runId,
|
|
1418
2045
|
workflowName
|
|
1419
2046
|
}) {
|
|
1420
2047
|
try {
|
|
1421
|
-
if (!runId || !workflowName
|
|
1422
|
-
throw new Error("runId, workflowName,
|
|
2048
|
+
if (!runId || !workflowName) {
|
|
2049
|
+
throw new Error("runId, workflowName, are required");
|
|
1423
2050
|
}
|
|
1424
|
-
const prefix = this.buildWorkflowSnapshotPrefix({
|
|
1425
|
-
const keyObjs = await this.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
|
|
2051
|
+
const prefix = this.buildWorkflowSnapshotPrefix({ workflowName, runId });
|
|
2052
|
+
const keyObjs = await this.operations.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
|
|
1426
2053
|
if (!keyObjs.length) return null;
|
|
1427
|
-
const
|
|
1428
|
-
|
|
2054
|
+
const exactKey = keyObjs.find((k) => {
|
|
2055
|
+
const parts = k.name.split(":");
|
|
2056
|
+
const idx = parts.indexOf(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
2057
|
+
if (idx === -1 || parts.length < idx + 3) return false;
|
|
2058
|
+
const wfName = parts[idx + 1];
|
|
2059
|
+
const rId = parts[idx + 2];
|
|
2060
|
+
return wfName === workflowName && rId === runId;
|
|
2061
|
+
});
|
|
2062
|
+
if (!exactKey) return null;
|
|
2063
|
+
const data = await this.operations.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, exactKey.name);
|
|
1429
2064
|
if (!data) return null;
|
|
1430
|
-
const
|
|
1431
|
-
this.
|
|
1432
|
-
return this.parseWorkflowRun({ ...data, snapshot: state });
|
|
2065
|
+
const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
|
|
2066
|
+
return this.parseWorkflowRun({ ...data, snapshot: snapshotData });
|
|
1433
2067
|
} catch (error$1) {
|
|
1434
2068
|
const mastraError = new error.MastraError(
|
|
1435
2069
|
{
|
|
@@ -1437,47 +2071,282 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
1437
2071
|
domain: error.ErrorDomain.STORAGE,
|
|
1438
2072
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1439
2073
|
details: {
|
|
1440
|
-
namespace,
|
|
1441
2074
|
workflowName,
|
|
1442
2075
|
runId
|
|
1443
2076
|
}
|
|
1444
2077
|
},
|
|
1445
2078
|
error$1
|
|
1446
2079
|
);
|
|
1447
|
-
this.logger?.
|
|
1448
|
-
this.logger
|
|
2080
|
+
this.logger.trackException?.(mastraError);
|
|
2081
|
+
this.logger.error(mastraError.toString());
|
|
1449
2082
|
return null;
|
|
1450
2083
|
}
|
|
1451
2084
|
}
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
// src/storage/types.ts
|
|
2088
|
+
function isWorkersConfig(config) {
|
|
2089
|
+
return "bindings" in config;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// src/storage/index.ts
|
|
2093
|
+
var CloudflareStore = class extends storage.MastraStorage {
|
|
2094
|
+
stores;
|
|
2095
|
+
client;
|
|
2096
|
+
accountId;
|
|
2097
|
+
namespacePrefix;
|
|
2098
|
+
bindings;
|
|
2099
|
+
validateWorkersConfig(config) {
|
|
2100
|
+
if (!isWorkersConfig(config)) {
|
|
2101
|
+
throw new Error("Invalid Workers API configuration");
|
|
2102
|
+
}
|
|
2103
|
+
if (!config.bindings) {
|
|
2104
|
+
throw new Error("KV bindings are required when using Workers Binding API");
|
|
2105
|
+
}
|
|
2106
|
+
const requiredTables = [
|
|
2107
|
+
storage.TABLE_THREADS,
|
|
2108
|
+
storage.TABLE_MESSAGES,
|
|
2109
|
+
storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2110
|
+
storage.TABLE_EVALS,
|
|
2111
|
+
storage.TABLE_SCORERS,
|
|
2112
|
+
storage.TABLE_TRACES
|
|
2113
|
+
];
|
|
2114
|
+
for (const table of requiredTables) {
|
|
2115
|
+
if (!(table in config.bindings)) {
|
|
2116
|
+
throw new Error(`Missing KV binding for table: ${table}`);
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
validateRestConfig(config) {
|
|
2121
|
+
if (isWorkersConfig(config)) {
|
|
2122
|
+
throw new Error("Invalid REST API configuration");
|
|
2123
|
+
}
|
|
2124
|
+
if (!config.accountId?.trim()) {
|
|
2125
|
+
throw new Error("accountId is required for REST API");
|
|
2126
|
+
}
|
|
2127
|
+
if (!config.apiToken?.trim()) {
|
|
2128
|
+
throw new Error("apiToken is required for REST API");
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
constructor(config) {
|
|
2132
|
+
super({ name: "Cloudflare" });
|
|
2133
|
+
try {
|
|
2134
|
+
if (isWorkersConfig(config)) {
|
|
2135
|
+
this.validateWorkersConfig(config);
|
|
2136
|
+
this.bindings = config.bindings;
|
|
2137
|
+
this.namespacePrefix = config.keyPrefix?.trim() || "";
|
|
2138
|
+
this.logger.info("Using Cloudflare KV Workers Binding API");
|
|
2139
|
+
} else {
|
|
2140
|
+
this.validateRestConfig(config);
|
|
2141
|
+
this.accountId = config.accountId.trim();
|
|
2142
|
+
this.namespacePrefix = config.namespacePrefix?.trim() || "";
|
|
2143
|
+
this.client = new Cloudflare__default.default({
|
|
2144
|
+
apiToken: config.apiToken.trim()
|
|
2145
|
+
});
|
|
2146
|
+
this.logger.info("Using Cloudflare KV REST API");
|
|
2147
|
+
}
|
|
2148
|
+
const operations = new StoreOperationsCloudflare({
|
|
2149
|
+
accountId: this.accountId,
|
|
2150
|
+
client: this.client,
|
|
2151
|
+
namespacePrefix: this.namespacePrefix,
|
|
2152
|
+
bindings: this.bindings
|
|
2153
|
+
});
|
|
2154
|
+
const legacyEvals = new LegacyEvalsStorageCloudflare({
|
|
2155
|
+
operations
|
|
2156
|
+
});
|
|
2157
|
+
const workflows = new WorkflowsStorageCloudflare({
|
|
2158
|
+
operations
|
|
2159
|
+
});
|
|
2160
|
+
const traces = new TracesStorageCloudflare({
|
|
2161
|
+
operations
|
|
2162
|
+
});
|
|
2163
|
+
const memory = new MemoryStorageCloudflare({
|
|
2164
|
+
operations
|
|
2165
|
+
});
|
|
2166
|
+
const scores = new ScoresStorageCloudflare({
|
|
2167
|
+
operations
|
|
2168
|
+
});
|
|
2169
|
+
this.stores = {
|
|
2170
|
+
operations,
|
|
2171
|
+
legacyEvals,
|
|
2172
|
+
workflows,
|
|
2173
|
+
traces,
|
|
2174
|
+
memory,
|
|
2175
|
+
scores
|
|
2176
|
+
};
|
|
2177
|
+
} catch (error$1) {
|
|
2178
|
+
throw new error.MastraError(
|
|
2179
|
+
{
|
|
2180
|
+
id: "CLOUDFLARE_STORAGE_INIT_FAILED",
|
|
2181
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2182
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2183
|
+
},
|
|
2184
|
+
error$1
|
|
2185
|
+
);
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
async createTable({
|
|
2189
|
+
tableName,
|
|
2190
|
+
schema
|
|
2191
|
+
}) {
|
|
2192
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
2193
|
+
}
|
|
2194
|
+
async alterTable(_args) {
|
|
2195
|
+
return this.stores.operations.alterTable(_args);
|
|
2196
|
+
}
|
|
2197
|
+
async clearTable({ tableName }) {
|
|
2198
|
+
return this.stores.operations.clearTable({ tableName });
|
|
2199
|
+
}
|
|
2200
|
+
async dropTable({ tableName }) {
|
|
2201
|
+
return this.stores.operations.dropTable({ tableName });
|
|
2202
|
+
}
|
|
2203
|
+
async insert({
|
|
2204
|
+
tableName,
|
|
2205
|
+
record
|
|
2206
|
+
}) {
|
|
2207
|
+
return this.stores.operations.insert({ tableName, record });
|
|
2208
|
+
}
|
|
2209
|
+
async load({ tableName, keys }) {
|
|
2210
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2211
|
+
}
|
|
2212
|
+
async getThreadById({ threadId }) {
|
|
2213
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2214
|
+
}
|
|
2215
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
2216
|
+
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
2217
|
+
}
|
|
2218
|
+
async saveThread({ thread }) {
|
|
2219
|
+
return this.stores.memory.saveThread({ thread });
|
|
2220
|
+
}
|
|
2221
|
+
async updateThread({
|
|
2222
|
+
id,
|
|
2223
|
+
title,
|
|
2224
|
+
metadata
|
|
2225
|
+
}) {
|
|
2226
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2227
|
+
}
|
|
2228
|
+
async deleteThread({ threadId }) {
|
|
2229
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2230
|
+
}
|
|
2231
|
+
async saveMessages(args) {
|
|
2232
|
+
return this.stores.memory.saveMessages(args);
|
|
2233
|
+
}
|
|
2234
|
+
async getMessages({
|
|
2235
|
+
threadId,
|
|
2236
|
+
resourceId,
|
|
2237
|
+
selectBy,
|
|
2238
|
+
format
|
|
2239
|
+
}) {
|
|
2240
|
+
return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format });
|
|
2241
|
+
}
|
|
2242
|
+
async persistWorkflowSnapshot(params) {
|
|
2243
|
+
return this.stores.workflows.persistWorkflowSnapshot(params);
|
|
1459
2244
|
}
|
|
1460
|
-
async
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
2245
|
+
async loadWorkflowSnapshot(params) {
|
|
2246
|
+
return this.stores.workflows.loadWorkflowSnapshot(params);
|
|
2247
|
+
}
|
|
2248
|
+
async batchInsert(input) {
|
|
2249
|
+
return this.stores.operations.batchInsert(input);
|
|
2250
|
+
}
|
|
2251
|
+
async getTraces({
|
|
2252
|
+
name,
|
|
2253
|
+
scope,
|
|
2254
|
+
page = 0,
|
|
2255
|
+
perPage = 100,
|
|
2256
|
+
attributes,
|
|
2257
|
+
fromDate,
|
|
2258
|
+
toDate
|
|
2259
|
+
}) {
|
|
2260
|
+
return this.stores.traces.getTraces({
|
|
2261
|
+
name,
|
|
2262
|
+
scope,
|
|
2263
|
+
page,
|
|
2264
|
+
perPage,
|
|
2265
|
+
attributes,
|
|
2266
|
+
fromDate,
|
|
2267
|
+
toDate
|
|
1466
2268
|
});
|
|
1467
2269
|
}
|
|
1468
|
-
async
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
2270
|
+
async getEvalsByAgentName(agentName, type) {
|
|
2271
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2272
|
+
}
|
|
2273
|
+
async getEvals(options) {
|
|
2274
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
2275
|
+
}
|
|
2276
|
+
async getWorkflowRuns({
|
|
2277
|
+
workflowName,
|
|
2278
|
+
limit = 20,
|
|
2279
|
+
offset = 0,
|
|
2280
|
+
resourceId,
|
|
2281
|
+
fromDate,
|
|
2282
|
+
toDate
|
|
2283
|
+
} = {}) {
|
|
2284
|
+
return this.stores.workflows.getWorkflowRuns({
|
|
2285
|
+
workflowName,
|
|
2286
|
+
limit,
|
|
2287
|
+
offset,
|
|
2288
|
+
resourceId,
|
|
2289
|
+
fromDate,
|
|
2290
|
+
toDate
|
|
1474
2291
|
});
|
|
1475
2292
|
}
|
|
1476
|
-
async
|
|
2293
|
+
async getWorkflowRunById({
|
|
2294
|
+
runId,
|
|
2295
|
+
workflowName
|
|
2296
|
+
}) {
|
|
2297
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2298
|
+
}
|
|
2299
|
+
async getTracesPaginated(args) {
|
|
2300
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
2301
|
+
}
|
|
2302
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2303
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2304
|
+
}
|
|
2305
|
+
async getMessagesPaginated(args) {
|
|
2306
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
2307
|
+
}
|
|
2308
|
+
async updateMessages(args) {
|
|
2309
|
+
return this.stores.memory.updateMessages(args);
|
|
1477
2310
|
}
|
|
1478
|
-
async
|
|
1479
|
-
this.
|
|
1480
|
-
|
|
2311
|
+
async getScoreById({ id }) {
|
|
2312
|
+
return this.stores.scores.getScoreById({ id });
|
|
2313
|
+
}
|
|
2314
|
+
async saveScore(score) {
|
|
2315
|
+
return this.stores.scores.saveScore(score);
|
|
2316
|
+
}
|
|
2317
|
+
async getScoresByRunId({
|
|
2318
|
+
runId,
|
|
2319
|
+
pagination
|
|
2320
|
+
}) {
|
|
2321
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
2322
|
+
}
|
|
2323
|
+
async getScoresByEntityId({
|
|
2324
|
+
entityId,
|
|
2325
|
+
entityType,
|
|
2326
|
+
pagination
|
|
2327
|
+
}) {
|
|
2328
|
+
return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
|
|
2329
|
+
}
|
|
2330
|
+
async getScoresByScorerId({
|
|
2331
|
+
scorerId,
|
|
2332
|
+
pagination
|
|
2333
|
+
}) {
|
|
2334
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
|
|
2335
|
+
}
|
|
2336
|
+
async getResourceById({ resourceId }) {
|
|
2337
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2338
|
+
}
|
|
2339
|
+
async saveResource({ resource }) {
|
|
2340
|
+
return this.stores.memory.saveResource({ resource });
|
|
2341
|
+
}
|
|
2342
|
+
async updateResource({
|
|
2343
|
+
resourceId,
|
|
2344
|
+
workingMemory,
|
|
2345
|
+
metadata
|
|
2346
|
+
}) {
|
|
2347
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2348
|
+
}
|
|
2349
|
+
async close() {
|
|
1481
2350
|
}
|
|
1482
2351
|
};
|
|
1483
2352
|
|