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