@mastra/cloudflare 0.0.0-taofeeqInngest-20250603090617 → 0.0.0-transpile-packages-20250724123433

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