@mastra/cloudflare 1.0.0-beta.2 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/index.cjs +69 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +70 -28
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +36 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @mastra/cloudflare
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat(storage): support querying messages from multiple threads ([#10663](https://github.com/mastra-ai/mastra/pull/10663))
|
|
8
|
+
- Fixed TypeScript errors where `threadId: string | string[]` was being passed to places expecting `Scalar` type
|
|
9
|
+
- Added proper multi-thread support for `listMessages` across all adapters when `threadId` is an array
|
|
10
|
+
- Updated `_getIncludedMessages` to look up message threadId by ID (since message IDs are globally unique)
|
|
11
|
+
- **upstash**: Added `msg-idx:{messageId}` index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)
|
|
12
|
+
|
|
13
|
+
- fix: ensure score responses match saved payloads for Mastra Stores. ([#10557](https://github.com/mastra-ai/mastra/pull/10557))
|
|
14
|
+
|
|
15
|
+
- Unify transformScoreRow functions across storage adapters ([#10648](https://github.com/mastra-ai/mastra/pull/10648))
|
|
16
|
+
|
|
17
|
+
Added a unified `transformScoreRow` function in `@mastra/core/storage` that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
|
|
18
|
+
- `preferredTimestampFields`: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)
|
|
19
|
+
- `convertTimestamps`: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)
|
|
20
|
+
- `nullValuePattern`: Skip values matching pattern (ClickHouse's `'_null_'`)
|
|
21
|
+
- `fieldMappings`: Map source column names to schema fields (LibSQL's `additionalLLMContext`)
|
|
22
|
+
|
|
23
|
+
Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [[`ac0d2f4`](https://github.com/mastra-ai/mastra/commit/ac0d2f4ff8831f72c1c66c2be809706d17f65789), [`1a0d3fc`](https://github.com/mastra-ai/mastra/commit/1a0d3fc811482c9c376cdf79ee615c23bae9b2d6), [`85a628b`](https://github.com/mastra-ai/mastra/commit/85a628b1224a8f64cd82ea7f033774bf22df7a7e), [`c237233`](https://github.com/mastra-ai/mastra/commit/c23723399ccedf7f5744b3f40997b79246bfbe64), [`15f9e21`](https://github.com/mastra-ai/mastra/commit/15f9e216177201ea6e3f6d0bfb063fcc0953444f), [`ff94dea`](https://github.com/mastra-ai/mastra/commit/ff94dea935f4e34545c63bcb6c29804732698809), [`5b2ff46`](https://github.com/mastra-ai/mastra/commit/5b2ff4651df70c146523a7fca773f8eb0a2272f8), [`db41688`](https://github.com/mastra-ai/mastra/commit/db4168806d007417e2e60b4f68656dca4e5f40c9), [`5ca599d`](https://github.com/mastra-ai/mastra/commit/5ca599d0bb59a1595f19f58473fcd67cc71cef58), [`bff1145`](https://github.com/mastra-ai/mastra/commit/bff114556b3cbadad9b2768488708f8ad0e91475), [`5c8ca24`](https://github.com/mastra-ai/mastra/commit/5c8ca247094e0cc2cdbd7137822fb47241f86e77), [`e191844`](https://github.com/mastra-ai/mastra/commit/e1918444ca3f80e82feef1dad506cd4ec6e2875f), [`22553f1`](https://github.com/mastra-ai/mastra/commit/22553f11c63ee5e966a9c034a349822249584691), [`7237163`](https://github.com/mastra-ai/mastra/commit/72371635dbf96a87df4b073cc48fc655afbdce3d), [`2500740`](https://github.com/mastra-ai/mastra/commit/2500740ea23da067d6e50ec71c625ab3ce275e64), [`873ecbb`](https://github.com/mastra-ai/mastra/commit/873ecbb517586aa17d2f1e99283755b3ebb2863f), [`4f9bbe5`](https://github.com/mastra-ai/mastra/commit/4f9bbe5968f42c86f4930b8193de3c3c17e5bd36), [`02e51fe`](https://github.com/mastra-ai/mastra/commit/02e51feddb3d4155cfbcc42624fd0d0970d032c0), [`8f3fa3a`](https://github.com/mastra-ai/mastra/commit/8f3fa3a652bb77da092f913ec51ae46e3a7e27dc), [`cd29ad2`](https://github.com/mastra-ai/mastra/commit/cd29ad23a255534e8191f249593849ed29160886), [`bdf4d8c`](https://github.com/mastra-ai/mastra/commit/bdf4d8cdc656d8a2c21d81834bfa3bfa70f56c16), [`854e3da`](https://github.com/mastra-ai/mastra/commit/854e3dad5daac17a91a20986399d3a51f54bf68b), [`ce18d38`](https://github.com/mastra-ai/mastra/commit/ce18d38678c65870350d123955014a8432075fd9), [`cccf9c8`](https://github.com/mastra-ai/mastra/commit/cccf9c8b2d2dfc1a5e63919395b83d78c89682a0), [`61a5705`](https://github.com/mastra-ai/mastra/commit/61a570551278b6743e64243b3ce7d73de915ca8a), [`db70a48`](https://github.com/mastra-ai/mastra/commit/db70a48aeeeeb8e5f92007e8ede52c364ce15287), [`f0fdc14`](https://github.com/mastra-ai/mastra/commit/f0fdc14ee233d619266b3d2bbdeea7d25cfc6d13), [`db18bc9`](https://github.com/mastra-ai/mastra/commit/db18bc9c3825e2c1a0ad9a183cc9935f6691bfa1), [`9b37b56`](https://github.com/mastra-ai/mastra/commit/9b37b565e1f2a76c24f728945cc740c2b09be9da), [`41a23c3`](https://github.com/mastra-ai/mastra/commit/41a23c32f9877d71810f37e24930515df2ff7a0f), [`5d171ad`](https://github.com/mastra-ai/mastra/commit/5d171ad9ef340387276b77c2bb3e83e83332d729), [`f03ae60`](https://github.com/mastra-ai/mastra/commit/f03ae60500fe350c9d828621006cdafe1975fdd8), [`d1e74a0`](https://github.com/mastra-ai/mastra/commit/d1e74a0a293866dece31022047f5dbab65a304d0), [`39e7869`](https://github.com/mastra-ai/mastra/commit/39e7869bc7d0ee391077ce291474d8a84eedccff), [`5761926`](https://github.com/mastra-ai/mastra/commit/57619260c4a2cdd598763abbacd90de594c6bc76), [`c900fdd`](https://github.com/mastra-ai/mastra/commit/c900fdd504c41348efdffb205cfe80d48c38fa33), [`604a79f`](https://github.com/mastra-ai/mastra/commit/604a79fecf276e26a54a3fe01bb94e65315d2e0e), [`887f0b4`](https://github.com/mastra-ai/mastra/commit/887f0b4746cdbd7cb7d6b17ac9f82aeb58037ea5), [`2562143`](https://github.com/mastra-ai/mastra/commit/256214336b4faa78646c9c1776612393790d8784), [`ef11a61`](https://github.com/mastra-ai/mastra/commit/ef11a61920fa0ed08a5b7ceedd192875af119749)]:
|
|
26
|
+
- @mastra/core@1.0.0-beta.6
|
|
27
|
+
|
|
3
28
|
## 1.0.0-beta.2
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -213,6 +213,17 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
213
213
|
);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Searches all threads in the KV store to find a message by its ID.
|
|
218
|
+
*
|
|
219
|
+
* **Performance Warning**: This method sequentially scans all threads to locate
|
|
220
|
+
* the message. For stores with many threads, this can result in significant
|
|
221
|
+
* latency and API calls. When possible, callers should provide the `threadId`
|
|
222
|
+
* directly to avoid this full scan.
|
|
223
|
+
*
|
|
224
|
+
* @param messageId - The globally unique message ID to search for
|
|
225
|
+
* @returns The message with its threadId if found, null otherwise
|
|
226
|
+
*/
|
|
216
227
|
async findMessageInAnyThread(messageId) {
|
|
217
228
|
try {
|
|
218
229
|
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
@@ -442,10 +453,25 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
442
453
|
async getFullOrder(orderKey) {
|
|
443
454
|
return this.getRange(orderKey, 0, -1);
|
|
444
455
|
}
|
|
445
|
-
|
|
456
|
+
/**
|
|
457
|
+
* Retrieves messages specified in the include array along with their surrounding context.
|
|
458
|
+
*
|
|
459
|
+
* **Performance Note**: When `threadId` is not provided in an include entry, this method
|
|
460
|
+
* must call `findMessageInAnyThread` which sequentially scans all threads in the KV store.
|
|
461
|
+
* For optimal performance, callers should provide `threadId` in include entries when known.
|
|
462
|
+
*
|
|
463
|
+
* @param include - Array of message IDs to include, optionally with context windows
|
|
464
|
+
* @param messageIds - Set to accumulate the message IDs that should be fetched
|
|
465
|
+
*/
|
|
466
|
+
async getIncludedMessagesWithContext(include, messageIds) {
|
|
446
467
|
await Promise.all(
|
|
447
468
|
include.map(async (item) => {
|
|
448
|
-
|
|
469
|
+
let targetThreadId = item.threadId;
|
|
470
|
+
if (!targetThreadId) {
|
|
471
|
+
const foundMessage = await this.findMessageInAnyThread(item.id);
|
|
472
|
+
if (!foundMessage) return;
|
|
473
|
+
targetThreadId = foundMessage.threadId;
|
|
474
|
+
}
|
|
449
475
|
if (!targetThreadId) return;
|
|
450
476
|
const threadMessagesKey = this.getThreadMessagesKey(targetThreadId);
|
|
451
477
|
messageIds.add(item.id);
|
|
@@ -478,6 +504,13 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
478
504
|
this.logger?.debug(`No message order found for thread ${threadId}, skipping latest messages`);
|
|
479
505
|
}
|
|
480
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Fetches and parses messages from one or more threads.
|
|
509
|
+
*
|
|
510
|
+
* **Performance Note**: When neither `include` entries with `threadId` nor `targetThreadId`
|
|
511
|
+
* are provided, this method falls back to `findMessageInAnyThread` which scans all threads.
|
|
512
|
+
* For optimal performance, provide `threadId` in include entries or specify `targetThreadId`.
|
|
513
|
+
*/
|
|
481
514
|
async fetchAndParseMessagesFromMultipleThreads(messageIds, include, targetThreadId) {
|
|
482
515
|
const messageIdToThreadId = /* @__PURE__ */ new Map();
|
|
483
516
|
if (include) {
|
|
@@ -519,6 +552,14 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
519
552
|
);
|
|
520
553
|
return messages.filter((msg) => msg !== null);
|
|
521
554
|
}
|
|
555
|
+
/**
|
|
556
|
+
* Retrieves messages by their IDs.
|
|
557
|
+
*
|
|
558
|
+
* **Performance Warning**: This method calls `findMessageInAnyThread` for each message ID,
|
|
559
|
+
* which scans all threads in the KV store. For large numbers of messages or threads,
|
|
560
|
+
* this can result in significant latency. Consider using `listMessages` with specific
|
|
561
|
+
* thread IDs when the thread context is known.
|
|
562
|
+
*/
|
|
522
563
|
async listMessagesById({ messageIds }) {
|
|
523
564
|
if (messageIds.length === 0) return { messages: [] };
|
|
524
565
|
try {
|
|
@@ -552,15 +593,17 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
552
593
|
}
|
|
553
594
|
async listMessages(args) {
|
|
554
595
|
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
555
|
-
|
|
596
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
597
|
+
const isValidThreadId = (id) => typeof id === "string" && id.trim().length > 0;
|
|
598
|
+
if (threadIds.length === 0 || threadIds.some((id) => !isValidThreadId(id))) {
|
|
556
599
|
throw new error.MastraError(
|
|
557
600
|
{
|
|
558
601
|
id: "STORAGE_CLOUDFLARE_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
559
602
|
domain: error.ErrorDomain.STORAGE,
|
|
560
603
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
561
|
-
details: { threadId }
|
|
604
|
+
details: { threadId: Array.isArray(threadId) ? JSON.stringify(threadId) : String(threadId) }
|
|
562
605
|
},
|
|
563
|
-
new Error("threadId must be a non-empty string")
|
|
606
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
564
607
|
);
|
|
565
608
|
}
|
|
566
609
|
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
@@ -579,16 +622,18 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
579
622
|
}
|
|
580
623
|
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
581
624
|
const threadMessageIds = /* @__PURE__ */ new Set();
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
625
|
+
for (const tid of threadIds) {
|
|
626
|
+
try {
|
|
627
|
+
const threadMessagesKey = this.getThreadMessagesKey(tid);
|
|
628
|
+
const allIds = await this.getFullOrder(threadMessagesKey);
|
|
629
|
+
allIds.forEach((id) => threadMessageIds.add(id));
|
|
630
|
+
} catch {
|
|
631
|
+
}
|
|
587
632
|
}
|
|
588
633
|
const threadMessages = await this.fetchAndParseMessagesFromMultipleThreads(
|
|
589
634
|
Array.from(threadMessageIds),
|
|
590
635
|
void 0,
|
|
591
|
-
|
|
636
|
+
threadIds.length === 1 ? threadIds[0] : void 0
|
|
592
637
|
);
|
|
593
638
|
let filteredThreadMessages = threadMessages;
|
|
594
639
|
if (resourceId) {
|
|
@@ -633,7 +678,7 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
633
678
|
let includedMessages = [];
|
|
634
679
|
if (include && include.length > 0) {
|
|
635
680
|
const includedMessageIds = /* @__PURE__ */ new Set();
|
|
636
|
-
await this.getIncludedMessagesWithContext(
|
|
681
|
+
await this.getIncludedMessagesWithContext(include, includedMessageIds);
|
|
637
682
|
const paginatedIds = new Set(paginatedMessages.map((m) => m.id));
|
|
638
683
|
const idsToFetch = Array.from(includedMessageIds).filter((id) => !paginatedIds.has(id));
|
|
639
684
|
if (idsToFetch.length > 0) {
|
|
@@ -679,7 +724,11 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
679
724
|
type: message.type !== "v2" ? message.type : void 0,
|
|
680
725
|
createdAt: storage.ensureDate(message.createdAt)
|
|
681
726
|
}));
|
|
682
|
-
const
|
|
727
|
+
const primaryThreadId = Array.isArray(threadId) ? threadId[0] : threadId;
|
|
728
|
+
const list = new agent.MessageList({ threadId: primaryThreadId, resourceId }).add(
|
|
729
|
+
prepared,
|
|
730
|
+
"memory"
|
|
731
|
+
);
|
|
683
732
|
let finalMessages = list.get.all.db();
|
|
684
733
|
finalMessages = finalMessages.sort((a, b) => {
|
|
685
734
|
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
@@ -695,7 +744,10 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
695
744
|
const cmp = direction === "ASC" ? String(aVal).localeCompare(String(bVal)) : String(bVal).localeCompare(String(aVal));
|
|
696
745
|
return cmp !== 0 ? cmp : a.id.localeCompare(b.id);
|
|
697
746
|
});
|
|
698
|
-
const
|
|
747
|
+
const threadIdSet = new Set(threadIds);
|
|
748
|
+
const returnedThreadMessageIds = new Set(
|
|
749
|
+
finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
|
|
750
|
+
);
|
|
699
751
|
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
700
752
|
const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + paginatedCount < total;
|
|
701
753
|
return {
|
|
@@ -711,9 +763,9 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
|
711
763
|
id: "CLOUDFLARE_STORAGE_LIST_MESSAGES_FAILED",
|
|
712
764
|
domain: error.ErrorDomain.STORAGE,
|
|
713
765
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
714
|
-
text: `Failed to list messages for thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
766
|
+
text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
715
767
|
details: {
|
|
716
|
-
threadId,
|
|
768
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
717
769
|
resourceId: resourceId ?? ""
|
|
718
770
|
}
|
|
719
771
|
},
|
|
@@ -1465,17 +1517,7 @@ var StoreOperationsCloudflare = class extends storage.StoreOperations {
|
|
|
1465
1517
|
}
|
|
1466
1518
|
};
|
|
1467
1519
|
function transformScoreRow(row) {
|
|
1468
|
-
|
|
1469
|
-
deserialized.input = storage.safelyParseJSON(row.input);
|
|
1470
|
-
deserialized.output = storage.safelyParseJSON(row.output);
|
|
1471
|
-
deserialized.scorer = storage.safelyParseJSON(row.scorer);
|
|
1472
|
-
deserialized.preprocessStepResult = storage.safelyParseJSON(row.preprocessStepResult);
|
|
1473
|
-
deserialized.analyzeStepResult = storage.safelyParseJSON(row.analyzeStepResult);
|
|
1474
|
-
deserialized.metadata = storage.safelyParseJSON(row.metadata);
|
|
1475
|
-
deserialized.additionalContext = storage.safelyParseJSON(row.additionalContext);
|
|
1476
|
-
deserialized.requestContext = storage.safelyParseJSON(row.requestContext);
|
|
1477
|
-
deserialized.entity = storage.safelyParseJSON(row.entity);
|
|
1478
|
-
return deserialized;
|
|
1520
|
+
return storage.transformScoreRow(row);
|
|
1479
1521
|
}
|
|
1480
1522
|
var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
1481
1523
|
operations;
|