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