@mastra/dynamodb 0.10.0 → 0.10.1-alpha.0

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.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var clientDynamodb = require('@aws-sdk/client-dynamodb');
4
4
  var libDynamodb = require('@aws-sdk/lib-dynamodb');
5
+ var agent = require('@mastra/core/agent');
5
6
  var storage = require('@mastra/core/storage');
6
7
  var electrodb = require('electrodb');
7
8
 
@@ -890,24 +891,38 @@ var DynamoDBStore = class extends storage.MastraStorage {
890
891
  throw error;
891
892
  }
892
893
  }
893
- // Message operations
894
- async getMessages(args) {
895
- const { threadId, selectBy } = args;
894
+ async getMessages({
895
+ threadId,
896
+ resourceId,
897
+ selectBy,
898
+ format
899
+ }) {
896
900
  this.logger.debug("Getting messages", { threadId, selectBy });
897
901
  try {
898
902
  const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
899
903
  if (selectBy?.last && typeof selectBy.last === "number") {
900
904
  const results2 = await query.go({ limit: selectBy.last, reverse: true });
901
- return results2.data.map((data) => this.parseMessageData(data));
905
+ const list2 = new agent.MessageList({ threadId, resourceId }).add(
906
+ results2.data.map((data) => this.parseMessageData(data)),
907
+ "memory"
908
+ );
909
+ if (format === `v2`) return list2.get.all.mastra();
910
+ return list2.get.all.v1();
902
911
  }
903
912
  const results = await query.go();
904
- return results.data.map((data) => this.parseMessageData(data));
913
+ const list = new agent.MessageList({ threadId, resourceId }).add(
914
+ results.data.map((data) => this.parseMessageData(data)),
915
+ "memory"
916
+ );
917
+ if (format === `v2`) return list.get.all.mastra();
918
+ return list.get.all.v1();
905
919
  } catch (error) {
906
920
  this.logger.error("Failed to get messages", { threadId, error });
907
921
  throw error;
908
922
  }
909
923
  }
910
- async saveMessages({ messages }) {
924
+ async saveMessages(args) {
925
+ const { messages, format = "v1" } = args;
911
926
  this.logger.debug("Saving messages", { count: messages.length });
912
927
  if (!messages.length) {
913
928
  return [];
@@ -924,10 +939,10 @@ var DynamoDBStore = class extends storage.MastraStorage {
924
939
  resourceId: msg.resourceId,
925
940
  // Ensure complex fields are stringified if not handled by attribute setters
926
941
  content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
927
- toolCallArgs: msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
928
- toolCallIds: msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
929
- toolNames: msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
930
- createdAt: msg.createdAt?.toISOString() || now,
942
+ toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
943
+ toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
944
+ toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
945
+ createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
931
946
  updatedAt: now
932
947
  // Add updatedAt
933
948
  };
@@ -948,7 +963,9 @@ var DynamoDBStore = class extends storage.MastraStorage {
948
963
  await this.service.entities.message.create(messageData).go();
949
964
  }
950
965
  }
951
- return messages;
966
+ const list = new agent.MessageList().add(messages, "memory");
967
+ if (format === `v1`) return list.get.all.v1();
968
+ return list.get.all.mastra();
952
969
  } catch (error) {
953
970
  this.logger.error("Failed to save messages", { error });
954
971
  throw error;
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
2
2
  import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
3
+ import { MessageList } from '@mastra/core/agent';
3
4
  import { MastraStorage, TABLE_TRACES, TABLE_EVALS, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, TABLE_THREADS } from '@mastra/core/storage';
4
5
  import { Entity, Service } from 'electrodb';
5
6
 
@@ -888,24 +889,38 @@ var DynamoDBStore = class extends MastraStorage {
888
889
  throw error;
889
890
  }
890
891
  }
891
- // Message operations
892
- async getMessages(args) {
893
- const { threadId, selectBy } = args;
892
+ async getMessages({
893
+ threadId,
894
+ resourceId,
895
+ selectBy,
896
+ format
897
+ }) {
894
898
  this.logger.debug("Getting messages", { threadId, selectBy });
895
899
  try {
896
900
  const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
897
901
  if (selectBy?.last && typeof selectBy.last === "number") {
898
902
  const results2 = await query.go({ limit: selectBy.last, reverse: true });
899
- return results2.data.map((data) => this.parseMessageData(data));
903
+ const list2 = new MessageList({ threadId, resourceId }).add(
904
+ results2.data.map((data) => this.parseMessageData(data)),
905
+ "memory"
906
+ );
907
+ if (format === `v2`) return list2.get.all.mastra();
908
+ return list2.get.all.v1();
900
909
  }
901
910
  const results = await query.go();
902
- return results.data.map((data) => this.parseMessageData(data));
911
+ const list = new MessageList({ threadId, resourceId }).add(
912
+ results.data.map((data) => this.parseMessageData(data)),
913
+ "memory"
914
+ );
915
+ if (format === `v2`) return list.get.all.mastra();
916
+ return list.get.all.v1();
903
917
  } catch (error) {
904
918
  this.logger.error("Failed to get messages", { threadId, error });
905
919
  throw error;
906
920
  }
907
921
  }
908
- async saveMessages({ messages }) {
922
+ async saveMessages(args) {
923
+ const { messages, format = "v1" } = args;
909
924
  this.logger.debug("Saving messages", { count: messages.length });
910
925
  if (!messages.length) {
911
926
  return [];
@@ -922,10 +937,10 @@ var DynamoDBStore = class extends MastraStorage {
922
937
  resourceId: msg.resourceId,
923
938
  // Ensure complex fields are stringified if not handled by attribute setters
924
939
  content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
925
- toolCallArgs: msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
926
- toolCallIds: msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
927
- toolNames: msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
928
- createdAt: msg.createdAt?.toISOString() || now,
940
+ toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
941
+ toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
942
+ toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
943
+ createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
929
944
  updatedAt: now
930
945
  // Add updatedAt
931
946
  };
@@ -946,7 +961,9 @@ var DynamoDBStore = class extends MastraStorage {
946
961
  await this.service.entities.message.create(messageData).go();
947
962
  }
948
963
  }
949
- return messages;
964
+ const list = new MessageList().add(messages, "memory");
965
+ if (format === `v1`) return list.get.all.v1();
966
+ return list.get.all.mastra();
950
967
  } catch (error) {
951
968
  this.logger.error("Failed to save messages", { error });
952
969
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/dynamodb",
3
- "version": "0.10.0",
3
+ "version": "0.10.1-alpha.0",
4
4
  "description": "DynamoDB storage adapter for Mastra",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -27,8 +27,8 @@
27
27
  "tsup": "^8.4.0",
28
28
  "typescript": "^5.8.2",
29
29
  "vitest": "^3.0.9",
30
- "@internal/lint": "0.0.6",
31
- "@mastra/core": "0.10.0"
30
+ "@internal/lint": "0.0.7",
31
+ "@mastra/core": "0.10.2-alpha.1"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsup src/index.ts --format esm,cjs --clean --treeshake=smallest --splitting",
@@ -11,7 +11,8 @@ import {
11
11
  waitUntilTableExists,
12
12
  waitUntilTableNotExists,
13
13
  } from '@aws-sdk/client-dynamodb';
14
- import type { MessageType, StorageThreadType, WorkflowRun, WorkflowRunState } from '@mastra/core';
14
+ import type { MastraMessageV1, StorageThreadType, WorkflowRun, WorkflowRunState } from '@mastra/core';
15
+ import type { MastraMessageV2 } from '@mastra/core/agent';
15
16
  import { TABLE_EVALS, TABLE_THREADS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
16
17
  import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'vitest';
17
18
  import { DynamoDBStore } from '..';
@@ -388,17 +389,17 @@ describe('DynamoDBStore Integration Tests', () => {
388
389
  });
389
390
 
390
391
  describe('Batch Operations', () => {
391
- test('should handle batch message inserts efficiently (up to 25 items)', async () => {
392
+ test('should handle batch message inserts efficiently (up to 25 items) [v1 storage]', async () => {
392
393
  const startTime = Date.now(); // Get a base time
393
394
  const threadId = 'batch-thread';
394
- const messages: MessageType[] = Array.from({ length: 25 }, (_, i) => ({
395
+ const messages: MastraMessageV1[] = Array.from({ length: 25 }, (_, i) => ({
395
396
  id: `msg-${i}`,
396
397
  threadId,
397
398
  resourceId: 'test-resource',
398
399
  content: `Message ${i}`,
399
400
  // Increment timestamp slightly for each message to ensure order
400
401
  createdAt: new Date(startTime + i),
401
- role: 'user',
402
+ role: i % 2 === 0 ? 'user' : 'assistant',
402
403
  type: 'text',
403
404
  }));
404
405
 
@@ -412,10 +413,36 @@ describe('DynamoDBStore Integration Tests', () => {
412
413
  expect(retrieved[24]?.content).toBe('Message 24');
413
414
  });
414
415
 
416
+ test('should handle batch message inserts efficiently (up to 25 items) [v2 storage]', async () => {
417
+ const startTime = Date.now(); // Get a base time
418
+ const threadId = 'batch-thread';
419
+ const messages: MastraMessageV2[] = Array.from({ length: 25 }, (_, i) => ({
420
+ id: `msg-${i}`,
421
+ threadId,
422
+ resourceId: 'test-resource',
423
+ content: { format: 2, parts: [{ type: 'text', text: `Message ${i}` }] },
424
+ // Increment timestamp slightly for each message to ensure order
425
+ createdAt: new Date(startTime + i),
426
+ role: i % 2 === 0 ? 'user' : 'assistant',
427
+ type: 'text',
428
+ }));
429
+
430
+ // Assuming saveMessages uses BatchWriteItem internally
431
+ await expect(store.saveMessages({ messages, format: 'v2' })).resolves.not.toThrow();
432
+
433
+ const retrieved = await store.getMessages({ threadId, format: 'v2' });
434
+ expect(retrieved).toHaveLength(25);
435
+ // Now the order should be guaranteed by the ascending createdAt timestamp
436
+ if (retrieved[0]?.content?.parts[0]?.type !== `text`) throw new Error(`Expected text part`);
437
+ expect(retrieved[0].content.parts[0].text).toBe('Message 0');
438
+ if (retrieved[24]?.content?.parts?.[0]?.type !== `text`) throw new Error(`Expected text part`);
439
+ expect(retrieved[24].content.parts[0].text).toBe('Message 24');
440
+ });
441
+
415
442
  test('should handle batch inserts exceeding 25 items (if saveMessages chunks)', async () => {
416
443
  const startTime = Date.now(); // Get a base time
417
444
  const threadId = 'batch-thread-large';
418
- const messages: MessageType[] = Array.from({ length: 30 }, (_, i) => ({
445
+ const messages: MastraMessageV1[] = Array.from({ length: 30 }, (_, i) => ({
419
446
  id: `msg-large-${i}`,
420
447
  threadId,
421
448
  resourceId: 'test-resource-large',
@@ -1,6 +1,8 @@
1
1
  import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
2
2
  import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
3
- import type { StorageThreadType, MessageType, WorkflowRunState } from '@mastra/core';
3
+ import type { StorageThreadType, WorkflowRunState, MastraMessageV1 } from '@mastra/core';
4
+ import type { MastraMessageV2 } from '@mastra/core/agent';
5
+ import { MessageList } from '@mastra/core/agent';
4
6
  import {
5
7
  MastraStorage,
6
8
  TABLE_THREADS,
@@ -514,8 +516,14 @@ export class DynamoDBStore extends MastraStorage {
514
516
  }
515
517
 
516
518
  // Message operations
517
- async getMessages(args: StorageGetMessagesArg): Promise<MessageType[]> {
518
- const { threadId, selectBy } = args;
519
+ public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
520
+ public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
521
+ public async getMessages({
522
+ threadId,
523
+ resourceId,
524
+ selectBy,
525
+ format,
526
+ }: StorageGetMessagesArg & { format?: 'v1' | 'v2' }): Promise<MastraMessageV1[] | MastraMessageV2[]> {
519
527
  this.logger.debug('Getting messages', { threadId, selectBy });
520
528
 
521
529
  try {
@@ -530,21 +538,34 @@ export class DynamoDBStore extends MastraStorage {
530
538
  // Assuming default sort is ascending on SK, use reverse: true for descending
531
539
  const results = await query.go({ limit: selectBy.last, reverse: true });
532
540
  // Use arrow function in map to preserve 'this' context for parseMessageData
533
- return results.data.map((data: any) => this.parseMessageData(data)) as MessageType[];
541
+ const list = new MessageList({ threadId, resourceId }).add(
542
+ results.data.map((data: any) => this.parseMessageData(data)),
543
+ 'memory',
544
+ );
545
+ if (format === `v2`) return list.get.all.mastra();
546
+ return list.get.all.v1();
534
547
  }
535
548
 
536
549
  // If no limit specified, get all messages (potentially paginated by ElectroDB)
537
550
  // Consider adding default limit or handling pagination if needed
538
551
  const results = await query.go();
539
- // Use arrow function in map to preserve 'this' context for parseMessageData
540
- return results.data.map((data: any) => this.parseMessageData(data)) as MessageType[];
552
+ const list = new MessageList({ threadId, resourceId }).add(
553
+ results.data.map((data: any) => this.parseMessageData(data)),
554
+ 'memory',
555
+ );
556
+ if (format === `v2`) return list.get.all.mastra();
557
+ return list.get.all.v1();
541
558
  } catch (error) {
542
559
  this.logger.error('Failed to get messages', { threadId, error });
543
560
  throw error;
544
561
  }
545
562
  }
546
-
547
- async saveMessages({ messages }: { messages: MessageType[] }): Promise<MessageType[]> {
563
+ async saveMessages(args: { messages: MastraMessageV1[]; format?: undefined | 'v1' }): Promise<MastraMessageV1[]>;
564
+ async saveMessages(args: { messages: MastraMessageV2[]; format: 'v2' }): Promise<MastraMessageV2[]>;
565
+ async saveMessages(
566
+ args: { messages: MastraMessageV1[]; format?: undefined | 'v1' } | { messages: MastraMessageV2[]; format: 'v2' },
567
+ ): Promise<MastraMessageV2[] | MastraMessageV1[]> {
568
+ const { messages, format = 'v1' } = args;
548
569
  this.logger.debug('Saving messages', { count: messages.length });
549
570
 
550
571
  if (!messages.length) {
@@ -563,10 +584,10 @@ export class DynamoDBStore extends MastraStorage {
563
584
  resourceId: msg.resourceId,
564
585
  // Ensure complex fields are stringified if not handled by attribute setters
565
586
  content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
566
- toolCallArgs: msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : undefined,
567
- toolCallIds: msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : undefined,
568
- toolNames: msg.toolNames ? JSON.stringify(msg.toolNames) : undefined,
569
- createdAt: msg.createdAt?.toISOString() || now,
587
+ toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : undefined,
588
+ toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : undefined,
589
+ toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : undefined,
590
+ createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
570
591
  updatedAt: now, // Add updatedAt
571
592
  };
572
593
  });
@@ -595,7 +616,9 @@ export class DynamoDBStore extends MastraStorage {
595
616
  // Original batch call: await this.service.entities.message.create(batch).go();
596
617
  }
597
618
 
598
- return messages; // Return original message objects
619
+ const list = new MessageList().add(messages, 'memory');
620
+ if (format === `v1`) return list.get.all.v1();
621
+ return list.get.all.mastra();
599
622
  } catch (error) {
600
623
  this.logger.error('Failed to save messages', { error });
601
624
  throw error;
@@ -603,7 +626,7 @@ export class DynamoDBStore extends MastraStorage {
603
626
  }
604
627
 
605
628
  // Helper function to parse message data (handle JSON fields)
606
- private parseMessageData(data: any): MessageType {
629
+ private parseMessageData(data: any): MastraMessageV2 | MastraMessageV1 {
607
630
  // Removed try/catch and JSON.parse logic - now handled by entity 'get' attributes
608
631
  // This function now primarily ensures correct typing and Date conversion.
609
632
  return {
@@ -613,7 +636,7 @@ export class DynamoDBStore extends MastraStorage {
613
636
  updatedAt: data.updatedAt ? new Date(data.updatedAt) : undefined,
614
637
  // Other fields like content, toolCallArgs etc. are assumed to be correctly
615
638
  // transformed by the ElectroDB entity getters.
616
- } as MessageType; // Add explicit type assertion
639
+ };
617
640
  }
618
641
 
619
642
  // Trace operations