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