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