@mastra/mssql 0.4.6 → 0.5.0-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,14 +2,15 @@
2
2
 
3
3
  var error = require('@mastra/core/error');
4
4
  var storage = require('@mastra/core/storage');
5
- var sql2 = require('mssql');
5
+ var sql3 = require('mssql');
6
6
  var utils = require('@mastra/core/utils');
7
7
  var agent = require('@mastra/core/agent');
8
+ var crypto = require('crypto');
8
9
  var scores = require('@mastra/core/scores');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
12
 
12
- var sql2__default = /*#__PURE__*/_interopDefault(sql2);
13
+ var sql3__default = /*#__PURE__*/_interopDefault(sql3);
13
14
 
14
15
  // src/storage/index.ts
15
16
  function getSchemaName(schema) {
@@ -21,6 +22,69 @@ function getTableName({ indexName, schemaName }) {
21
22
  const quotedSchemaName = schemaName;
22
23
  return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
23
24
  }
25
+ function buildDateRangeFilter(dateRange, fieldName) {
26
+ const filters = {};
27
+ if (dateRange?.start) {
28
+ filters[`${fieldName}_gte`] = dateRange.start;
29
+ }
30
+ if (dateRange?.end) {
31
+ filters[`${fieldName}_lte`] = dateRange.end;
32
+ }
33
+ return filters;
34
+ }
35
+ function prepareWhereClause(filters, _schema) {
36
+ const conditions = [];
37
+ const params = {};
38
+ let paramIndex = 1;
39
+ Object.entries(filters).forEach(([key, value]) => {
40
+ if (value === void 0) return;
41
+ const paramName = `p${paramIndex++}`;
42
+ if (key.endsWith("_gte")) {
43
+ const fieldName = key.slice(0, -4);
44
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
45
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
46
+ } else if (key.endsWith("_lte")) {
47
+ const fieldName = key.slice(0, -4);
48
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
49
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
50
+ } else if (value === null) {
51
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
52
+ } else {
53
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
54
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
55
+ }
56
+ });
57
+ return {
58
+ sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
59
+ params
60
+ };
61
+ }
62
+ function transformFromSqlRow({
63
+ tableName,
64
+ sqlRow
65
+ }) {
66
+ const schema = storage.TABLE_SCHEMAS[tableName];
67
+ const result = {};
68
+ Object.entries(sqlRow).forEach(([key, value]) => {
69
+ const columnSchema = schema?.[key];
70
+ if (columnSchema?.type === "jsonb" && typeof value === "string") {
71
+ try {
72
+ result[key] = JSON.parse(value);
73
+ } catch {
74
+ result[key] = value;
75
+ }
76
+ } else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
77
+ result[key] = new Date(value);
78
+ } else if (columnSchema?.type === "timestamp" && value instanceof Date) {
79
+ result[key] = value;
80
+ } else if (columnSchema?.type === "boolean") {
81
+ result[key] = Boolean(value);
82
+ } else {
83
+ result[key] = value;
84
+ }
85
+ });
86
+ return result;
87
+ }
24
88
 
25
89
  // src/storage/domains/legacy-evals/index.ts
26
90
  function transformEvalRow(row) {
@@ -31,7 +95,7 @@ function transformEvalRow(row) {
31
95
  } catch {
32
96
  }
33
97
  }
34
- if (row.test_info) {
98
+ if (row.result) {
35
99
  try {
36
100
  resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
37
101
  } catch {
@@ -77,7 +141,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
77
141
  if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
78
142
  return [];
79
143
  }
80
- console.error("Failed to get evals for the specified agent: " + error?.message);
144
+ this.logger?.error?.("Failed to get evals for the specified agent:", error);
81
145
  throw error;
82
146
  }
83
147
  }
@@ -113,7 +177,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
113
177
  const countReq = this.pool.request();
114
178
  Object.entries(params).forEach(([key, value]) => {
115
179
  if (value instanceof Date) {
116
- countReq.input(key, sql2__default.default.DateTime, value);
180
+ countReq.input(key, sql3__default.default.DateTime, value);
117
181
  } else {
118
182
  countReq.input(key, value);
119
183
  }
@@ -132,7 +196,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
132
196
  const req = this.pool.request();
133
197
  Object.entries(params).forEach(([key, value]) => {
134
198
  if (value instanceof Date) {
135
- req.input(key, sql2__default.default.DateTime, value);
199
+ req.input(key, sql3__default.default.DateTime, value);
136
200
  } else {
137
201
  req.input(key, value);
138
202
  }
@@ -164,7 +228,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
164
228
  error$1
165
229
  );
166
230
  this.logger?.error?.(mastraError.toString());
167
- this.logger?.trackException(mastraError);
231
+ this.logger?.trackException?.(mastraError);
168
232
  throw mastraError;
169
233
  }
170
234
  }
@@ -257,7 +321,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
257
321
  };
258
322
  }
259
323
  const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
260
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
324
+ const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
325
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
261
326
  const dataRequest = this.pool.request();
262
327
  dataRequest.input("resourceId", resourceId);
263
328
  dataRequest.input("perPage", perPage);
@@ -314,9 +379,14 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
314
379
  req.input("id", thread.id);
315
380
  req.input("resourceId", thread.resourceId);
316
381
  req.input("title", thread.title);
317
- req.input("metadata", thread.metadata ? JSON.stringify(thread.metadata) : null);
318
- req.input("createdAt", sql2__default.default.DateTime2, thread.createdAt);
319
- req.input("updatedAt", sql2__default.default.DateTime2, thread.updatedAt);
382
+ const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
383
+ if (metadata === null) {
384
+ req.input("metadata", sql3__default.default.NVarChar, null);
385
+ } else {
386
+ req.input("metadata", metadata);
387
+ }
388
+ req.input("createdAt", sql3__default.default.DateTime2, thread.createdAt);
389
+ req.input("updatedAt", sql3__default.default.DateTime2, thread.updatedAt);
320
390
  await req.query(mergeSql);
321
391
  return thread;
