@mastra/dynamodb 1.0.0-beta.5 → 1.0.0-beta.7
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 +232 -0
- package/dist/index.cjs +212 -506
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +213 -507
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +32 -0
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +4 -4
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/{score → scores}/index.d.ts +9 -22
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +7 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +10 -15
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +67 -172
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +4 -5
- package/dist/storage/domains/operations/index.d.ts +0 -69
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
- package/dist/storage/domains/score/index.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
|
|
2
2
|
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
3
3
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
4
|
-
import { MastraStorage, createStorageErrorId,
|
|
4
|
+
import { MastraStorage, createStorageErrorId, WorkflowsStorage, normalizePerPage, MemoryStorage, calculatePagination, ScoresStorage, SCORERS_SCHEMA, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, TABLE_SCORERS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
|
|
5
5
|
import { Entity, Service } from 'electrodb';
|
|
6
6
|
import { MessageList } from '@mastra/core/agent';
|
|
7
7
|
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
@@ -937,11 +937,113 @@ function getElectroDbService(client, tableName) {
|
|
|
937
937
|
}
|
|
938
938
|
);
|
|
939
939
|
}
|
|
940
|
+
function resolveDynamoDBConfig(config) {
|
|
941
|
+
if ("service" in config) {
|
|
942
|
+
return config.service;
|
|
943
|
+
}
|
|
944
|
+
const dynamoClient = new DynamoDBClient({
|
|
945
|
+
region: config.region || "us-east-1",
|
|
946
|
+
endpoint: config.endpoint,
|
|
947
|
+
credentials: config.credentials
|
|
948
|
+
});
|
|
949
|
+
const client = DynamoDBDocumentClient.from(dynamoClient);
|
|
950
|
+
return getElectroDbService(client, config.tableName);
|
|
951
|
+
}
|
|
952
|
+
var ENTITY_MAP = {
|
|
953
|
+
[TABLE_THREADS]: "thread",
|
|
954
|
+
[TABLE_MESSAGES]: "message",
|
|
955
|
+
[TABLE_RESOURCES]: "resource",
|
|
956
|
+
[TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
|
|
957
|
+
[TABLE_SCORERS]: "score"
|
|
958
|
+
};
|
|
959
|
+
function getDeleteKey(entityName, item) {
|
|
960
|
+
const key = { entity: entityName };
|
|
961
|
+
switch (entityName) {
|
|
962
|
+
case "thread":
|
|
963
|
+
case "message":
|
|
964
|
+
case "resource":
|
|
965
|
+
case "score":
|
|
966
|
+
key.id = item.id;
|
|
967
|
+
break;
|
|
968
|
+
case "workflow_snapshot":
|
|
969
|
+
key.workflow_name = item.workflow_name;
|
|
970
|
+
key.run_id = item.run_id;
|
|
971
|
+
break;
|
|
972
|
+
default:
|
|
973
|
+
key.id = item.id;
|
|
974
|
+
}
|
|
975
|
+
return key;
|
|
976
|
+
}
|
|
977
|
+
async function deleteTableData(service, tableName) {
|
|
978
|
+
const entityName = ENTITY_MAP[tableName];
|
|
979
|
+
if (!entityName || !service.entities[entityName]) {
|
|
980
|
+
throw new Error(`No entity mapping found for table: ${tableName}`);
|
|
981
|
+
}
|
|
982
|
+
const entity = service.entities[entityName];
|
|
983
|
+
const result = await entity.scan.go({ pages: "all" });
|
|
984
|
+
if (!result.data.length) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
const batchSize = 25;
|
|
988
|
+
for (let i = 0; i < result.data.length; i += batchSize) {
|
|
989
|
+
const batch = result.data.slice(i, i + batchSize);
|
|
990
|
+
const keysToDelete = batch.map((item) => getDeleteKey(entityName, item));
|
|
991
|
+
await entity.delete(keysToDelete).go();
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// src/storage/domains/memory/index.ts
|
|
940
996
|
var MemoryStorageDynamoDB = class extends MemoryStorage {
|
|
941
997
|
service;
|
|
942
|
-
constructor(
|
|
998
|
+
constructor(config) {
|
|
943
999
|
super();
|
|
944
|
-
this.service =
|
|
1000
|
+
this.service = resolveDynamoDBConfig(config);
|
|
1001
|
+
}
|
|
1002
|
+
async dangerouslyClearAll() {
|
|
1003
|
+
await deleteTableData(this.service, TABLE_THREADS);
|
|
1004
|
+
await deleteTableData(this.service, TABLE_MESSAGES);
|
|
1005
|
+
await deleteTableData(this.service, TABLE_RESOURCES);
|
|
1006
|
+
}
|
|
1007
|
+
async deleteMessages(messageIds) {
|
|
1008
|
+
if (!messageIds || messageIds.length === 0) {
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
this.logger.debug("Deleting messages", { count: messageIds.length });
|
|
1012
|
+
try {
|
|
1013
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
1014
|
+
const batchSize = 25;
|
|
1015
|
+
for (let i = 0; i < messageIds.length; i += batchSize) {
|
|
1016
|
+
const batch = messageIds.slice(i, i + batchSize);
|
|
1017
|
+
const messagesToDelete = await Promise.all(
|
|
1018
|
+
batch.map(async (id) => {
|
|
1019
|
+
const result = await this.service.entities.message.get({ entity: "message", id }).go();
|
|
1020
|
+
return result.data;
|
|
1021
|
+
})
|
|
1022
|
+
);
|
|
1023
|
+
for (const message of messagesToDelete) {
|
|
1024
|
+
if (message) {
|
|
1025
|
+
if (message.threadId) {
|
|
1026
|
+
threadIds.add(message.threadId);
|
|
1027
|
+
}
|
|
1028
|
+
await this.service.entities.message.delete({ entity: "message", id: message.id }).go();
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1033
|
+
for (const threadId of threadIds) {
|
|
1034
|
+
await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({ updatedAt: now }).go();
|
|
1035
|
+
}
|
|
1036
|
+
} catch (error) {
|
|
1037
|
+
throw new MastraError(
|
|
1038
|
+
{
|
|
1039
|
+
id: createStorageErrorId("DYNAMODB", "DELETE_MESSAGES", "FAILED"),
|
|
1040
|
+
domain: ErrorDomain.STORAGE,
|
|
1041
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1042
|
+
details: { count: messageIds.length }
|
|
1043
|
+
},
|
|
1044
|
+
error
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
945
1047
|
}
|
|
946
1048
|
// Helper function to parse message data (handle JSON fields)
|
|
947
1049
|
parseMessageData(data) {
|
|
@@ -1635,334 +1737,14 @@ var MemoryStorageDynamoDB = class extends MemoryStorage {
|
|
|
1635
1737
|
}
|
|
1636
1738
|
}
|
|
1637
1739
|
};
|
|
1638
|
-
var StoreOperationsDynamoDB = class extends StoreOperations {
|
|
1639
|
-
client;
|
|
1640
|
-
tableName;
|
|
1641
|
-
service;
|
|
1642
|
-
constructor({
|
|
1643
|
-
service,
|
|
1644
|
-
tableName,
|
|
1645
|
-
client
|
|
1646
|
-
}) {
|
|
1647
|
-
super();
|
|
1648
|
-
this.service = service;
|
|
1649
|
-
this.client = client;
|
|
1650
|
-
this.tableName = tableName;
|
|
1651
|
-
}
|
|
1652
|
-
async hasColumn() {
|
|
1653
|
-
return true;
|
|
1654
|
-
}
|
|
1655
|
-
async dropTable() {
|
|
1656
|
-
}
|
|
1657
|
-
// Helper methods for entity/table mapping
|
|
1658
|
-
getEntityNameForTable(tableName) {
|
|
1659
|
-
const mapping = {
|
|
1660
|
-
[TABLE_THREADS]: "thread",
|
|
1661
|
-
[TABLE_MESSAGES]: "message",
|
|
1662
|
-
[TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
|
|
1663
|
-
[TABLE_SCORERS]: "score",
|
|
1664
|
-
[TABLE_TRACES]: "trace",
|
|
1665
|
-
[TABLE_RESOURCES]: "resource",
|
|
1666
|
-
[TABLE_SPANS]: "ai_span",
|
|
1667
|
-
mastra_agents: "agent"
|
|
1668
|
-
};
|
|
1669
|
-
return mapping[tableName] || null;
|
|
1670
|
-
}
|
|
1671
|
-
/**
|
|
1672
|
-
* Pre-processes a record to ensure Date objects are converted to ISO strings
|
|
1673
|
-
* This is necessary because ElectroDB validation happens before setters are applied
|
|
1674
|
-
*/
|
|
1675
|
-
preprocessRecord(record) {
|
|
1676
|
-
const processed = { ...record };
|
|
1677
|
-
if (processed.createdAt instanceof Date) {
|
|
1678
|
-
processed.createdAt = processed.createdAt.toISOString();
|
|
1679
|
-
}
|
|
1680
|
-
if (processed.updatedAt instanceof Date) {
|
|
1681
|
-
processed.updatedAt = processed.updatedAt.toISOString();
|
|
1682
|
-
}
|
|
1683
|
-
if (processed.created_at instanceof Date) {
|
|
1684
|
-
processed.created_at = processed.created_at.toISOString();
|
|
1685
|
-
}
|
|
1686
|
-
if (processed.result && typeof processed.result === "object") {
|
|
1687
|
-
processed.result = JSON.stringify(processed.result);
|
|
1688
|
-
}
|
|
1689
|
-
if (processed.test_info && typeof processed.test_info === "object") {
|
|
1690
|
-
processed.test_info = JSON.stringify(processed.test_info);
|
|
1691
|
-
} else if (processed.test_info === void 0 || processed.test_info === null) {
|
|
1692
|
-
delete processed.test_info;
|
|
1693
|
-
}
|
|
1694
|
-
if (processed.snapshot && typeof processed.snapshot === "object") {
|
|
1695
|
-
processed.snapshot = JSON.stringify(processed.snapshot);
|
|
1696
|
-
}
|
|
1697
|
-
if (processed.attributes && typeof processed.attributes === "object") {
|
|
1698
|
-
processed.attributes = JSON.stringify(processed.attributes);
|
|
1699
|
-
}
|
|
1700
|
-
if (processed.status && typeof processed.status === "object") {
|
|
1701
|
-
processed.status = JSON.stringify(processed.status);
|
|
1702
|
-
}
|
|
1703
|
-
if (processed.events && typeof processed.events === "object") {
|
|
1704
|
-
processed.events = JSON.stringify(processed.events);
|
|
1705
|
-
}
|
|
1706
|
-
if (processed.links && typeof processed.links === "object") {
|
|
1707
|
-
processed.links = JSON.stringify(processed.links);
|
|
1708
|
-
}
|
|
1709
|
-
return processed;
|
|
1710
|
-
}
|
|
1711
|
-
/**
|
|
1712
|
-
* Validates that the required DynamoDB table exists and is accessible.
|
|
1713
|
-
* This does not check the table structure - it assumes the table
|
|
1714
|
-
* was created with the correct structure via CDK/CloudFormation.
|
|
1715
|
-
*/
|
|
1716
|
-
async validateTableExists() {
|
|
1717
|
-
try {
|
|
1718
|
-
const command = new DescribeTableCommand({
|
|
1719
|
-
TableName: this.tableName
|
|
1720
|
-
});
|
|
1721
|
-
await this.client.send(command);
|
|
1722
|
-
return true;
|
|
1723
|
-
} catch (error) {
|
|
1724
|
-
if (error.name === "ResourceNotFoundException") {
|
|
1725
|
-
return false;
|
|
1726
|
-
}
|
|
1727
|
-
throw new MastraError(
|
|
1728
|
-
{
|
|
1729
|
-
id: createStorageErrorId("DYNAMODB", "VALIDATE_TABLE_EXISTS", "FAILED"),
|
|
1730
|
-
domain: ErrorDomain.STORAGE,
|
|
1731
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1732
|
-
details: { tableName: this.tableName }
|
|
1733
|
-
},
|
|
1734
|
-
error
|
|
1735
|
-
);
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
/**
|
|
1739
|
-
* This method is modified for DynamoDB with ElectroDB single-table design.
|
|
1740
|
-
* It assumes the table is created and managed externally via CDK/CloudFormation.
|
|
1741
|
-
*
|
|
1742
|
-
* This implementation only validates that the required table exists and is accessible.
|
|
1743
|
-
* No table creation is attempted - we simply check if we can access the table.
|
|
1744
|
-
*/
|
|
1745
|
-
async createTable({ tableName }) {
|
|
1746
|
-
this.logger.debug("Validating access to externally managed table", { tableName, physicalTable: this.tableName });
|
|
1747
|
-
try {
|
|
1748
|
-
const tableExists = await this.validateTableExists();
|
|
1749
|
-
if (!tableExists) {
|
|
1750
|
-
this.logger.error(
|
|
1751
|
-
`Table ${this.tableName} does not exist or is not accessible. It should be created via CDK/CloudFormation.`
|
|
1752
|
-
);
|
|
1753
|
-
throw new Error(
|
|
1754
|
-
`Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
|
|
1755
|
-
);
|
|
1756
|
-
}
|
|
1757
|
-
this.logger.debug(`Table ${this.tableName} exists and is accessible`);
|
|
1758
|
-
} catch (error) {
|
|
1759
|
-
this.logger.error("Error validating table access", { tableName: this.tableName, error });
|
|
1760
|
-
throw new MastraError(
|
|
1761
|
-
{
|
|
1762
|
-
id: createStorageErrorId("DYNAMODB", "VALIDATE_TABLE_ACCESS", "FAILED"),
|
|
1763
|
-
domain: ErrorDomain.STORAGE,
|
|
1764
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1765
|
-
details: { tableName: this.tableName }
|
|
1766
|
-
},
|
|
1767
|
-
error
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
async insert({ tableName, record }) {
|
|
1772
|
-
this.logger.debug("DynamoDB insert called", { tableName });
|
|
1773
|
-
const entityName = this.getEntityNameForTable(tableName);
|
|
1774
|
-
if (!entityName || !this.service.entities[entityName]) {
|
|
1775
|
-
throw new MastraError({
|
|
1776
|
-
id: createStorageErrorId("DYNAMODB", "INSERT", "INVALID_ARGS"),
|
|
1777
|
-
domain: ErrorDomain.STORAGE,
|
|
1778
|
-
category: ErrorCategory.USER,
|
|
1779
|
-
text: "No entity defined for tableName",
|
|
1780
|
-
details: { tableName }
|
|
1781
|
-
});
|
|
1782
|
-
}
|
|
1783
|
-
try {
|
|
1784
|
-
const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
|
|
1785
|
-
await this.service.entities[entityName].create(dataToSave).go();
|
|
1786
|
-
} catch (error) {
|
|
1787
|
-
throw new MastraError(
|
|
1788
|
-
{
|
|
1789
|
-
id: createStorageErrorId("DYNAMODB", "INSERT", "FAILED"),
|
|
1790
|
-
domain: ErrorDomain.STORAGE,
|
|
1791
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1792
|
-
details: { tableName }
|
|
1793
|
-
},
|
|
1794
|
-
error
|
|
1795
|
-
);
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
async alterTable(_args) {
|
|
1799
|
-
}
|
|
1800
|
-
/**
|
|
1801
|
-
* Clear all items from a logical "table" (entity type)
|
|
1802
|
-
*/
|
|
1803
|
-
async clearTable({ tableName }) {
|
|
1804
|
-
this.logger.debug("DynamoDB clearTable called", { tableName });
|
|
1805
|
-
const entityName = this.getEntityNameForTable(tableName);
|
|
1806
|
-
if (!entityName || !this.service.entities[entityName]) {
|
|
1807
|
-
throw new MastraError({
|
|
1808
|
-
id: createStorageErrorId("DYNAMODB", "CLEAR_TABLE", "INVALID_ARGS"),
|
|
1809
|
-
domain: ErrorDomain.STORAGE,
|
|
1810
|
-
category: ErrorCategory.USER,
|
|
1811
|
-
text: "No entity defined for tableName",
|
|
1812
|
-
details: { tableName }
|
|
1813
|
-
});
|
|
1814
|
-
}
|
|
1815
|
-
try {
|
|
1816
|
-
const result = await this.service.entities[entityName].scan.go({ pages: "all" });
|
|
1817
|
-
if (!result.data.length) {
|
|
1818
|
-
this.logger.debug(`No records found to clear for ${tableName}`);
|
|
1819
|
-
return;
|
|
1820
|
-
}
|
|
1821
|
-
this.logger.debug(`Found ${result.data.length} records to delete for ${tableName}`);
|
|
1822
|
-
const keysToDelete = result.data.map((item) => {
|
|
1823
|
-
const key = { entity: entityName };
|
|
1824
|
-
switch (entityName) {
|
|
1825
|
-
case "thread":
|
|
1826
|
-
if (!item.id) throw new Error(`Missing required key 'id' for entity 'thread'`);
|
|
1827
|
-
key.id = item.id;
|
|
1828
|
-
break;
|
|
1829
|
-
case "message":
|
|
1830
|
-
if (!item.id) throw new Error(`Missing required key 'id' for entity 'message'`);
|
|
1831
|
-
key.id = item.id;
|
|
1832
|
-
break;
|
|
1833
|
-
case "workflow_snapshot":
|
|
1834
|
-
if (!item.workflow_name)
|
|
1835
|
-
throw new Error(`Missing required key 'workflow_name' for entity 'workflow_snapshot'`);
|
|
1836
|
-
if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'workflow_snapshot'`);
|
|
1837
|
-
key.workflow_name = item.workflow_name;
|
|
1838
|
-
key.run_id = item.run_id;
|
|
1839
|
-
break;
|
|
1840
|
-
case "eval":
|
|
1841
|
-
if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'eval'`);
|
|
1842
|
-
key.run_id = item.run_id;
|
|
1843
|
-
break;
|
|
1844
|
-
case "trace":
|
|
1845
|
-
if (!item.id) throw new Error(`Missing required key 'id' for entity 'trace'`);
|
|
1846
|
-
key.id = item.id;
|
|
1847
|
-
break;
|
|
1848
|
-
case "score":
|
|
1849
|
-
if (!item.id) throw new Error(`Missing required key 'id' for entity 'score'`);
|
|
1850
|
-
key.id = item.id;
|
|
1851
|
-
break;
|
|
1852
|
-
case "resource":
|
|
1853
|
-
if (!item.id) throw new Error(`Missing required key 'id' for entity 'resource'`);
|
|
1854
|
-
key.id = item.id;
|
|
1855
|
-
break;
|
|
1856
|
-
default:
|
|
1857
|
-
this.logger.warn(`Unknown entity type encountered during clearTable: ${entityName}`);
|
|
1858
|
-
throw new Error(`Cannot construct delete key for unknown entity type: ${entityName}`);
|
|
1859
|
-
}
|
|
1860
|
-
return key;
|
|
1861
|
-
});
|
|
1862
|
-
const batchSize = 25;
|
|
1863
|
-
for (let i = 0; i < keysToDelete.length; i += batchSize) {
|
|
1864
|
-
const batchKeys = keysToDelete.slice(i, i + batchSize);
|
|
1865
|
-
await this.service.entities[entityName].delete(batchKeys).go();
|
|
1866
|
-
}
|
|
1867
|
-
this.logger.debug(`Successfully cleared all records for ${tableName}`);
|
|
1868
|
-
} catch (error) {
|
|
1869
|
-
throw new MastraError(
|
|
1870
|
-
{
|
|
1871
|
-
id: createStorageErrorId("DYNAMODB", "CLEAR_TABLE", "FAILED"),
|
|
1872
|
-
domain: ErrorDomain.STORAGE,
|
|
1873
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1874
|
-
details: { tableName }
|
|
1875
|
-
},
|
|
1876
|
-
error
|
|
1877
|
-
);
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
/**
|
|
1881
|
-
* Insert multiple records as a batch
|
|
1882
|
-
*/
|
|
1883
|
-
async batchInsert({ tableName, records }) {
|
|
1884
|
-
this.logger.debug("DynamoDB batchInsert called", { tableName, count: records.length });
|
|
1885
|
-
const entityName = this.getEntityNameForTable(tableName);
|
|
1886
|
-
if (!entityName || !this.service.entities[entityName]) {
|
|
1887
|
-
throw new MastraError({
|
|
1888
|
-
id: createStorageErrorId("DYNAMODB", "BATCH_INSERT", "INVALID_ARGS"),
|
|
1889
|
-
domain: ErrorDomain.STORAGE,
|
|
1890
|
-
category: ErrorCategory.USER,
|
|
1891
|
-
text: "No entity defined for tableName",
|
|
1892
|
-
details: { tableName }
|
|
1893
|
-
});
|
|
1894
|
-
}
|
|
1895
|
-
const recordsToSave = records.map((rec) => ({ entity: entityName, ...this.preprocessRecord(rec) }));
|
|
1896
|
-
const batchSize = 25;
|
|
1897
|
-
const batches = [];
|
|
1898
|
-
for (let i = 0; i < recordsToSave.length; i += batchSize) {
|
|
1899
|
-
const batch = recordsToSave.slice(i, i + batchSize);
|
|
1900
|
-
batches.push(batch);
|
|
1901
|
-
}
|
|
1902
|
-
try {
|
|
1903
|
-
for (const batch of batches) {
|
|
1904
|
-
for (const recordData of batch) {
|
|
1905
|
-
if (!recordData.entity) {
|
|
1906
|
-
this.logger.error("Missing entity property in record data for batchInsert", { recordData, tableName });
|
|
1907
|
-
throw new Error(`Internal error: Missing entity property during batchInsert for ${tableName}`);
|
|
1908
|
-
}
|
|
1909
|
-
this.logger.debug("Attempting to create record in batchInsert:", { entityName, recordData });
|
|
1910
|
-
await this.service.entities[entityName].create(recordData).go();
|
|
1911
|
-
}
|
|
1912
|
-
}
|
|
1913
|
-
} catch (error) {
|
|
1914
|
-
throw new MastraError(
|
|
1915
|
-
{
|
|
1916
|
-
id: createStorageErrorId("DYNAMODB", "BATCH_INSERT", "FAILED"),
|
|
1917
|
-
domain: ErrorDomain.STORAGE,
|
|
1918
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1919
|
-
details: { tableName }
|
|
1920
|
-
},
|
|
1921
|
-
error
|
|
1922
|
-
);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
/**
|
|
1926
|
-
* Load a record by its keys
|
|
1927
|
-
*/
|
|
1928
|
-
async load({ tableName, keys }) {
|
|
1929
|
-
this.logger.debug("DynamoDB load called", { tableName, keys });
|
|
1930
|
-
const entityName = this.getEntityNameForTable(tableName);
|
|
1931
|
-
if (!entityName || !this.service.entities[entityName]) {
|
|
1932
|
-
throw new MastraError({
|
|
1933
|
-
id: createStorageErrorId("DYNAMODB", "LOAD", "INVALID_ARGS"),
|
|
1934
|
-
domain: ErrorDomain.STORAGE,
|
|
1935
|
-
category: ErrorCategory.USER,
|
|
1936
|
-
text: "No entity defined for tableName",
|
|
1937
|
-
details: { tableName }
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
try {
|
|
1941
|
-
const keyObject = { entity: entityName, ...keys };
|
|
1942
|
-
const result = await this.service.entities[entityName].get(keyObject).go();
|
|
1943
|
-
if (!result.data) {
|
|
1944
|
-
return null;
|
|
1945
|
-
}
|
|
1946
|
-
let data = result.data;
|
|
1947
|
-
return data;
|
|
1948
|
-
} catch (error) {
|
|
1949
|
-
throw new MastraError(
|
|
1950
|
-
{
|
|
1951
|
-
id: createStorageErrorId("DYNAMODB", "LOAD", "FAILED"),
|
|
1952
|
-
domain: ErrorDomain.STORAGE,
|
|
1953
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1954
|
-
details: { tableName }
|
|
1955
|
-
},
|
|
1956
|
-
error
|
|
1957
|
-
);
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
};
|
|
1961
1740
|
var ScoresStorageDynamoDB = class extends ScoresStorage {
|
|
1962
1741
|
service;
|
|
1963
|
-
constructor(
|
|
1742
|
+
constructor(config) {
|
|
1964
1743
|
super();
|
|
1965
|
-
this.service =
|
|
1744
|
+
this.service = resolveDynamoDBConfig(config);
|
|
1745
|
+
}
|
|
1746
|
+
async dangerouslyClearAll() {
|
|
1747
|
+
await deleteTableData(this.service, TABLE_SCORERS);
|
|
1966
1748
|
}
|
|
1967
1749
|
/**
|
|
1968
1750
|
* DynamoDB-specific score row transformation.
|
|
@@ -2019,7 +1801,7 @@ var ScoresStorageDynamoDB = class extends ScoresStorage {
|
|
|
2019
1801
|
domain: ErrorDomain.STORAGE,
|
|
2020
1802
|
category: ErrorCategory.USER,
|
|
2021
1803
|
details: {
|
|
2022
|
-
scorer: score.scorer?.id ?? "unknown",
|
|
1804
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
2023
1805
|
entityId: score.entityId ?? "unknown",
|
|
2024
1806
|
entityType: score.entityType ?? "unknown",
|
|
2025
1807
|
traceId: score.traceId ?? "",
|
|
@@ -2262,44 +2044,104 @@ function formatWorkflowRun(snapshotData) {
|
|
|
2262
2044
|
}
|
|
2263
2045
|
var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
|
|
2264
2046
|
service;
|
|
2265
|
-
constructor(
|
|
2047
|
+
constructor(config) {
|
|
2266
2048
|
super();
|
|
2267
|
-
this.service =
|
|
2049
|
+
this.service = resolveDynamoDBConfig(config);
|
|
2268
2050
|
}
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2051
|
+
async dangerouslyClearAll() {
|
|
2052
|
+
await deleteTableData(this.service, TABLE_WORKFLOW_SNAPSHOT);
|
|
2053
|
+
}
|
|
2054
|
+
async updateWorkflowResults({
|
|
2055
|
+
workflowName,
|
|
2056
|
+
runId,
|
|
2057
|
+
stepId,
|
|
2058
|
+
result,
|
|
2059
|
+
requestContext
|
|
2275
2060
|
}) {
|
|
2276
|
-
|
|
2061
|
+
try {
|
|
2062
|
+
const existingSnapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
2063
|
+
let snapshot;
|
|
2064
|
+
if (!existingSnapshot) {
|
|
2065
|
+
snapshot = {
|
|
2066
|
+
context: {},
|
|
2067
|
+
activePaths: [],
|
|
2068
|
+
timestamp: Date.now(),
|
|
2069
|
+
suspendedPaths: {},
|
|
2070
|
+
activeStepsPath: {},
|
|
2071
|
+
resumeLabels: {},
|
|
2072
|
+
serializedStepGraph: [],
|
|
2073
|
+
status: "pending",
|
|
2074
|
+
value: {},
|
|
2075
|
+
waitingPaths: {},
|
|
2076
|
+
runId,
|
|
2077
|
+
requestContext: {}
|
|
2078
|
+
};
|
|
2079
|
+
} else {
|
|
2080
|
+
snapshot = existingSnapshot;
|
|
2081
|
+
}
|
|
2082
|
+
snapshot.context[stepId] = result;
|
|
2083
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2084
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2085
|
+
return snapshot.context;
|
|
2086
|
+
} catch (error) {
|
|
2087
|
+
if (error instanceof MastraError) throw error;
|
|
2088
|
+
throw new MastraError(
|
|
2089
|
+
{
|
|
2090
|
+
id: createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
2091
|
+
domain: ErrorDomain.STORAGE,
|
|
2092
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2093
|
+
details: { workflowName, runId, stepId }
|
|
2094
|
+
},
|
|
2095
|
+
error
|
|
2096
|
+
);
|
|
2097
|
+
}
|
|
2277
2098
|
}
|
|
2278
|
-
updateWorkflowState({
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2099
|
+
async updateWorkflowState({
|
|
2100
|
+
workflowName,
|
|
2101
|
+
runId,
|
|
2102
|
+
opts
|
|
2282
2103
|
}) {
|
|
2283
|
-
|
|
2104
|
+
try {
|
|
2105
|
+
const existingSnapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
|
|
2106
|
+
if (!existingSnapshot || !existingSnapshot.context) {
|
|
2107
|
+
return void 0;
|
|
2108
|
+
}
|
|
2109
|
+
const updatedSnapshot = { ...existingSnapshot, ...opts };
|
|
2110
|
+
await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
|
|
2111
|
+
return updatedSnapshot;
|
|
2112
|
+
} catch (error) {
|
|
2113
|
+
if (error instanceof MastraError) throw error;
|
|
2114
|
+
throw new MastraError(
|
|
2115
|
+
{
|
|
2116
|
+
id: createStorageErrorId("DYNAMODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
2117
|
+
domain: ErrorDomain.STORAGE,
|
|
2118
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2119
|
+
details: { workflowName, runId }
|
|
2120
|
+
},
|
|
2121
|
+
error
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2284
2124
|
}
|
|
2285
2125
|
// Workflow operations
|
|
2286
2126
|
async persistWorkflowSnapshot({
|
|
2287
2127
|
workflowName,
|
|
2288
2128
|
runId,
|
|
2289
2129
|
resourceId,
|
|
2290
|
-
snapshot
|
|
2130
|
+
snapshot,
|
|
2131
|
+
createdAt,
|
|
2132
|
+
updatedAt
|
|
2291
2133
|
}) {
|
|
2292
2134
|
this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
|
|
2293
2135
|
try {
|
|
2294
|
-
const now =
|
|
2136
|
+
const now = /* @__PURE__ */ new Date();
|
|
2295
2137
|
const data = {
|
|
2296
2138
|
entity: "workflow_snapshot",
|
|
2297
2139
|
// Add entity type
|
|
2298
2140
|
workflow_name: workflowName,
|
|
2299
2141
|
run_id: runId,
|
|
2300
2142
|
snapshot: JSON.stringify(snapshot),
|
|
2301
|
-
createdAt: now,
|
|
2302
|
-
updatedAt: now,
|
|
2143
|
+
createdAt: (createdAt ?? now).toISOString(),
|
|
2144
|
+
updatedAt: (updatedAt ?? now).toISOString(),
|
|
2303
2145
|
resourceId
|
|
2304
2146
|
};
|
|
2305
2147
|
await this.service.entities.workflow_snapshot.upsert(data).go();
|
|
@@ -2507,6 +2349,9 @@ var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
|
|
|
2507
2349
|
};
|
|
2508
2350
|
|
|
2509
2351
|
// src/storage/index.ts
|
|
2352
|
+
var isClientConfig = (config) => {
|
|
2353
|
+
return "client" in config;
|
|
2354
|
+
};
|
|
2510
2355
|
var DynamoDBStore = class extends MastraStorage {
|
|
2511
2356
|
tableName;
|
|
2512
2357
|
client;
|
|
@@ -2524,24 +2369,23 @@ var DynamoDBStore = class extends MastraStorage {
|
|
|
2524
2369
|
`DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
|
|
2525
2370
|
);
|
|
2526
2371
|
}
|
|
2527
|
-
const dynamoClient = new DynamoDBClient({
|
|
2528
|
-
region: config.region || "us-east-1",
|
|
2529
|
-
endpoint: config.endpoint,
|
|
2530
|
-
credentials: config.credentials
|
|
2531
|
-
});
|
|
2532
2372
|
this.tableName = config.tableName;
|
|
2533
|
-
|
|
2373
|
+
if (isClientConfig(config)) {
|
|
2374
|
+
this.client = config.client;
|
|
2375
|
+
} else {
|
|
2376
|
+
const dynamoClient = new DynamoDBClient({
|
|
2377
|
+
region: config.region || "us-east-1",
|
|
2378
|
+
endpoint: config.endpoint,
|
|
2379
|
+
credentials: config.credentials
|
|
2380
|
+
});
|
|
2381
|
+
this.client = DynamoDBDocumentClient.from(dynamoClient);
|
|
2382
|
+
}
|
|
2534
2383
|
this.service = getElectroDbService(this.client, this.tableName);
|
|
2535
|
-
const
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
});
|
|
2540
|
-
const workflows = new WorkflowStorageDynamoDB({ service: this.service });
|
|
2541
|
-
const memory = new MemoryStorageDynamoDB({ service: this.service });
|
|
2542
|
-
const scores = new ScoresStorageDynamoDB({ service: this.service });
|
|
2384
|
+
const domainConfig = { service: this.service };
|
|
2385
|
+
const workflows = new WorkflowStorageDynamoDB(domainConfig);
|
|
2386
|
+
const memory = new MemoryStorageDynamoDB(domainConfig);
|
|
2387
|
+
const scores = new ScoresStorageDynamoDB(domainConfig);
|
|
2543
2388
|
this.stores = {
|
|
2544
|
-
operations,
|
|
2545
2389
|
workflows,
|
|
2546
2390
|
memory,
|
|
2547
2391
|
scores
|
|
@@ -2563,8 +2407,11 @@ var DynamoDBStore = class extends MastraStorage {
|
|
|
2563
2407
|
resourceWorkingMemory: true,
|
|
2564
2408
|
hasColumn: false,
|
|
2565
2409
|
createTable: false,
|
|
2566
|
-
deleteMessages:
|
|
2567
|
-
|
|
2410
|
+
deleteMessages: true,
|
|
2411
|
+
observability: false,
|
|
2412
|
+
indexManagement: false,
|
|
2413
|
+
listScoresBySpan: true,
|
|
2414
|
+
agents: false
|
|
2568
2415
|
};
|
|
2569
2416
|
}
|
|
2570
2417
|
/**
|
|
@@ -2634,109 +2481,10 @@ var DynamoDBStore = class extends MastraStorage {
|
|
|
2634
2481
|
throw err;
|
|
2635
2482
|
});
|
|
2636
2483
|
}
|
|
2637
|
-
async createTable({ tableName, schema }) {
|
|
2638
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
2639
|
-
}
|
|
2640
|
-
async alterTable(_args) {
|
|
2641
|
-
return this.stores.operations.alterTable(_args);
|
|
2642
|
-
}
|
|
2643
|
-
async clearTable({ tableName }) {
|
|
2644
|
-
return this.stores.operations.clearTable({ tableName });
|
|
2645
|
-
}
|
|
2646
|
-
async dropTable({ tableName }) {
|
|
2647
|
-
return this.stores.operations.dropTable({ tableName });
|
|
2648
|
-
}
|
|
2649
|
-
async insert({ tableName, record }) {
|
|
2650
|
-
return this.stores.operations.insert({ tableName, record });
|
|
2651
|
-
}
|
|
2652
|
-
async batchInsert({ tableName, records }) {
|
|
2653
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
2654
|
-
}
|
|
2655
|
-
async load({ tableName, keys }) {
|
|
2656
|
-
return this.stores.operations.load({ tableName, keys });
|
|
2657
|
-
}
|
|
2658
|
-
// Thread operations
|
|
2659
|
-
async getThreadById({ threadId }) {
|
|
2660
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
2661
|
-
}
|
|
2662
|
-
async saveThread({ thread }) {
|
|
2663
|
-
return this.stores.memory.saveThread({ thread });
|
|
2664
|
-
}
|
|
2665
|
-
async updateThread({
|
|
2666
|
-
id,
|
|
2667
|
-
title,
|
|
2668
|
-
metadata
|
|
2669
|
-
}) {
|
|
2670
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2671
|
-
}
|
|
2672
|
-
async deleteThread({ threadId }) {
|
|
2673
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
2674
|
-
}
|
|
2675
|
-
async listMessagesById(args) {
|
|
2676
|
-
return this.stores.memory.listMessagesById(args);
|
|
2677
|
-
}
|
|
2678
|
-
async saveMessages(args) {
|
|
2679
|
-
return this.stores.memory.saveMessages(args);
|
|
2680
|
-
}
|
|
2681
|
-
async updateMessages(_args) {
|
|
2682
|
-
return this.stores.memory.updateMessages(_args);
|
|
2683
|
-
}
|
|
2684
|
-
// Workflow operations
|
|
2685
|
-
async updateWorkflowResults({
|
|
2686
|
-
workflowName,
|
|
2687
|
-
runId,
|
|
2688
|
-
stepId,
|
|
2689
|
-
result,
|
|
2690
|
-
requestContext
|
|
2691
|
-
}) {
|
|
2692
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2693
|
-
}
|
|
2694
|
-
async updateWorkflowState({
|
|
2695
|
-
workflowName,
|
|
2696
|
-
runId,
|
|
2697
|
-
opts
|
|
2698
|
-
}) {
|
|
2699
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2700
|
-
}
|
|
2701
|
-
async persistWorkflowSnapshot({
|
|
2702
|
-
workflowName,
|
|
2703
|
-
runId,
|
|
2704
|
-
resourceId,
|
|
2705
|
-
snapshot
|
|
2706
|
-
}) {
|
|
2707
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2708
|
-
}
|
|
2709
|
-
async loadWorkflowSnapshot({
|
|
2710
|
-
workflowName,
|
|
2711
|
-
runId
|
|
2712
|
-
}) {
|
|
2713
|
-
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2714
|
-
}
|
|
2715
|
-
async listWorkflowRuns(args) {
|
|
2716
|
-
return this.stores.workflows.listWorkflowRuns(args);
|
|
2717
|
-
}
|
|
2718
|
-
async getWorkflowRunById(args) {
|
|
2719
|
-
return this.stores.workflows.getWorkflowRunById(args);
|
|
2720
|
-
}
|
|
2721
|
-
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
2722
|
-
return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
|
|
2723
|
-
}
|
|
2724
|
-
async getResourceById({ resourceId }) {
|
|
2725
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
2726
|
-
}
|
|
2727
|
-
async saveResource({ resource }) {
|
|
2728
|
-
return this.stores.memory.saveResource({ resource });
|
|
2729
|
-
}
|
|
2730
|
-
async updateResource({
|
|
2731
|
-
resourceId,
|
|
2732
|
-
workingMemory,
|
|
2733
|
-
metadata
|
|
2734
|
-
}) {
|
|
2735
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2736
|
-
}
|
|
2737
2484
|
/**
|
|
2738
2485
|
* Closes the DynamoDB client connection and cleans up resources.
|
|
2739
|
-
*
|
|
2486
|
+
*
|
|
2487
|
+
* This will close the DynamoDB client, including pre-configured clients.
|
|
2740
2488
|
*/
|
|
2741
2489
|
async close() {
|
|
2742
2490
|
this.logger.debug("Closing DynamoDB client for store:", { name: this.name });
|
|
@@ -2754,48 +2502,6 @@ var DynamoDBStore = class extends MastraStorage {
|
|
|
2754
2502
|
);
|
|
2755
2503
|
}
|
|
2756
2504
|
}
|
|
2757
|
-
/**
|
|
2758
|
-
* SCORERS - Not implemented
|
|
2759
|
-
*/
|
|
2760
|
-
async getScoreById({ id: _id }) {
|
|
2761
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
2762
|
-
}
|
|
2763
|
-
async saveScore(score) {
|
|
2764
|
-
return this.stores.scores.saveScore(score);
|
|
2765
|
-
}
|
|
2766
|
-
async listScoresByRunId({
|
|
2767
|
-
runId: _runId,
|
|
2768
|
-
pagination: _pagination
|
|
2769
|
-
}) {
|
|
2770
|
-
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2771
|
-
}
|
|
2772
|
-
async listScoresByEntityId({
|
|
2773
|
-
entityId: _entityId,
|
|
2774
|
-
entityType: _entityType,
|
|
2775
|
-
pagination: _pagination
|
|
2776
|
-
}) {
|
|
2777
|
-
return this.stores.scores.listScoresByEntityId({
|
|
2778
|
-
entityId: _entityId,
|
|
2779
|
-
entityType: _entityType,
|
|
2780
|
-
pagination: _pagination
|
|
2781
|
-
});
|
|
2782
|
-
}
|
|
2783
|
-
async listScoresByScorerId({
|
|
2784
|
-
scorerId,
|
|
2785
|
-
source,
|
|
2786
|
-
entityId,
|
|
2787
|
-
entityType,
|
|
2788
|
-
pagination
|
|
2789
|
-
}) {
|
|
2790
|
-
return this.stores.scores.listScoresByScorerId({ scorerId, source, entityId, entityType, pagination });
|
|
2791
|
-
}
|
|
2792
|
-
async listScoresBySpan({
|
|
2793
|
-
traceId,
|
|
2794
|
-
spanId,
|
|
2795
|
-
pagination
|
|
2796
|
-
}) {
|
|
2797
|
-
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
2798
|
-
}
|
|
2799
2505
|
};
|
|
2800
2506
|
|
|
2801
2507
|
export { DynamoDBStore };
|