@mastra/cloudflare 0.0.0-vector-sources-20250516175436 → 0.0.0-vector-extension-schema-20250922130418

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