322
392
  } catch (error$1) {
@@ -341,7 +411,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
341
411
  try {
342
412
  const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
343
413
  const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
344
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection}`;
414
+ const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
415
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
345
416
  const request = this.pool.request();
346
417
  request.input("resourceId", resourceId);
347
418
  const resultSet = await request.query(dataQuery);
@@ -590,7 +661,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
590
661
  error$1
591
662
  );
592
663
  this.logger?.error?.(mastraError.toString());
593
- this.logger?.trackException(mastraError);
664
+ this.logger?.trackException?.(mastraError);
594
665
  return [];
595
666
  }
596
667
  }
@@ -630,7 +701,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
630
701
  error$1
631
702
  );
632
703
  this.logger?.error?.(mastraError.toString());
633
- this.logger?.trackException(mastraError);
704
+ this.logger?.trackException?.(mastraError);
634
705
  return [];
635
706
  }
636
707
  }
@@ -692,7 +763,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
692
763
  const parsed = this._parseAndFormatMessages(messages, format);
693
764
  return {
694
765
  messages: parsed,
695
- total: total + excludeIds.length,
766
+ total,
696
767
  page,
697
768
  perPage,
698
769
  hasMore: currentOffset + rows.length < total
@@ -712,7 +783,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
712
783
  error$1
713
784
  );
714
785
  this.logger?.error?.(mastraError.toString());
715
- this.logger?.trackException(mastraError);
786
+ this.logger?.trackException?.(mastraError);
716
787
  return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
717
788
  }
718
789
  }
@@ -764,7 +835,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
764
835
  "content",
765
836
  typeof message.content === "string" ? message.content : JSON.stringify(message.content)
766
837
  );
767
- request.input("createdAt", sql2__default.default.DateTime2, message.createdAt);
838
+ request.input("createdAt", sql3__default.default.DateTime2, message.createdAt);
768
839
  request.input("role", message.role);
769
840
  request.input("type", message.type || "v2");
770
841
  request.input("resourceId", message.resourceId);
@@ -783,7 +854,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
783
854
  await request.query(mergeSql);
784
855
  }
785
856
  const threadReq = transaction.request();
786
- threadReq.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
857
+ threadReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
787
858
  threadReq.input("id", threadId);
788
859
  await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
789
860
  await transaction.commit();
@@ -979,8 +1050,10 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
979
1050
  return null;
980
1051
  }
981
1052
  return {
982
- ...result,
983
- workingMemory: typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
1053
+ id: result.id,
1054
+ createdAt: result.createdAt,
1055
+ updatedAt: result.updatedAt,
1056
+ workingMemory: result.workingMemory,
984
1057
  metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
985
1058
  };
986
1059
  } catch (error$1) {
@@ -994,7 +1067,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
994
1067
  error$1
995
1068
  );
996
1069
  this.logger?.error?.(mastraError.toString());
997
- this.logger?.trackException(mastraError);
1070
+ this.logger?.trackException?.(mastraError);
998
1071
  throw mastraError;
999
1072
  }
1000
1073
  }
@@ -1003,7 +1076,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1003
1076
  tableName: storage.TABLE_RESOURCES,
1004
1077
  record: {
1005
1078
  ...resource,
1006
- metadata: JSON.stringify(resource.metadata)
1079
+ metadata: resource.metadata
1007
1080
  }
1008
1081
  });
1009
1082
  return resource;
@@ -1061,20 +1134,337 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1061
1134
  error$1
1062
1135
  );
1063
1136
  this.logger?.error?.(mastraError.toString());
1064
- this.logger?.trackException(mastraError);
1137
+ this.logger?.trackException?.(mastraError);
1065
1138
  throw mastraError;
1066
1139
  }
1067
1140
  }
1068
1141
  };
1142
+ var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
1143
+ pool;
1144
+ operations;
1145
+ schema;
1146
+ constructor({
1147
+ pool,
1148
+ operations,
1149
+ schema
1150
+ }) {
1151
+ super();
1152
+ this.pool = pool;
1153
+ this.operations = operations;
1154
+ this.schema = schema;
1155
+ }
1156
+ get aiTracingStrategy() {
1157
+ return {
1158
+ preferred: "batch-with-updates",
1159
+ supported: ["batch-with-updates", "insert-only"]
1160
+ };
1161
+ }
1162
+ async createAISpan(span) {
1163
+ try {
1164
+ const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
1165
+ const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
1166
+ const record = {
1167
+ ...span,
1168
+ startedAt,
1169
+ endedAt
1170
+ // Note: createdAt/updatedAt will be set by default values
1171
+ };
1172
+ return this.operations.insert({ tableName: storage.TABLE_AI_SPANS, record });
1173
+ } catch (error$1) {
1174
+ throw new error.MastraError(
1175
+ {
1176
+ id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
1177
+ domain: error.ErrorDomain.STORAGE,
1178
+ category: error.ErrorCategory.USER,
1179
+ details: {
1180
+ spanId: span.spanId,
1181
+ traceId: span.traceId,
1182
+ spanType: span.spanType,
1183
+ spanName: span.name
1184
+ }
1185
+ },
1186
+ error$1
1187
+ );
1188
+ }
1189
+ }
1190
+ async getAITrace(traceId) {
1191
+ try {
1192
+ const tableName = getTableName({
1193
+ indexName: storage.TABLE_AI_SPANS,
1194
+ schemaName: getSchemaName(this.schema)
1195
+ });
1196
+ const request = this.pool.request();
1197
+ request.input("traceId", traceId);
1198
+ const result = await request.query(
1199
+ `SELECT
1200
+ [traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
1201
+ [attributes], [metadata], [links], [input], [output], [error], [isEvent],
1202
+ [startedAt], [endedAt], [createdAt], [updatedAt]
1203
+ FROM ${tableName}
1204
+ WHERE [traceId] = @traceId
1205
+ ORDER BY [startedAt] DESC`
1206
+ );
1207
+ if (!result.recordset || result.recordset.length === 0) {
1208
+ return null;
1209
+ }
1210
+ return {
1211
+ traceId,
1212
+ spans: result.recordset.map(
1213
+ (span) => transformFromSqlRow({
1214
+ tableName: storage.TABLE_AI_SPANS,
1215
+ sqlRow: span
1216
+ })
1217
+ )
1218
+ };
1219
+ } catch (error$1) {
1220
+ throw new error.MastraError(
1221
+ {
1222
+ id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
1223
+ domain: error.ErrorDomain.STORAGE,
1224
+ category: error.ErrorCategory.USER,
1225
+ details: {
1226
+ traceId
1227
+ }
1228
+ },
1229
+ error$1
1230
+ );
1231
+ }
1232
+ }
1233
+ async updateAISpan({
1234
+ spanId,
1235
+ traceId,
1236
+ updates
1237
+ }) {
1238
+ try {
1239
+ const data = { ...updates };
1240
+ if (data.endedAt instanceof Date) {
1241
+ data.endedAt = data.endedAt.toISOString();
1242
+ }
1243
+ if (data.startedAt instanceof Date) {
1244
+ data.startedAt = data.startedAt.toISOString();
1245
+ }
1246
+ await this.operations.update({
1247
+ tableName: storage.TABLE_AI_SPANS,
1248
+ keys: { spanId, traceId },
1249
+ data
1250
+ });
1251
+ } catch (error$1) {
1252
+ throw new error.MastraError(
1253
+ {
1254
+ id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
1255
+ domain: error.ErrorDomain.STORAGE,
1256
+ category: error.ErrorCategory.USER,
1257
+ details: {
1258
+ spanId,
1259
+ traceId
1260
+ }
1261
+ },
1262
+ error$1
1263
+ );
1264
+ }
1265
+ }
1266
+ async getAITracesPaginated({
1267
+ filters,
1268
+ pagination
1269
+ }) {
1270
+ const page = pagination?.page ?? 0;
1271
+ const perPage = pagination?.perPage ?? 10;
1272
+ const { entityId, entityType, ...actualFilters } = filters || {};
1273
+ const filtersWithDateRange = {
1274
+ ...actualFilters,
1275
+ ...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
1276
+ parentSpanId: null
1277
+ // Only get root spans for traces
1278
+ };
1279
+ const whereClause = prepareWhereClause(filtersWithDateRange);
1280
+ let actualWhereClause = whereClause.sql;
1281
+ const params = { ...whereClause.params };
1282
+ let currentParamIndex = Object.keys(params).length + 1;
1283
+ if (entityId && entityType) {
1284
+ let name = "";
1285
+ if (entityType === "workflow") {
1286
+ name = `workflow run: '${entityId}'`;
1287
+ } else if (entityType === "agent") {
1288
+ name = `agent run: '${entityId}'`;
1289
+ } else {
1290
+ const error$1 = new error.MastraError({
1291
+ id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
1292
+ domain: error.ErrorDomain.STORAGE,
1293
+ category: error.ErrorCategory.USER,
1294
+ details: {
1295
+ entityType
1296
+ },
1297
+ text: `Cannot filter by entity type: ${entityType}`
1298
+ });
1299
+ throw error$1;
1300
+ }
1301
+ const entityParam = `p${currentParamIndex++}`;
1302
+ if (actualWhereClause) {
1303
+ actualWhereClause += ` AND [name] = @${entityParam}`;
1304
+ } else {
1305
+ actualWhereClause = ` WHERE [name] = @${entityParam}`;
1306
+ }
1307
+ params[entityParam] = name;
1308
+ }
1309
+ const tableName = getTableName({
1310
+ indexName: storage.TABLE_AI_SPANS,
1311
+ schemaName: getSchemaName(this.schema)
1312
+ });
1313
+ try {
1314
+ const countRequest = this.pool.request();
1315
+ Object.entries(params).forEach(([key, value]) => {
1316
+ countRequest.input(key, value);
1317
+ });
1318
+ const countResult = await countRequest.query(
1319
+ `SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
1320
+ );
1321
+ const total = countResult.recordset[0]?.count ?? 0;
1322
+ if (total === 0) {
1323
+ return {
1324
+ pagination: {
1325
+ total: 0,
1326
+ page,
1327
+ perPage,
1328
+ hasMore: false
1329
+ },
1330
+ spans: []
1331
+ };
1332
+ }
1333
+ const dataRequest = this.pool.request();
1334
+ Object.entries(params).forEach(([key, value]) => {
1335
+ dataRequest.input(key, value);
1336
+ });
1337
+ dataRequest.input("offset", page * perPage);
1338
+ dataRequest.input("limit", perPage);
1339
+ const dataResult = await dataRequest.query(
1340
+ `SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
1341
+ );
1342
+ const spans = dataResult.recordset.map(
1343
+ (row) => transformFromSqlRow({
1344
+ tableName: storage.TABLE_AI_SPANS,
1345
+ sqlRow: row
1346
+ })
1347
+ );
1348
+ return {
1349
+ pagination: {
1350
+ total,
1351
+ page,
1352
+ perPage,
1353
+ hasMore: (page + 1) * perPage < total
1354
+ },
1355
+ spans
1356
+ };
1357
+ } catch (error$1) {
1358
+ throw new error.MastraError(
1359
+ {
1360
+ id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
1361
+ domain: error.ErrorDomain.STORAGE,
1362
+ category: error.ErrorCategory.USER
1363
+ },
1364
+ error$1
1365
+ );
1366
+ }
1367
+ }
1368
+ async batchCreateAISpans(args) {
1369
+ if (!args.records || args.records.length === 0) {
1370
+ return;
1371
+ }
1372
+ try {
1373
+ await this.operations.batchInsert({
1374
+ tableName: storage.TABLE_AI_SPANS,
1375
+ records: args.records.map((span) => ({
1376
+ ...span,
1377
+ startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
1378
+ endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
1379
+ }))
1380
+ });
1381
+ } catch (error$1) {
1382
+ throw new error.MastraError(
1383
+ {
1384
+ id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
1385
+ domain: error.ErrorDomain.STORAGE,
1386
+ category: error.ErrorCategory.USER,
1387
+ details: {
1388
+ count: args.records.length
1389
+ }
1390
+ },
1391
+ error$1
1392
+ );
1393
+ }
1394
+ }
1395
+ async batchUpdateAISpans(args) {
1396
+ if (!args.records || args.records.length === 0) {
1397
+ return;
1398
+ }
1399
+ try {
1400
+ const updates = args.records.map(({ traceId, spanId, updates: data }) => {
1401
+ const processedData = { ...data };
1402
+ if (processedData.endedAt instanceof Date) {
1403
+ processedData.endedAt = processedData.endedAt.toISOString();
1404
+ }
1405
+ if (processedData.startedAt instanceof Date) {
1406
+ processedData.startedAt = processedData.startedAt.toISOString();
1407
+ }
1408
+ return {
1409
+ keys: { spanId, traceId },
1410
+ data: processedData
1411
+ };
1412
+ });
1413
+ await this.operations.batchUpdate({
1414
+ tableName: storage.TABLE_AI_SPANS,
1415
+ updates
1416
+ });
1417
+ } catch (error$1) {
1418
+ throw new error.MastraError(
1419
+ {
1420
+ id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
1421
+ domain: error.ErrorDomain.STORAGE,
1422
+ category: error.ErrorCategory.USER,
1423
+ details: {
1424
+ count: args.records.length
1425
+ }
1426
+ },
1427
+ error$1
1428
+ );
1429
+ }
1430
+ }
1431
+ async batchDeleteAITraces(args) {
1432
+ if (!args.traceIds || args.traceIds.length === 0) {
1433
+ return;
1434
+ }
1435
+ try {
1436
+ const keys = args.traceIds.map((traceId) => ({ traceId }));
1437
+ await this.operations.batchDelete({
1438
+ tableName: storage.TABLE_AI_SPANS,
1439
+ keys
1440
+ });
1441
+ } catch (error$1) {
1442
+ throw new error.MastraError(
1443
+ {
1444
+ id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
1445
+ domain: error.ErrorDomain.STORAGE,
1446
+ category: error.ErrorCategory.USER,
1447
+ details: {
1448
+ count: args.traceIds.length
1449
+ }
1450
+ },
1451
+ error$1
1452
+ );
1453
+ }
1454
+ }
1455
+ };
1069
1456
  var StoreOperationsMSSQL = class extends storage.StoreOperations {
1070
1457
  pool;
1071
1458
  schemaName;
1072
1459
  setupSchemaPromise = null;
1073
1460
  schemaSetupComplete = void 0;
1074
- getSqlType(type, isPrimaryKey = false) {
1461
+ getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
1075
1462
  switch (type) {
1076
1463
  case "text":
1077
- return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(MAX)";
1464
+ if (useLargeStorage) {
1465
+ return "NVARCHAR(MAX)";
1466
+ }
1467
+ return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
1078
1468
  case "timestamp":
1079
1469
  return "DATETIME2(7)";
1080
1470
  case "uuid":
@@ -1087,6 +1477,8 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1087
1477
  return "BIGINT";
1088
1478
  case "float":
1089
1479
  return "FLOAT";
1480
+ case "boolean":
1481
+ return "BIT";
1090
1482
  default:
1091
1483
  throw new error.MastraError({
1092
1484
  id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
@@ -1149,20 +1541,26 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1149
1541
  }
1150
1542
  await this.setupSchemaPromise;
1151
1543
  }
1152
- async insert({ tableName, record }) {
1544
+ async insert({
1545
+ tableName,
1546
+ record,
1547
+ transaction
1548
+ }) {
1153
1549
  try {
1154
- const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
1155
- const values = Object.values(record);
1156
- const paramNames = values.map((_, i) => `@param${i}`);
1157
- const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${columns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
1158
- const request = this.pool.request();
1159
- values.forEach((value, i) => {
1160
- if (value instanceof Date) {
1161
- request.input(`param${i}`, sql2__default.default.DateTime2, value);
1162
- } else if (typeof value === "object" && value !== null) {
1163
- request.input(`param${i}`, JSON.stringify(value));
1550
+ const columns = Object.keys(record);
1551
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
1552
+ const paramNames = columns.map((_, i) => `@param${i}`);
1553
+ const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
1554
+ const request = transaction ? transaction.request() : this.pool.request();
1555
+ columns.forEach((col, i) => {
1556
+ const value = record[col];
1557
+ const preparedValue = this.prepareValue(value, col, tableName);
1558
+ if (preparedValue instanceof Date) {
1559
+ request.input(`param${i}`, sql3__default.default.DateTime2, preparedValue);
1560
+ } else if (preparedValue === null || preparedValue === void 0) {
1561
+ request.input(`param${i}`, this.getMssqlType(tableName, col), null);
1164
1562
  } else {
1165
- request.input(`param${i}`, value);
1563
+ request.input(`param${i}`, preparedValue);
1166
1564
  }
1167
1565
  });
1168
1566
  await request.query(insertSql);
@@ -1186,7 +1584,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1186
1584
  try {
1187
1585
  await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
1188
1586
  } catch (truncateError) {
1189
- if (truncateError.message && truncateError.message.includes("foreign key")) {
1587
+ if (truncateError?.number === 4712) {
1190
1588
  await this.pool.request().query(`DELETE FROM ${fullTableName}`);
1191
1589
  } else {
1192
1590
  throw truncateError;
@@ -1209,9 +1607,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1209
1607
  getDefaultValue(type) {
1210
1608
  switch (type) {
1211
1609
  case "timestamp":
1212
- return "DEFAULT SYSDATETIMEOFFSET()";
1610
+ return "DEFAULT SYSUTCDATETIME()";
1213
1611
  case "jsonb":
1214
1612
  return "DEFAULT N'{}'";
1613
+ case "boolean":
1614
+ return "DEFAULT 0";
1215
1615
  default:
1216
1616
  return super.getDefaultValue(type);
1217
1617
  }
@@ -1222,13 +1622,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1222
1622
  }) {
1223
1623
  try {
1224
1624
  const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
1625
+ const largeDataColumns = [
1626
+ "workingMemory",
1627
+ "snapshot",
1628
+ "metadata",
1629
+ "content",
1630
+ // messages.content - can be very long conversation content
1631
+ "input",
1632
+ // evals.input - test input data
1633
+ "output",
1634
+ // evals.output - test output data
1635
+ "instructions",
1636
+ // evals.instructions - evaluation instructions
1637
+ "other"
1638
+ // traces.other - additional trace data
1639
+ ];
1225
1640
  const columns = Object.entries(schema).map(([name, def]) => {
1226
1641
  const parsedName = utils.parseSqlIdentifier(name, "column name");
1227
1642
  const constraints = [];
1228
1643
  if (def.primaryKey) constraints.push("PRIMARY KEY");
1229
1644
  if (!def.nullable) constraints.push("NOT NULL");
1230
1645
  const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
1231
- return `[${parsedName}] ${this.getSqlType(def.type, isIndexed)} ${constraints.join(" ")}`.trim();
1646
+ const useLargeStorage = largeDataColumns.includes(name);
1647
+ return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
1232
1648
  }).join(",\n");
1233
1649
  if (this.schemaName) {
1234
1650
  await this.setupSchema();
@@ -1315,7 +1731,19 @@ ${columns}
1315
1731
  const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1316
1732
  if (!columnExists) {
1317
1733
  const columnDef = schema[columnName];
1318
- const sqlType = this.getSqlType(columnDef.type);
1734
+ const largeDataColumns = [
1735
+ "workingMemory",
1736
+ "snapshot",
1737
+ "metadata",
1738
+ "content",
1739
+ "input",
1740
+ "output",
1741
+ "instructions",
1742
+ "other"
1743
+ ];
1744
+ const useLargeStorage = largeDataColumns.includes(columnName);
1745
+ const isIndexed = !!columnDef.primaryKey;
1746
+ const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
1319
1747
  const nullable = columnDef.nullable === false ? "NOT NULL" : "";
1320
1748
  const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
1321
1749
  const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
@@ -1343,11 +1771,15 @@ ${columns}
1343
1771
  try {
1344
1772
  const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
1345
1773
  const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
1346
- const values = keyEntries.map(([_, value]) => value);
1347
1774
  const sql7 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
1348
1775
  const request = this.pool.request();
1349
- values.forEach((value, i) => {
1350
- request.input(`param${i}`, value);
1776
+ keyEntries.forEach(([key, value], i) => {
1777
+ const preparedValue = this.prepareValue(value, key, tableName);
1778
+ if (preparedValue === null || preparedValue === void 0) {
1779
+ request.input(`param${i}`, this.getMssqlType(tableName, key), null);
1780
+ } else {
1781
+ request.input(`param${i}`, preparedValue);
1782
+ }
1351
1783
  });
1352
1784
  const resultSet = await request.query(sql7);
1353
1785
  const result = resultSet.recordset[0] || null;
@@ -1381,7 +1813,7 @@ ${columns}
1381
1813
  try {
1382
1814
  await transaction.begin();
1383
1815
  for (const record of records) {
1384
- await this.insert({ tableName, record });
1816
+ await this.insert({ tableName, record, transaction });
1385
1817
  }
1386
1818
  await transaction.commit();
1387
1819
  } catch (error$1) {
@@ -1418,51 +1850,592 @@ ${columns}
1418
1850
  );
1419
1851
  }
1420
1852
  }
1421
- };
1422
- function parseJSON(jsonString) {
1423
- try {
1424
- return JSON.parse(jsonString);
1425
- } catch {
1426
- return jsonString;
1853
+ /**
1854
+ * Prepares a value for database operations, handling Date objects and JSON serialization
1855
+ */
1856
+ prepareValue(value, columnName, tableName) {
1857
+ if (value === null || value === void 0) {
1858
+ return value;
1859
+ }
1860
+ if (value instanceof Date) {
1861
+ return value;
1862
+ }
1863
+ const schema = storage.TABLE_SCHEMAS[tableName];
1864
+ const columnSchema = schema?.[columnName];
1865
+ if (columnSchema?.type === "boolean") {
1866
+ return value ? 1 : 0;
1867
+ }
1868
+ if (columnSchema?.type === "jsonb") {
1869
+ return JSON.stringify(value);
1870
+ }
1871
+ if (typeof value === "object") {
1872
+ return JSON.stringify(value);
1873
+ }
1874
+ return value;
1427
1875
  }
1428
- }
1429
- function transformScoreRow(row) {
1430
- return {
1431
- ...row,
1432
- input: parseJSON(row.input),
1433
- scorer: parseJSON(row.scorer),
1434
- preprocessStepResult: parseJSON(row.preprocessStepResult),
1435
- analyzeStepResult: parseJSON(row.analyzeStepResult),
1436
- metadata: parseJSON(row.metadata),
1437
- output: parseJSON(row.output),
1438
- additionalContext: parseJSON(row.additionalContext),
1439
- runtimeContext: parseJSON(row.runtimeContext),
1440
- entity: parseJSON(row.entity),
1441
- createdAt: row.createdAt,
1442
- updatedAt: row.updatedAt
1443
- };
1444
- }
1445
- var ScoresMSSQL = class extends storage.ScoresStorage {
1446
- pool;
1447
- operations;
1448
- schema;
1449
- constructor({
1450
- pool,
1451
- operations,
1452
- schema
1453
- }) {
1454
- super();
1455
- this.pool = pool;
1456
- this.operations = operations;
1457
- this.schema = schema;
1876
+ /**
1877
+ * Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
1878
+ */
1879
+ getMssqlType(tableName, columnName) {
1880
+ const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
1881
+ switch (col?.type) {
1882
+ case "text":
1883
+ return sql3__default.default.NVarChar;
1884
+ case "timestamp":
1885
+ return sql3__default.default.DateTime2;
1886
+ case "uuid":
1887
+ return sql3__default.default.UniqueIdentifier;
1888
+ case "jsonb":
1889
+ return sql3__default.default.NVarChar;
1890
+ case "integer":
1891
+ return sql3__default.default.Int;
1892
+ case "bigint":
1893
+ return sql3__default.default.BigInt;
1894
+ case "float":
1895
+ return sql3__default.default.Float;
1896
+ case "boolean":
1897
+ return sql3__default.default.Bit;
1898
+ default:
1899
+ return sql3__default.default.NVarChar;
1900
+ }
1458
1901
  }
1459
- async getScoreById({ id }) {
1902
+ /**
1903
+ * Update a single record in the database
1904
+ */
1905
+ async update({
1906
+ tableName,
1907
+ keys,
1908
+ data,
1909
+ transaction
1910
+ }) {
1460
1911
  try {
1461
- const request = this.pool.request();
1462
- request.input("p1", id);
1463
- const result = await request.query(
1464
- `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE id = @p1`
1465
- );
1912
+ if (!data || Object.keys(data).length === 0) {
1913
+ throw new error.MastraError({
1914
+ id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
1915
+ domain: error.ErrorDomain.STORAGE,
1916
+ category: error.ErrorCategory.USER,
1917
+ text: "Cannot update with empty data payload"
1918
+ });
1919
+ }
1920
+ if (!keys || Object.keys(keys).length === 0) {
1921
+ throw new error.MastraError({
1922
+ id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
1923
+ domain: error.ErrorDomain.STORAGE,
1924
+ category: error.ErrorCategory.USER,
1925
+ text: "Cannot update without keys to identify records"
1926
+ });
1927
+ }
1928
+ const setClauses = [];
1929
+ const request = transaction ? transaction.request() : this.pool.request();
1930
+ let paramIndex = 0;
1931
+ Object.entries(data).forEach(([key, value]) => {
1932
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1933
+ const paramName = `set${paramIndex++}`;
1934
+ setClauses.push(`[${parsedKey}] = @${paramName}`);
1935
+ const preparedValue = this.prepareValue(value, key, tableName);
1936
+ if (preparedValue === null || preparedValue === void 0) {
1937
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1938
+ } else {
1939
+ request.input(paramName, preparedValue);
1940
+ }
1941
+ });
1942
+ const whereConditions = [];
1943
+ Object.entries(keys).forEach(([key, value]) => {
1944
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1945
+ const paramName = `where${paramIndex++}`;
1946
+ whereConditions.push(`[${parsedKey}] = @${paramName}`);
1947
+ const preparedValue = this.prepareValue(value, key, tableName);
1948
+ if (preparedValue === null || preparedValue === void 0) {
1949
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1950
+ } else {
1951
+ request.input(paramName, preparedValue);
1952
+ }
1953
+ });
1954
+ const tableName_ = getTableName({
1955
+ indexName: tableName,
1956
+ schemaName: getSchemaName(this.schemaName)
1957
+ });
1958
+ const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
1959
+ await request.query(updateSql);
1960
+ } catch (error$1) {
1961
+ throw new error.MastraError(
1962
+ {
1963
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
1964
+ domain: error.ErrorDomain.STORAGE,
1965
+ category: error.ErrorCategory.THIRD_PARTY,
1966
+ details: {
1967
+ tableName
1968
+ }
1969
+ },
1970
+ error$1
1971
+ );
1972
+ }
1973
+ }
1974
+ /**
1975
+ * Update multiple records in a single batch transaction
1976
+ */
1977
+ async batchUpdate({
1978
+ tableName,
1979
+ updates
1980
+ }) {
1981
+ const transaction = this.pool.transaction();
1982
+ try {
1983
+ await transaction.begin();
1984
+ for (const { keys, data } of updates) {
1985
+ await this.update({ tableName, keys, data, transaction });
1986
+ }
1987
+ await transaction.commit();
1988
+ } catch (error$1) {
1989
+ await transaction.rollback();
1990
+ throw new error.MastraError(
1991
+ {
1992
+ id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
1993
+ domain: error.ErrorDomain.STORAGE,
1994
+ category: error.ErrorCategory.THIRD_PARTY,
1995
+ details: {
1996
+ tableName,
1997
+ numberOfRecords: updates.length
1998
+ }
1999
+ },
2000
+ error$1
2001
+ );
2002
+ }
2003
+ }
2004
+ /**
2005
+ * Delete multiple records by keys
2006
+ */
2007
+ async batchDelete({ tableName, keys }) {
2008
+ if (keys.length === 0) {
2009
+ return;
2010
+ }
2011
+ const tableName_ = getTableName({
2012
+ indexName: tableName,
2013
+ schemaName: getSchemaName(this.schemaName)
2014
+ });
2015
+ const transaction = this.pool.transaction();
2016
+ try {
2017
+ await transaction.begin();
2018
+ for (const keySet of keys) {
2019
+ const conditions = [];
2020
+ const request = transaction.request();
2021
+ let paramIndex = 0;
2022
+ Object.entries(keySet).forEach(([key, value]) => {
2023
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
2024
+ const paramName = `p${paramIndex++}`;
2025
+ conditions.push(`[${parsedKey}] = @${paramName}`);
2026
+ const preparedValue = this.prepareValue(value, key, tableName);
2027
+ if (preparedValue === null || preparedValue === void 0) {
2028
+ request.input(paramName, this.getMssqlType(tableName, key), null);
2029
+ } else {
2030
+ request.input(paramName, preparedValue);
2031
+ }
2032
+ });
2033
+ const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
2034
+ await request.query(deleteSql);
2035
+ }
2036
+ await transaction.commit();
2037
+ } catch (error$1) {
2038
+ await transaction.rollback();
2039
+ throw new error.MastraError(
2040
+ {
2041
+ id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
2042
+ domain: error.ErrorDomain.STORAGE,
2043
+ category: error.ErrorCategory.THIRD_PARTY,
2044
+ details: {
2045
+ tableName,
2046
+ numberOfRecords: keys.length
2047
+ }
2048
+ },
2049
+ error$1
2050
+ );
2051
+ }
2052
+ }
2053
+ /**
2054
+ * Create a new index on a table
2055
+ */
2056
+ async createIndex(options) {
2057
+ try {
2058
+ const { name, table, columns, unique = false, where } = options;
2059
+ const schemaName = this.schemaName || "dbo";
2060
+ const fullTableName = getTableName({
2061
+ indexName: table,
2062
+ schemaName: getSchemaName(this.schemaName)
2063
+ });
2064
+ const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
2065
+ const checkRequest = this.pool.request();
2066
+ checkRequest.input("indexName", indexNameSafe);
2067
+ checkRequest.input("schemaName", schemaName);
2068
+ checkRequest.input("tableName", table);
2069
+ const indexExists = await checkRequest.query(`
2070
+ SELECT 1 as found
2071
+ FROM sys.indexes i
2072
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
2073
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
2074
+ WHERE i.name = @indexName
2075
+ AND s.name = @schemaName
2076
+ AND t.name = @tableName
2077
+ `);
2078
+ if (indexExists.recordset && indexExists.recordset.length > 0) {
2079
+ return;
2080
+ }
2081
+ const uniqueStr = unique ? "UNIQUE " : "";
2082
+ const columnsStr = columns.map((col) => {
2083
+ if (col.includes(" DESC") || col.includes(" ASC")) {
2084
+ const [colName, ...modifiers] = col.split(" ");
2085
+ if (!colName) {
2086
+ throw new Error(`Invalid column specification: ${col}`);
2087
+ }
2088
+ return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
2089
+ }
2090
+ return `[${utils.parseSqlIdentifier(col, "column name")}]`;
2091
+ }).join(", ");
2092
+ const whereStr = where ? ` WHERE ${where}` : "";
2093
+ const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
2094
+ await this.pool.request().query(createIndexSql);
2095
+ } catch (error$1) {
2096
+ throw new error.MastraError(
2097
+ {
2098
+ id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
2099
+ domain: error.ErrorDomain.STORAGE,
2100
+ category: error.ErrorCategory.THIRD_PARTY,
2101
+ details: {
2102
+ indexName: options.name,
2103
+ tableName: options.table
2104
+ }
2105
+ },
2106
+ error$1
2107
+ );
2108
+ }
2109
+ }
2110
+ /**
2111
+ * Drop an existing index
2112
+ */
2113
+ async dropIndex(indexName) {
2114
+ try {
2115
+ const schemaName = this.schemaName || "dbo";
2116
+ const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
2117
+ const checkRequest = this.pool.request();
2118
+ checkRequest.input("indexName", indexNameSafe);
2119
+ checkRequest.input("schemaName", schemaName);
2120
+ const result = await checkRequest.query(`
2121
+ SELECT t.name as table_name
2122
+ FROM sys.indexes i
2123
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
2124
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
2125
+ WHERE i.name = @indexName
2126
+ AND s.name = @schemaName
2127
+ `);
2128
+ if (!result.recordset || result.recordset.length === 0) {
2129
+ return;
2130
+ }
2131
+ if (result.recordset.length > 1) {
2132
+ const tables = result.recordset.map((r) => r.table_name).join(", ");
2133
+ throw new error.MastraError({
2134
+ id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
2135
+ domain: error.ErrorDomain.STORAGE,
2136
+ category: error.ErrorCategory.USER,
2137
+ text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
2138
+ });
2139
+ }
2140
+ const tableName = result.recordset[0].table_name;
2141
+ const fullTableName = getTableName({
2142
+ indexName: tableName,
2143
+ schemaName: getSchemaName(this.schemaName)
2144
+ });
2145
+ const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
2146
+ await this.pool.request().query(dropSql);
2147
+ } catch (error$1) {
2148
+ throw new error.MastraError(
2149
+ {
2150
+ id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
2151
+ domain: error.ErrorDomain.STORAGE,
2152
+ category: error.ErrorCategory.THIRD_PARTY,
2153
+ details: {
2154
+ indexName
2155
+ }
2156
+ },
2157
+ error$1
2158
+ );
2159
+ }
2160
+ }
2161
+ /**
2162
+ * List indexes for a specific table or all tables
2163
+ */
2164
+ async listIndexes(tableName) {
2165
+ try {
2166
+ const schemaName = this.schemaName || "dbo";
2167
+ let query;
2168
+ const request = this.pool.request();
2169
+ request.input("schemaName", schemaName);
2170
+ if (tableName) {
2171
+ query = `
2172
+ SELECT
2173
+ i.name as name,
2174
+ o.name as [table],
2175
+ i.is_unique as is_unique,
2176
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2177
+ FROM sys.indexes i
2178
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2179
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2180
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2181
+ WHERE sch.name = @schemaName
2182
+ AND o.name = @tableName
2183
+ AND i.name IS NOT NULL
2184
+ GROUP BY i.name, o.name, i.is_unique
2185
+ `;
2186
+ request.input("tableName", tableName);
2187
+ } else {
2188
+ query = `
2189
+ SELECT
2190
+ i.name as name,
2191
+ o.name as [table],
2192
+ i.is_unique as is_unique,
2193
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2194
+ FROM sys.indexes i
2195
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2196
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2197
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2198
+ WHERE sch.name = @schemaName
2199
+ AND i.name IS NOT NULL
2200
+ GROUP BY i.name, o.name, i.is_unique
2201
+ `;
2202
+ }
2203
+ const result = await request.query(query);
2204
+ const indexes = [];
2205
+ for (const row of result.recordset) {
2206
+ const colRequest = this.pool.request();
2207
+ colRequest.input("indexName", row.name);
2208
+ colRequest.input("schemaName", schemaName);
2209
+ const colResult = await colRequest.query(`
2210
+ SELECT c.name as column_name
2211
+ FROM sys.indexes i
2212
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2213
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2214
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2215
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2216
+ WHERE i.name = @indexName
2217
+ AND s.name = @schemaName
2218
+ ORDER BY ic.key_ordinal
2219
+ `);
2220
+ indexes.push({
2221
+ name: row.name,
2222
+ table: row.table,
2223
+ columns: colResult.recordset.map((c) => c.column_name),
2224
+ unique: row.is_unique || false,
2225
+ size: row.size || "0 MB",
2226
+ definition: ""
2227
+ // MSSQL doesn't store definition like PG
2228
+ });
2229
+ }
2230
+ return indexes;
2231
+ } catch (error$1) {
2232
+ throw new error.MastraError(
2233
+ {
2234
+ id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
2235
+ domain: error.ErrorDomain.STORAGE,
2236
+ category: error.ErrorCategory.THIRD_PARTY,
2237
+ details: tableName ? {
2238
+ tableName
2239
+ } : {}
2240
+ },
2241
+ error$1
2242
+ );
2243
+ }
2244
+ }
2245
+ /**
2246
+ * Get detailed statistics for a specific index
2247
+ */
2248
+ async describeIndex(indexName) {
2249
+ try {
2250
+ const schemaName = this.schemaName || "dbo";
2251
+ const request = this.pool.request();
2252
+ request.input("indexName", indexName);
2253
+ request.input("schemaName", schemaName);
2254
+ const query = `
2255
+ SELECT
2256
+ i.name as name,
2257
+ o.name as [table],
2258
+ i.is_unique as is_unique,
2259
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
2260
+ i.type_desc as method,
2261
+ ISNULL(us.user_scans, 0) as scans,
2262
+ ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
2263
+ ISNULL(us.user_lookups, 0) as tuples_fetched
2264
+ FROM sys.indexes i
2265
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2266
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2267
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2268
+ LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
2269
+ WHERE i.name = @indexName
2270
+ AND sch.name = @schemaName
2271
+ GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
2272
+ `;
2273
+ const result = await request.query(query);
2274
+ if (!result.recordset || result.recordset.length === 0) {
2275
+ throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
2276
+ }
2277
+ const row = result.recordset[0];
2278
+ const colRequest = this.pool.request();
2279
+ colRequest.input("indexName", indexName);
2280
+ colRequest.input("schemaName", schemaName);
2281
+ const colResult = await colRequest.query(`
2282
+ SELECT c.name as column_name
2283
+ FROM sys.indexes i
2284
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2285
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2286
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2287
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2288
+ WHERE i.name = @indexName
2289
+ AND s.name = @schemaName
2290
+ ORDER BY ic.key_ordinal
2291
+ `);
2292
+ return {
2293
+ name: row.name,
2294
+ table: row.table,
2295
+ columns: colResult.recordset.map((c) => c.column_name),
2296
+ unique: row.is_unique || false,
2297
+ size: row.size || "0 MB",
2298
+ definition: "",
2299
+ method: row.method?.toLowerCase() || "nonclustered",
2300
+ scans: Number(row.scans) || 0,
2301
+ tuples_read: Number(row.tuples_read) || 0,
2302
+ tuples_fetched: Number(row.tuples_fetched) || 0
2303
+ };
2304
+ } catch (error$1) {
2305
+ throw new error.MastraError(
2306
+ {
2307
+ id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
2308
+ domain: error.ErrorDomain.STORAGE,
2309
+ category: error.ErrorCategory.THIRD_PARTY,
2310
+ details: {
2311
+ indexName
2312
+ }
2313
+ },
2314
+ error$1
2315
+ );
2316
+ }
2317
+ }
2318
+ /**
2319
+ * Returns definitions for automatic performance indexes
2320
+ * IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
2321
+ * NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
2322
+ */
2323
+ getAutomaticIndexDefinitions() {
2324
+ const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
2325
+ return [
2326
+ // Composite indexes for optimal filtering + sorting performance
2327
+ // NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
2328
+ {
2329
+ name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
2330
+ table: storage.TABLE_THREADS,
2331
+ columns: ["resourceId", "seq_id DESC"]
2332
+ },
2333
+ {
2334
+ name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
2335
+ table: storage.TABLE_MESSAGES,
2336
+ columns: ["thread_id", "seq_id DESC"]
2337
+ },
2338
+ {
2339
+ name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
2340
+ table: storage.TABLE_TRACES,
2341
+ columns: ["name", "seq_id DESC"]
2342
+ },
2343
+ {
2344
+ name: `${schemaPrefix}mastra_evals_agent_name_seqid_idx`,
2345
+ table: storage.TABLE_EVALS,
2346
+ columns: ["agent_name", "seq_id DESC"]
2347
+ },
2348
+ {
2349
+ name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
2350
+ table: storage.TABLE_SCORERS,
2351
+ columns: ["traceId", "spanId", "seq_id DESC"]
2352
+ },
2353
+ // AI Spans indexes for optimal trace querying
2354
+ {
2355
+ name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
2356
+ table: storage.TABLE_AI_SPANS,
2357
+ columns: ["traceId", "startedAt DESC"]
2358
+ },
2359
+ {
2360
+ name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
2361
+ table: storage.TABLE_AI_SPANS,
2362
+ columns: ["parentSpanId", "startedAt DESC"]
2363
+ },
2364
+ {
2365
+ name: `${schemaPrefix}mastra_ai_spans_name_idx`,
2366
+ table: storage.TABLE_AI_SPANS,
2367
+ columns: ["name"]
2368
+ },
2369
+ {
2370
+ name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
2371
+ table: storage.TABLE_AI_SPANS,
2372
+ columns: ["spanType", "startedAt DESC"]
2373
+ }
2374
+ ];
2375
+ }
2376
+ /**
2377
+ * Creates automatic indexes for optimal query performance
2378
+ * Uses getAutomaticIndexDefinitions() to determine which indexes to create
2379
+ */
2380
+ async createAutomaticIndexes() {
2381
+ try {
2382
+ const indexes = this.getAutomaticIndexDefinitions();
2383
+ for (const indexOptions of indexes) {
2384
+ try {
2385
+ await this.createIndex(indexOptions);
2386
+ } catch (error) {
2387
+ this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
2388
+ }
2389
+ }
2390
+ } catch (error$1) {
2391
+ throw new error.MastraError(
2392
+ {
2393
+ id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
2394
+ domain: error.ErrorDomain.STORAGE,
2395
+ category: error.ErrorCategory.THIRD_PARTY
2396
+ },
2397
+ error$1
2398
+ );
2399
+ }
2400
+ }
2401
+ };
2402
+ function transformScoreRow(row) {
2403
+ return {
2404
+ ...row,
2405
+ input: storage.safelyParseJSON(row.input),
2406
+ scorer: storage.safelyParseJSON(row.scorer),
2407
+ preprocessStepResult: storage.safelyParseJSON(row.preprocessStepResult),
2408
+ analyzeStepResult: storage.safelyParseJSON(row.analyzeStepResult),
2409
+ metadata: storage.safelyParseJSON(row.metadata),
2410
+ output: storage.safelyParseJSON(row.output),
2411
+ additionalContext: storage.safelyParseJSON(row.additionalContext),
2412
+ runtimeContext: storage.safelyParseJSON(row.runtimeContext),
2413
+ entity: storage.safelyParseJSON(row.entity),
2414
+ createdAt: row.createdAt,
2415
+ updatedAt: row.updatedAt
2416
+ };
2417
+ }
2418
+ var ScoresMSSQL = class extends storage.ScoresStorage {
2419
+ pool;
2420
+ operations;
2421
+ schema;
2422
+ constructor({
2423
+ pool,
2424
+ operations,
2425
+ schema
2426
+ }) {
2427
+ super();
2428
+ this.pool = pool;
2429
+ this.operations = operations;
2430
+ this.schema = schema;
2431
+ }
2432
+ async getScoreById({ id }) {
2433
+ try {
2434
+ const request = this.pool.request();
2435
+ request.input("p1", id);
2436
+ const result = await request.query(
2437
+ `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE id = @p1`
2438
+ );
1466
2439
  if (result.recordset.length === 0) {
1467
2440
  return null;
1468
2441
  }
@@ -1512,15 +2485,15 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1512
2485
  record: {
1513
2486
  id: scoreId,
1514
2487
  ...rest,
1515
- input: JSON.stringify(input) || "",
1516
- output: JSON.stringify(output) || "",
1517
- preprocessStepResult: preprocessStepResult ? JSON.stringify(preprocessStepResult) : null,
1518
- analyzeStepResult: analyzeStepResult ? JSON.stringify(analyzeStepResult) : null,
1519
- metadata: metadata ? JSON.stringify(metadata) : null,
1520
- additionalContext: additionalContext ? JSON.stringify(additionalContext) : null,
1521
- runtimeContext: runtimeContext ? JSON.stringify(runtimeContext) : null,
1522
- entity: entity ? JSON.stringify(entity) : null,
1523
- scorer: scorer ? JSON.stringify(scorer) : null,
2488
+ input: input || "",
2489
+ output: output || "",
2490
+ preprocessStepResult: preprocessStepResult || null,
2491
+ analyzeStepResult: analyzeStepResult || null,
2492
+ metadata: metadata || null,
2493
+ additionalContext: additionalContext || null,
2494
+ runtimeContext: runtimeContext || null,
2495
+ entity: entity || null,
2496
+ scorer: scorer || null,
1524
2497
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1525
2498
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1526
2499
  }
@@ -1540,14 +2513,37 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1540
2513
  }
1541
2514
  async getScoresByScorerId({
1542
2515
  scorerId,
1543
- pagination
2516
+ pagination,
2517
+ entityId,
2518
+ entityType,
2519
+ source
1544
2520
  }) {
1545
2521
  try {
1546
- const request = this.pool.request();
1547
- request.input("p1", scorerId);
1548
- const totalResult = await request.query(
1549
- `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [scorerId] = @p1`
1550
- );
2522
+ const conditions = ["[scorerId] = @p1"];
2523
+ const params = { p1: scorerId };
2524
+ let paramIndex = 2;
2525
+ if (entityId) {
2526
+ conditions.push(`[entityId] = @p${paramIndex}`);
2527
+ params[`p${paramIndex}`] = entityId;
2528
+ paramIndex++;
2529
+ }
2530
+ if (entityType) {
2531
+ conditions.push(`[entityType] = @p${paramIndex}`);
2532
+ params[`p${paramIndex}`] = entityType;
2533
+ paramIndex++;
2534
+ }
2535
+ if (source) {
2536
+ conditions.push(`[source] = @p${paramIndex}`);
2537
+ params[`p${paramIndex}`] = source;
2538
+ paramIndex++;
2539
+ }
2540
+ const whereClause = conditions.join(" AND ");
2541
+ const tableName = getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
2542
+ const countRequest = this.pool.request();
2543
+ Object.entries(params).forEach(([key, value]) => {
2544
+ countRequest.input(key, value);
2545
+ });
2546
+ const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
1551
2547
  const total = totalResult.recordset[0]?.count || 0;
1552
2548
  if (total === 0) {
1553
2549
  return {
@@ -1561,12 +2557,13 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1561
2557
  };
1562
2558
  }
1563
2559
  const dataRequest = this.pool.request();
1564
- dataRequest.input("p1", scorerId);
1565
- dataRequest.input("p2", pagination.perPage);
1566
- dataRequest.input("p3", pagination.page * pagination.perPage);
1567
- const result = await dataRequest.query(
1568
- `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [scorerId] = @p1 ORDER BY [createdAt] DESC OFFSET @p3 ROWS FETCH NEXT @p2 ROWS ONLY`
1569
- );
2560
+ Object.entries(params).forEach(([key, value]) => {
2561
+ dataRequest.input(key, value);
2562
+ });
2563
+ dataRequest.input("perPage", pagination.perPage);
2564
+ dataRequest.input("offset", pagination.page * pagination.perPage);
2565
+ const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
2566
+ const result = await dataRequest.query(dataQuery);
1570
2567
  return {
1571
2568
  pagination: {
1572
2569
  total: Number(total),
@@ -1823,7 +2820,7 @@ var TracesMSSQL = class extends storage.TracesStorage {
1823
2820
  const countRequest = this.pool.request();
1824
2821
  Object.entries(paramMap).forEach(([key, value]) => {
1825
2822
  if (value instanceof Date) {
1826
- countRequest.input(key, sql2__default.default.DateTime, value);
2823
+ countRequest.input(key, sql3__default.default.DateTime, value);
1827
2824
  } else {
1828
2825
  countRequest.input(key, value);
1829
2826
  }
@@ -1857,7 +2854,7 @@ var TracesMSSQL = class extends storage.TracesStorage {
1857
2854
  const dataRequest = this.pool.request();
1858
2855
  Object.entries(paramMap).forEach(([key, value]) => {
1859
2856
  if (value instanceof Date) {
1860
- dataRequest.input(key, sql2__default.default.DateTime, value);
2857
+ dataRequest.input(key, sql3__default.default.DateTime, value);
1861
2858
  } else {
1862
2859
  dataRequest.input(key, value);
1863
2860
  }
@@ -1913,24 +2910,6 @@ var TracesMSSQL = class extends storage.TracesStorage {
1913
2910
  });
1914
2911
  }
1915
2912
  };
1916
- function parseWorkflowRun(row) {
1917
- let parsedSnapshot = row.snapshot;
1918
- if (typeof parsedSnapshot === "string") {
1919
- try {
1920
- parsedSnapshot = JSON.parse(row.snapshot);
1921
- } catch (e) {
1922
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1923
- }
1924
- }
1925
- return {
1926
- workflowName: row.workflow_name,
1927
- runId: row.run_id,
1928
- snapshot: parsedSnapshot,
1929
- createdAt: row.createdAt,
1930
- updatedAt: row.updatedAt,
1931
- resourceId: row.resourceId
1932
- };
1933
- }
1934
2913
  var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1935
2914
  pool;
1936
2915
  operations;
@@ -1945,21 +2924,163 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1945
2924
  this.operations = operations;
1946
2925
  this.schema = schema;
1947
2926
  }
1948
- updateWorkflowResults({
1949
- // workflowName,
1950
- // runId,
1951
- // stepId,
1952
- // result,
1953
- // runtimeContext,
2927
+ parseWorkflowRun(row) {
2928
+ let parsedSnapshot = row.snapshot;
2929
+ if (typeof parsedSnapshot === "string") {
2930
+ try {
2931
+ parsedSnapshot = JSON.parse(row.snapshot);
2932
+ } catch (e) {
2933
+ this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
2934
+ }
2935
+ }
2936
+ return {
2937
+ workflowName: row.workflow_name,
2938
+ runId: row.run_id,
2939
+ snapshot: parsedSnapshot,
2940
+ createdAt: row.createdAt,
2941
+ updatedAt: row.updatedAt,
2942
+ resourceId: row.resourceId
2943
+ };
2944
+ }
2945
+ async updateWorkflowResults({
2946
+ workflowName,
2947
+ runId,
2948
+ stepId,
2949
+ result,
2950
+ runtimeContext
1954
2951
  }) {
1955
- throw new Error("Method not implemented.");
2952
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2953
+ const transaction = this.pool.transaction();
2954
+ try {
2955
+ await transaction.begin();
2956
+ const selectRequest = new sql3__default.default.Request(transaction);
2957
+ selectRequest.input("workflow_name", workflowName);
2958
+ selectRequest.input("run_id", runId);
2959
+ const existingSnapshotResult = await selectRequest.query(
2960
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
2961
+ );
2962
+ let snapshot;
2963
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
2964
+ snapshot = {
2965
+ context: {},
2966
+ activePaths: [],
2967
+ timestamp: Date.now(),
2968
+ suspendedPaths: {},
2969
+ resumeLabels: {},
2970
+ serializedStepGraph: [],
2971
+ value: {},
2972
+ waitingPaths: {},
2973
+ status: "pending",
2974
+ runId,
2975
+ runtimeContext: {}
2976
+ };
2977
+ } else {
2978
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
2979
+ snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2980
+ }
2981
+ snapshot.context[stepId] = result;
2982
+ snapshot.runtimeContext = { ...snapshot.runtimeContext, ...runtimeContext };
2983
+ const upsertReq = new sql3__default.default.Request(transaction);
2984
+ upsertReq.input("workflow_name", workflowName);
2985
+ upsertReq.input("run_id", runId);
2986
+ upsertReq.input("snapshot", JSON.stringify(snapshot));
2987
+ upsertReq.input("createdAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
2988
+ upsertReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
2989
+ await upsertReq.query(
2990
+ `MERGE ${table} AS target
2991
+ USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
2992
+ ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
2993
+ WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
2994
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
2995
+ VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
2996
+ );
2997
+ await transaction.commit();
2998
+ return snapshot.context;
2999
+ } catch (error$1) {
3000
+ try {
3001
+ await transaction.rollback();
3002
+ } catch {
3003
+ }
3004
+ throw new error.MastraError(
3005
+ {
3006
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
3007
+ domain: error.ErrorDomain.STORAGE,
3008
+ category: error.ErrorCategory.THIRD_PARTY,
3009
+ details: {
3010
+ workflowName,
3011
+ runId,
3012
+ stepId
3013
+ }
3014
+ },
3015
+ error$1
3016
+ );
3017
+ }
1956
3018
  }
