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