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