1957
- updateWorkflowState({
1958
- // workflowName,
1959
- // runId,
1960
- // opts,
3019
+ async updateWorkflowState({
3020
+ workflowName,
3021
+ runId,
3022
+ opts
1961
3023
  }) {
1962
- throw new Error("Method not implemented.");
3024
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
3025
+ const transaction = this.pool.transaction();
3026
+ try {
3027
+ await transaction.begin();
3028
+ const selectRequest = new sql3__default.default.Request(transaction);
3029
+ selectRequest.input("workflow_name", workflowName);
3030
+ selectRequest.input("run_id", runId);
3031
+ const existingSnapshotResult = await selectRequest.query(
3032
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
3033
+ );
3034
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
3035
+ await transaction.rollback();
3036
+ return void 0;
3037
+ }
3038
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
3039
+ const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
3040
+ if (!snapshot || !snapshot?.context) {
3041
+ await transaction.rollback();
3042
+ throw new error.MastraError(
3043
+ {
3044
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
3045
+ domain: error.ErrorDomain.STORAGE,
3046
+ category: error.ErrorCategory.SYSTEM,
3047
+ details: {
3048
+ workflowName,
3049
+ runId
3050
+ }
3051
+ },
3052
+ new Error(`Snapshot not found for runId ${runId}`)
3053
+ );
3054
+ }
3055
+ const updatedSnapshot = { ...snapshot, ...opts };
3056
+ const updateRequest = new sql3__default.default.Request(transaction);
3057
+ updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
3058
+ updateRequest.input("workflow_name", workflowName);
3059
+ updateRequest.input("run_id", runId);
3060
+ updateRequest.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
3061
+ await updateRequest.query(
3062
+ `UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
3063
+ );
3064
+ await transaction.commit();
3065
+ return updatedSnapshot;
3066
+ } catch (error$1) {
3067
+ try {
3068
+ await transaction.rollback();
3069
+ } catch {
3070
+ }
3071
+ throw new error.MastraError(
3072
+ {
3073
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
3074
+ domain: error.ErrorDomain.STORAGE,
3075
+ category: error.ErrorCategory.THIRD_PARTY,
3076
+ details: {
3077
+ workflowName,
3078
+ runId
3079
+ }
3080
+ },
3081
+ error$1
3082
+ );
3083
+ }
1963
3084
  }
1964
3085
  async persistWorkflowSnapshot({
1965
3086
  workflowName,
@@ -1975,8 +3096,8 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1975
3096
  request.input("run_id", runId);
1976
3097
  request.input("resourceId", resourceId);
1977
3098
  request.input("snapshot", JSON.stringify(snapshot));
1978
- request.input("createdAt", sql2__default.default.DateTime2, new Date(now));
1979
- request.input("updatedAt", sql2__default.default.DateTime2, new Date(now));
3099
+ request.input("createdAt", sql3__default.default.DateTime2, new Date(now));
3100
+ request.input("updatedAt", sql3__default.default.DateTime2, new Date(now));
1980
3101
  const mergeSql = `MERGE INTO ${table} AS target
1981
3102
  USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
1982
3103
  ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
@@ -2057,7 +3178,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2057
3178
  if (!result.recordset || result.recordset.length === 0) {
2058
3179
  return null;
2059
3180
  }
2060
- return parseWorkflowRun(result.recordset[0]);
3181
+ return this.parseWorkflowRun(result.recordset[0]);
2061
3182
  } catch (error$1) {
2062
3183
  throw new error.MastraError(
2063
3184
  {
@@ -2094,7 +3215,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2094
3215
  conditions.push(`[resourceId] = @resourceId`);
2095
3216
  paramMap["resourceId"] = resourceId;
2096
3217
  } else {
2097
- console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
3218
+ this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
2098
3219
  }
2099
3220
  }
2100
3221
  if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
@@ -2111,7 +3232,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2111
3232
  const request = this.pool.request();
2112
3233
  Object.entries(paramMap).forEach(([key, value]) => {
2113
3234
  if (value instanceof Date) {
2114
- request.input(key, sql2__default.default.DateTime, value);
3235
+ request.input(key, sql3__default.default.DateTime, value);
2115
3236
  } else {
2116
3237
  request.input(key, value);
2117
3238
  }
@@ -2128,7 +3249,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2128
3249
  request.input("offset", offset);
2129
3250
  }
2130
3251
  const result = await request.query(query);
2131
- const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
3252
+ const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
2132
3253
  return { runs, total: total || runs.length };
2133
3254
  } catch (error$1) {
2134
3255
  throw new error.MastraError(
@@ -2168,7 +3289,7 @@ var MSSQLStore = class extends storage.MastraStorage {
2168
3289
  }
2169
3290
  }
2170
3291
  this.schema = config.schemaName || "dbo";
2171
- this.pool = "connectionString" in config ? new sql2__default.default.ConnectionPool(config.connectionString) : new sql2__default.default.ConnectionPool({
3292
+ this.pool = "connectionString" in config ? new sql3__default.default.ConnectionPool(config.connectionString) : new sql3__default.default.ConnectionPool({
2172
3293
  server: config.server,
2173
3294
  database: config.database,
2174
3295
  user: config.user,
@@ -2182,13 +3303,15 @@ var MSSQLStore = class extends storage.MastraStorage {
2182
3303
  const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
2183
3304
  const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
2184
3305
  const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
3306
+ const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
2185
3307
  this.stores = {
2186
3308
  operations,
2187
3309
  scores,
2188
3310
  traces,
2189
3311
  workflows,
2190
3312
  legacyEvals,
2191
- memory
3313
+ memory,
3314
+ observability
2192
3315
  };
2193
3316
  } catch (e) {
2194
3317
  throw new error.MastraError(
@@ -2208,6 +3331,11 @@ var MSSQLStore = class extends storage.MastraStorage {
2208
3331
  try {
2209
3332
  await this.isConnected;
2210
3333
  await super.init();
3334
+ try {
3335
+ await this.stores.operations.createAutomaticIndexes();
3336
+ } catch (indexError) {
3337
+ this.logger?.warn?.("Failed to create indexes:", indexError);
3338
+ }
2211
3339
  } catch (error$1) {
2212
3340
  this.isConnected = null;
2213
3341
  throw new error.MastraError(
@@ -2235,7 +3363,9 @@ var MSSQLStore = class extends storage.MastraStorage {
2235
3363
  hasColumn: true,
2236
3364
  createTable: true,
2237
3365
  deleteMessages: true,
2238
- getScoresBySpan: true
3366
+ getScoresBySpan: true,
3367
+ aiTracing: true,
3368
+ indexManagement: true
2239
3369
  };
2240
3370
  }
2241
3371
  /** @deprecated use getEvals instead */
@@ -2401,6 +3531,60 @@ var MSSQLStore = class extends storage.MastraStorage {
2401
3531
  async close() {
2402
3532
  await this.pool.close();
2403
3533
  }
3534
+ /**
3535
+ * Index Management
3536
+ */
3537
+ async createIndex(options) {
3538
+ return this.stores.operations.createIndex(options);
3539
+ }
3540
+ async listIndexes(tableName) {
3541
+ return this.stores.operations.listIndexes(tableName);
3542
+ }
3543
+ async describeIndex(indexName) {
3544
+ return this.stores.operations.describeIndex(indexName);
3545
+ }
3546
+ async dropIndex(indexName) {
3547
+ return this.stores.operations.dropIndex(indexName);
3548
+ }
3549
+ /**
3550
+ * AI Tracing / Observability
3551
+ */
3552
+ getObservabilityStore() {
3553
+ if (!this.stores.observability) {
3554
+ throw new error.MastraError({
3555
+ id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
3556
+ domain: error.ErrorDomain.STORAGE,
3557
+ category: error.ErrorCategory.SYSTEM,
3558
+ text: "Observability storage is not initialized"
3559
+ });
3560
+ }
3561
+ return this.stores.observability;
3562
+ }
3563
+ async createAISpan(span) {
3564
+ return this.getObservabilityStore().createAISpan(span);
3565
+ }
3566
+ async updateAISpan({
3567
+ spanId,
3568
+ traceId,
3569
+ updates
3570
+ }) {
3571
+ return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
3572
+ }
3573
+ async getAITrace(traceId) {
3574
+ return this.getObservabilityStore().getAITrace(traceId);
3575
+ }
3576
+ async getAITracesPaginated(args) {
3577
+ return this.getObservabilityStore().getAITracesPaginated(args);
3578
+ }
3579
+ async batchCreateAISpans(args) {
3580
+ return this.getObservabilityStore().batchCreateAISpans(args);
3581
+ }
3582
+ async batchUpdateAISpans(args) {
3583
+ return this.getObservabilityStore().batchUpdateAISpans(args);
3584
+ }
3585
+ async batchDeleteAITraces(args) {
3586
+ return this.getObservabilityStore().batchDeleteAITraces(args);
3587
+ }
2404
3588
  /**
2405
3589
  * Scorers
2406
3590
  */
@@ -2409,9 +3593,18 @@ var MSSQLStore = class extends storage.MastraStorage {
2409
3593
  }
2410
3594
  async getScoresByScorerId({
2411
3595
  scorerId: _scorerId,
2412
- pagination: _pagination
3596
+ pagination: _pagination,
3597
+ entityId: _entityId,
3598
+ entityType: _entityType,
3599
+ source: _source
2413
3600
  }) {
2414
- return this.stores.scores.getScoresByScorerId({ scorerId: _scorerId, pagination: _pagination });
3601
+ return this.stores.scores.getScoresByScorerId({
3602
+ scorerId: _scorerId,
3603
+ pagination: _pagination,
3604
+ entityId: _entityId,
3605
+ entityType: _entityType,
3606
+ source: _source
3607
+ });
2415
3608
  }
2416
3609
  async saveScore(_score) {
2417
3610
  return this.stores.scores.saveScore(_score);