@mastra/dynamodb 1.0.3 → 1.0.4-alpha.1

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,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 { MemoryStorage, createStorageErrorId, normalizePerPage, calculatePagination, filterByDateRange, ScoresStorage, SCORERS_SCHEMA, WorkflowsStorage, MastraCompositeStore, TABLE_SCORERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_RESOURCES, TABLE_MESSAGES, TABLE_THREADS } from '@mastra/core/storage';
4
+ import { BackgroundTasksStorage, createStorageErrorId, MemoryStorage, normalizePerPage, calculatePagination, filterByDateRange, ScoresStorage, SCORERS_SCHEMA, WorkflowsStorage, MastraCompositeStore, TABLE_BACKGROUND_TASKS, TABLE_SCORERS, TABLE_WORKFLOW_SNAPSHOT, TABLE_RESOURCES, TABLE_MESSAGES, TABLE_THREADS } 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';
@@ -80,7 +80,128 @@ var baseAttributes = {
80
80
  }
81
81
  };
82
82
 
83
- // src/entities/eval.ts
83
+ // src/entities/background-task.ts
84
+ var jsonSetGet = {
85
+ set: (value) => {
86
+ if (value == null) return value;
87
+ if (typeof value === "string") return value;
88
+ return JSON.stringify(value);
89
+ },
90
+ get: (value) => {
91
+ if (!value) return value;
92
+ if (typeof value !== "string") return value;
93
+ try {
94
+ if (value.startsWith("{") || value.startsWith("[")) {
95
+ return JSON.parse(value);
96
+ }
97
+ } catch {
98
+ }
99
+ return value;
100
+ }
101
+ };
102
+ var backgroundTaskEntity = new Entity({
103
+ model: {
104
+ entity: "background_task",
105
+ version: "1",
106
+ service: "mastra"
107
+ },
108
+ attributes: {
109
+ entity: {
110
+ type: "string",
111
+ required: true
112
+ },
113
+ ...baseAttributes,
114
+ id: {
115
+ type: "string",
116
+ required: true
117
+ },
118
+ status: {
119
+ type: "string",
120
+ required: true
121
+ },
122
+ toolName: {
123
+ type: "string",
124
+ required: true
125
+ },
126
+ toolCallId: {
127
+ type: "string",
128
+ required: true
129
+ },
130
+ agentId: {
131
+ type: "string",
132
+ required: true
133
+ },
134
+ runId: {
135
+ type: "string",
136
+ required: true
137
+ },
138
+ threadId: {
139
+ type: "string",
140
+ required: false
141
+ },
142
+ resourceId: {
143
+ type: "string",
144
+ required: false
145
+ },
146
+ args: {
147
+ type: "string",
148
+ required: true,
149
+ ...jsonSetGet
150
+ },
151
+ result: {
152
+ type: "string",
153
+ required: false,
154
+ ...jsonSetGet
155
+ },
156
+ error: {
157
+ type: "string",
158
+ required: false,
159
+ ...jsonSetGet
160
+ },
161
+ retryCount: {
162
+ type: "number",
163
+ required: true
164
+ },
165
+ maxRetries: {
166
+ type: "number",
167
+ required: true
168
+ },
169
+ timeoutMs: {
170
+ type: "number",
171
+ required: true
172
+ },
173
+ // Separate ISO strings for date columns — use these for GSI sort keys
174
+ startedAtIso: {
175
+ type: "string",
176
+ required: false
177
+ },
178
+ completedAtIso: {
179
+ type: "string",
180
+ required: false
181
+ }
182
+ },
183
+ indexes: {
184
+ primary: {
185
+ pk: { field: "pk", composite: ["entity", "id"] },
186
+ sk: { field: "sk", composite: ["entity"] }
187
+ },
188
+ byAgent: {
189
+ index: "gsi1",
190
+ pk: { field: "gsi1pk", composite: ["entity", "agentId"] },
191
+ sk: { field: "gsi1sk", composite: ["createdAt"] }
192
+ },
193
+ byRun: {
194
+ index: "gsi2",
195
+ pk: { field: "gsi2pk", composite: ["entity", "runId"] },
196
+ sk: { field: "gsi2sk", composite: ["createdAt"] }
197
+ },
198
+ byStatus: {
199
+ index: "gsi3",
200
+ pk: { field: "gsi3pk", composite: ["entity", "status"] },
201
+ sk: { field: "gsi3sk", composite: ["createdAt"] }
202
+ }
203
+ }
204
+ });
84
205
  var evalEntity = new Entity({
85
206
  model: {
86
207
  entity: "eval",
@@ -970,7 +1091,8 @@ function getElectroDbService(client, tableName) {
970
1091
  trace: traceEntity,
971
1092
  workflow_snapshot: workflowSnapshotEntity,
972
1093
  resource: resourceEntity,
973
- score: scoreEntity
1094
+ score: scoreEntity,
1095
+ background_task: backgroundTaskEntity
974
1096
  },
975
1097
  {
976
1098
  client,
@@ -993,38 +1115,13 @@ function resolveDynamoDBConfig(config) {
993
1115
  ttl: config.ttl
994
1116
  };
995
1117
  }
996
-
997
- // src/storage/ttl.ts
998
- function calculateTtl(entityName, ttlConfig, customTtlSeconds) {
999
- const entityConfig = ttlConfig?.[entityName];
1000
- if (!entityConfig?.enabled) {
1001
- return void 0;
1002
- }
1003
- const ttlSeconds = customTtlSeconds ?? entityConfig.defaultTtlSeconds;
1004
- if (ttlSeconds === void 0 || ttlSeconds <= 0) {
1005
- return void 0;
1006
- }
1007
- return Math.floor(Date.now() / 1e3) + ttlSeconds;
1008
- }
1009
- function getTtlAttributeName(entityName, ttlConfig) {
1010
- const entityConfig = ttlConfig?.[entityName];
1011
- return entityConfig?.attributeName ?? "ttl";
1012
- }
1013
- function isTtlEnabled(entityName, ttlConfig) {
1014
- return ttlConfig?.[entityName]?.enabled === true;
1015
- }
1016
- function getTtlProps(entityName, ttlConfig, customTtlSeconds) {
1017
- const ttlValue = calculateTtl(entityName, ttlConfig, customTtlSeconds);
1018
- if (ttlValue === void 0) return {};
1019
- const attributeName = getTtlAttributeName(entityName, ttlConfig);
1020
- return { [attributeName]: ttlValue };
1021
- }
1022
1118
  var ENTITY_MAP = {
1023
1119
  [TABLE_THREADS]: "thread",
1024
1120
  [TABLE_MESSAGES]: "message",
1025
1121
  [TABLE_RESOURCES]: "resource",
1026
1122
  [TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
1027
- [TABLE_SCORERS]: "score"
1123
+ [TABLE_SCORERS]: "score",
1124
+ [TABLE_BACKGROUND_TASKS]: "background_task"
1028
1125
  };
1029
1126
  function getDeleteKey(entityName, item) {
1030
1127
  const key = { entity: entityName };
@@ -1033,6 +1130,7 @@ function getDeleteKey(entityName, item) {
1033
1130
  case "message":
1034
1131
  case "resource":
1035
1132
  case "score":
1133
+ case "background_task":
1036
1134
  key.id = item.id;
1037
1135
  break;
1038
1136
  case "workflow_snapshot":
@@ -1062,6 +1160,296 @@ async function deleteTableData(service, tableName) {
1062
1160
  }
1063
1161
  }
1064
1162
 
1163
+ // src/storage/domains/background-tasks/index.ts
1164
+ var ENTITY = "background_task";
1165
+ function serializeJson(v) {
1166
+ if (typeof v === "object" && v != null) return JSON.stringify(v);
1167
+ return v ?? void 0;
1168
+ }
1169
+ function toElectroRecord(task) {
1170
+ return {
1171
+ entity: ENTITY,
1172
+ id: task.id,
1173
+ status: task.status,
1174
+ toolName: task.toolName,
1175
+ toolCallId: task.toolCallId,
1176
+ agentId: task.agentId,
1177
+ runId: task.runId,
1178
+ threadId: task.threadId ?? void 0,
1179
+ resourceId: task.resourceId ?? void 0,
1180
+ args: serializeJson(task.args),
1181
+ result: serializeJson(task.result),
1182
+ error: serializeJson(task.error),
1183
+ retryCount: task.retryCount,
1184
+ maxRetries: task.maxRetries,
1185
+ timeoutMs: task.timeoutMs,
1186
+ createdAt: task.createdAt.toISOString(),
1187
+ startedAtIso: task.startedAt?.toISOString(),
1188
+ completedAtIso: task.completedAt?.toISOString()
1189
+ };
1190
+ }
1191
+ function fromElectroRecord(data) {
1192
+ const parseJson = (v) => {
1193
+ if (v == null || v === "") return void 0;
1194
+ if (typeof v === "string") {
1195
+ try {
1196
+ if (v.startsWith("{") || v.startsWith("[")) return JSON.parse(v);
1197
+ } catch {
1198
+ return v;
1199
+ }
1200
+ }
1201
+ return v;
1202
+ };
1203
+ const asDate = (v) => v ? new Date(String(v)) : void 0;
1204
+ return {
1205
+ id: String(data.id),
1206
+ status: String(data.status),
1207
+ toolName: String(data.toolName),
1208
+ toolCallId: String(data.toolCallId),
1209
+ args: parseJson(data.args) ?? {},
1210
+ agentId: String(data.agentId),
1211
+ threadId: data.threadId != null && data.threadId !== "" ? String(data.threadId) : void 0,
1212
+ resourceId: data.resourceId != null && data.resourceId !== "" ? String(data.resourceId) : void 0,
1213
+ runId: String(data.runId),
1214
+ result: parseJson(data.result),
1215
+ error: parseJson(data.error),
1216
+ retryCount: Number(data.retryCount ?? 0),
1217
+ maxRetries: Number(data.maxRetries ?? 0),
1218
+ timeoutMs: Number(data.timeoutMs ?? 3e5),
1219
+ createdAt: asDate(data.createdAt) ?? /* @__PURE__ */ new Date(),
1220
+ startedAt: asDate(data.startedAtIso),
1221
+ completedAt: asDate(data.completedAtIso)
1222
+ };
1223
+ }
1224
+ var BackgroundTasksStorageDynamoDB = class extends BackgroundTasksStorage {
1225
+ service;
1226
+ constructor(config) {
1227
+ super();
1228
+ const resolved = resolveDynamoDBConfig(config);
1229
+ this.service = resolved.service;
1230
+ }
1231
+ async dangerouslyClearAll() {
1232
+ await deleteTableData(this.service, TABLE_BACKGROUND_TASKS);
1233
+ }
1234
+ async createTask(task) {
1235
+ try {
1236
+ await this.service.entities.background_task.create(toElectroRecord(task)).go();
1237
+ } catch (error) {
1238
+ throw new MastraError(
1239
+ {
1240
+ id: createStorageErrorId("DYNAMODB", "BACKGROUND_TASKS_CREATE", "FAILED"),
1241
+ domain: ErrorDomain.STORAGE,
1242
+ category: ErrorCategory.THIRD_PARTY,
1243
+ details: { taskId: task.id }
1244
+ },
1245
+ error
1246
+ );
1247
+ }
1248
+ }
1249
+ async updateTask(taskId, update) {
1250
+ try {
1251
+ const setFields = {};
1252
+ const removeFields = [];
1253
+ if ("status" in update && update.status !== void 0) {
1254
+ setFields.status = update.status;
1255
+ }
1256
+ if ("retryCount" in update && update.retryCount !== void 0) {
1257
+ setFields.retryCount = update.retryCount;
1258
+ }
1259
+ if ("result" in update) {
1260
+ if (update.result === void 0 || update.result === null) {
1261
+ removeFields.push("result");
1262
+ } else {
1263
+ setFields.result = serializeJson(update.result);
1264
+ }
1265
+ }
1266
+ if ("error" in update) {
1267
+ if (update.error === void 0 || update.error === null) {
1268
+ removeFields.push("error");
1269
+ } else {
1270
+ setFields.error = serializeJson(update.error);
1271
+ }
1272
+ }
1273
+ if ("startedAt" in update) {
1274
+ if (update.startedAt === void 0 || update.startedAt === null) {
1275
+ removeFields.push("startedAtIso");
1276
+ } else {
1277
+ setFields.startedAtIso = update.startedAt.toISOString();
1278
+ }
1279
+ }
1280
+ if ("completedAt" in update) {
1281
+ if (update.completedAt === void 0 || update.completedAt === null) {
1282
+ removeFields.push("completedAtIso");
1283
+ } else {
1284
+ setFields.completedAtIso = update.completedAt.toISOString();
1285
+ }
1286
+ }
1287
+ if (Object.keys(setFields).length === 0 && removeFields.length === 0) return;
1288
+ let op = this.service.entities.background_task.patch({ entity: ENTITY, id: taskId });
1289
+ if (Object.keys(setFields).length > 0) op = op.set(setFields);
1290
+ if (removeFields.length > 0) op = op.remove(removeFields);
1291
+ await op.go();
1292
+ } catch (error) {
1293
+ throw new MastraError(
1294
+ {
1295
+ id: createStorageErrorId("DYNAMODB", "BACKGROUND_TASKS_UPDATE", "FAILED"),
1296
+ domain: ErrorDomain.STORAGE,
1297
+ category: ErrorCategory.THIRD_PARTY,
1298
+ details: { taskId }
1299
+ },
1300
+ error
1301
+ );
1302
+ }
1303
+ }
1304
+ async getTask(taskId) {
1305
+ try {
1306
+ const result = await this.service.entities.background_task.get({ entity: ENTITY, id: taskId }).go();
1307
+ if (!result.data) return null;
1308
+ return fromElectroRecord(result.data);
1309
+ } catch (error) {
1310
+ throw new MastraError(
1311
+ {
1312
+ id: createStorageErrorId("DYNAMODB", "BACKGROUND_TASKS_GET", "FAILED"),
1313
+ domain: ErrorDomain.STORAGE,
1314
+ category: ErrorCategory.THIRD_PARTY,
1315
+ details: { taskId }
1316
+ },
1317
+ error
1318
+ );
1319
+ }
1320
+ }
1321
+ async listTasks(filter) {
1322
+ try {
1323
+ let rawResults = [];
1324
+ if (filter.runId) {
1325
+ const res = await this.service.entities.background_task.query.byRun({ entity: ENTITY, runId: filter.runId }).go({ pages: "all" });
1326
+ rawResults = res.data;
1327
+ } else if (filter.agentId) {
1328
+ const res = await this.service.entities.background_task.query.byAgent({ entity: ENTITY, agentId: filter.agentId }).go({ pages: "all" });
1329
+ rawResults = res.data;
1330
+ } else if (filter.status && !Array.isArray(filter.status)) {
1331
+ const res = await this.service.entities.background_task.query.byStatus({ entity: ENTITY, status: filter.status }).go({ pages: "all" });
1332
+ rawResults = res.data;
1333
+ } else {
1334
+ const res = await this.service.entities.background_task.scan.go({ pages: "all" });
1335
+ rawResults = res.data;
1336
+ }
1337
+ let tasks = rawResults.map(fromElectroRecord);
1338
+ if (filter.status) {
1339
+ const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];
1340
+ tasks = tasks.filter((t) => statuses.includes(t.status));
1341
+ }
1342
+ if (filter.agentId) tasks = tasks.filter((t) => t.agentId === filter.agentId);
1343
+ if (filter.threadId) tasks = tasks.filter((t) => t.threadId === filter.threadId);
1344
+ if (filter.resourceId) tasks = tasks.filter((t) => t.resourceId === filter.resourceId);
1345
+ if (filter.toolName) tasks = tasks.filter((t) => t.toolName === filter.toolName);
1346
+ if (filter.runId) tasks = tasks.filter((t) => t.runId === filter.runId);
1347
+ const dateCol = filter.dateFilterBy ?? "createdAt";
1348
+ if (filter.fromDate) {
1349
+ tasks = tasks.filter((t) => {
1350
+ const val = t[dateCol];
1351
+ return val != null && val >= filter.fromDate;
1352
+ });
1353
+ }
1354
+ if (filter.toDate) {
1355
+ tasks = tasks.filter((t) => {
1356
+ const val = t[dateCol];
1357
+ return val != null && val < filter.toDate;
1358
+ });
1359
+ }
1360
+ const orderBy = filter.orderBy ?? "createdAt";
1361
+ const dir = filter.orderDirection === "desc" ? -1 : 1;
1362
+ tasks.sort((a, b) => ((a[orderBy]?.getTime() ?? 0) - (b[orderBy]?.getTime() ?? 0)) * dir);
1363
+ const total = tasks.length;
1364
+ if (filter.page != null && filter.perPage != null) {
1365
+ const start = filter.page * filter.perPage;
1366
+ tasks = tasks.slice(start, start + filter.perPage);
1367
+ } else if (filter.perPage != null) {
1368
+ tasks = tasks.slice(0, filter.perPage);
1369
+ }
1370
+ return { tasks, total };
1371
+ } catch (error) {
1372
+ throw new MastraError(
1373
+ {
1374
+ id: createStorageErrorId("DYNAMODB", "BACKGROUND_TASKS_LIST", "FAILED"),
1375
+ domain: ErrorDomain.STORAGE,
1376
+ category: ErrorCategory.THIRD_PARTY
1377
+ },
1378
+ error
1379
+ );
1380
+ }
1381
+ }
1382
+ async deleteTask(taskId) {
1383
+ try {
1384
+ await this.service.entities.background_task.delete({ entity: ENTITY, id: taskId }).go();
1385
+ } catch (error) {
1386
+ throw new MastraError(
1387
+ {
1388
+ id: createStorageErrorId("DYNAMODB", "BACKGROUND_TASKS_DELETE", "FAILED"),
1389
+ domain: ErrorDomain.STORAGE,
1390
+ category: ErrorCategory.THIRD_PARTY,
1391
+ details: { taskId }
1392
+ },
1393
+ error
1394
+ );
1395
+ }
1396
+ }
1397
+ async deleteTasks(filter) {
1398
+ const { tasks } = await this.listTasks(filter);
1399
+ if (tasks.length === 0) return;
1400
+ try {
1401
+ const batchSize = 25;
1402
+ for (let i = 0; i < tasks.length; i += batchSize) {
1403
+ const batch = tasks.slice(i, i + batchSize).map((t) => ({ entity: ENTITY, id: t.id }));
1404
+ await this.service.entities.background_task.delete(batch).go();
1405
+ }
1406
+ } catch (error) {
1407
+ throw new MastraError(
1408
+ {
1409
+ id: createStorageErrorId("DYNAMODB", "BACKGROUND_TASKS_DELETE_MANY", "FAILED"),
1410
+ domain: ErrorDomain.STORAGE,
1411
+ category: ErrorCategory.THIRD_PARTY
1412
+ },
1413
+ error
1414
+ );
1415
+ }
1416
+ }
1417
+ async getRunningCount() {
1418
+ const { total } = await this.listTasks({ status: "running" });
1419
+ return total;
1420
+ }
1421
+ async getRunningCountByAgent(agentId) {
1422
+ const { total } = await this.listTasks({ status: "running", agentId });
1423
+ return total;
1424
+ }
1425
+ };
1426
+
1427
+ // src/storage/ttl.ts
1428
+ function calculateTtl(entityName, ttlConfig, customTtlSeconds) {
1429
+ const entityConfig = ttlConfig?.[entityName];
1430
+ if (!entityConfig?.enabled) {
1431
+ return void 0;
1432
+ }
1433
+ const ttlSeconds = customTtlSeconds ?? entityConfig.defaultTtlSeconds;
1434
+ if (ttlSeconds === void 0 || ttlSeconds <= 0) {
1435
+ return void 0;
1436
+ }
1437
+ return Math.floor(Date.now() / 1e3) + ttlSeconds;
1438
+ }
1439
+ function getTtlAttributeName(entityName, ttlConfig) {
1440
+ const entityConfig = ttlConfig?.[entityName];
1441
+ return entityConfig?.attributeName ?? "ttl";
1442
+ }
1443
+ function isTtlEnabled(entityName, ttlConfig) {
1444
+ return ttlConfig?.[entityName]?.enabled === true;
1445
+ }
1446
+ function getTtlProps(entityName, ttlConfig, customTtlSeconds) {
1447
+ const ttlValue = calculateTtl(entityName, ttlConfig, customTtlSeconds);
1448
+ if (ttlValue === void 0) return {};
1449
+ const attributeName = getTtlAttributeName(entityName, ttlConfig);
1450
+ return { [attributeName]: ttlValue };
1451
+ }
1452
+
1065
1453
  // src/storage/domains/memory/index.ts
1066
1454
  var MemoryStorageDynamoDB = class extends MemoryStorage {
1067
1455
  service;
@@ -2614,10 +3002,12 @@ var DynamoDBStore = class extends MastraCompositeStore {
2614
3002
  const workflows = new WorkflowStorageDynamoDB(domainConfig);
2615
3003
  const memory = new MemoryStorageDynamoDB(domainConfig);
2616
3004
  const scores = new ScoresStorageDynamoDB(domainConfig);
3005
+ const backgroundTasks = new BackgroundTasksStorageDynamoDB(domainConfig);
2617
3006
  this.stores = {
2618
3007
  workflows,
2619
3008
  memory,
2620
- scores
3009
+ scores,
3010
+ backgroundTasks
2621
3011
  };
2622
3012
  } catch (error) {
2623
3013
  throw new MastraError(
@@ -2720,6 +3110,6 @@ var DynamoDBStore = class extends MastraCompositeStore {
2720
3110
  }
2721
3111
  };
2722
3112
 
2723
- export { DynamoDBStore, MemoryStorageDynamoDB, ScoresStorageDynamoDB, WorkflowStorageDynamoDB, calculateTtl, getTtlAttributeName, getTtlProps, isTtlEnabled };
3113
+ export { BackgroundTasksStorageDynamoDB, DynamoDBStore, MemoryStorageDynamoDB, ScoresStorageDynamoDB, WorkflowStorageDynamoDB, calculateTtl, getTtlAttributeName, getTtlProps, isTtlEnabled };
2724
3114
  //# sourceMappingURL=index.js.map
2725
3115
  //# sourceMappingURL=index.js.map