@mastra/mssql 0.0.0-fix-memory-search-fetch-20251027160505 → 0.0.0-fix-persist-session-cache-option-mcp-server-20251030161352

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
@@ -3,8 +3,9 @@
3
3
  var error = require('@mastra/core/error');
4
4
  var storage = require('@mastra/core/storage');
5
5
  var sql2 = require('mssql');
6
- var utils = require('@mastra/core/utils');
7
6
  var agent = require('@mastra/core/agent');
7
+ var utils = require('@mastra/core/utils');
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 }; }
@@ -21,154 +22,71 @@ function getTableName({ indexName, schemaName }) {
21
22
  const quotedSchemaName = schemaName;
22
23
  return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
23
24
  }
24
-
25
- // src/storage/domains/legacy-evals/index.ts
26
- function transformEvalRow(row) {
27
- let testInfoValue = null, resultValue = null;
28
- if (row.test_info) {
29
- try {
30
- testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
31
- } catch {
32
- }
25
+ function buildDateRangeFilter(dateRange, fieldName) {
26
+ const filters = {};
27
+ if (dateRange?.start) {
28
+ filters[`${fieldName}_gte`] = dateRange.start;
33
29
  }
34
- if (row.test_info) {
35
- try {
36
- resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
37
- } catch {
38
- }
30
+ if (dateRange?.end) {
31
+ filters[`${fieldName}_lte`] = dateRange.end;
39
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
+ });
40
57
  return {
41
- agentName: row.agent_name,
42
- input: row.input,
43
- output: row.output,
44
- result: resultValue,
45
- metricName: row.metric_name,
46
- instructions: row.instructions,
47
- testInfo: testInfoValue,
48
- globalRunId: row.global_run_id,
49
- runId: row.run_id,
50
- createdAt: row.created_at
58
+ sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
59
+ params
51
60
  };
52
61
  }
53
- var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
54
- pool;
55
- schema;
56
- constructor({ pool, schema }) {
57
- super();
58
- this.pool = pool;
59
- this.schema = schema;
60
- }
61
- /** @deprecated use getEvals instead */
62
- async getEvalsByAgentName(agentName, type) {
63
- try {
64
- let query = `SELECT * FROM ${getTableName({ indexName: storage.TABLE_EVALS, schemaName: getSchemaName(this.schema) })} WHERE agent_name = @p1`;
65
- if (type === "test") {
66
- query += " AND test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL";
67
- } else if (type === "live") {
68
- query += " AND (test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)";
69
- }
70
- query += " ORDER BY created_at DESC";
71
- const request = this.pool.request();
72
- request.input("p1", agentName);
73
- const result = await request.query(query);
74
- const rows = result.recordset;
75
- return typeof transformEvalRow === "function" ? rows?.map((row) => transformEvalRow(row)) ?? [] : rows ?? [];
76
- } catch (error) {
77
- if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
78
- return [];
79
- }
80
- console.error("Failed to get evals for the specified agent: " + error?.message);
81
- throw error;
82
- }
83
- }
84
- async getEvals(options = {}) {
85
- const { agentName, type, page = 0, perPage = 100, dateRange } = options;
86
- const fromDate = dateRange?.start;
87
- const toDate = dateRange?.end;
88
- const where = [];
89
- const params = {};
90
- if (agentName) {
91
- where.push("agent_name = @agentName");
92
- params["agentName"] = agentName;
93
- }
94
- if (type === "test") {
95
- where.push("test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL");
96
- } else if (type === "live") {
97
- where.push("(test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)");
98
- }
99
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
100
- where.push(`[created_at] >= @fromDate`);
101
- params[`fromDate`] = fromDate.toISOString();
102
- }
103
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
104
- where.push(`[created_at] <= @toDate`);
105
- params[`toDate`] = toDate.toISOString();
106
- }
107
- const whereClause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
108
- const tableName = getTableName({ indexName: storage.TABLE_EVALS, schemaName: getSchemaName(this.schema) });
109
- const offset = page * perPage;
110
- const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
111
- const dataQuery = `SELECT * FROM ${tableName} ${whereClause} ORDER BY seq_id DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
112
- try {
113
- const countReq = this.pool.request();
114
- Object.entries(params).forEach(([key, value]) => {
115
- if (value instanceof Date) {
116
- countReq.input(key, sql2__default.default.DateTime, value);
117
- } else {
118
- countReq.input(key, value);
119
- }
120
- });
121
- const countResult = await countReq.query(countQuery);
122
- const total = countResult.recordset[0]?.total || 0;
123
- if (total === 0) {
124
- return {
125
- evals: [],
126
- total: 0,
127
- page,
128
- perPage,
129
- hasMore: false
130
- };
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;
131
75
  }
132
- const req = this.pool.request();
133
- Object.entries(params).forEach(([key, value]) => {
134
- if (value instanceof Date) {
135
- req.input(key, sql2__default.default.DateTime, value);
136
- } else {
137
- req.input(key, value);
138
- }
139
- });
140
- req.input("offset", offset);
141
- req.input("perPage", perPage);
142
- const result = await req.query(dataQuery);
143
- const rows = result.recordset;
144
- return {
145
- evals: rows?.map((row) => transformEvalRow(row)) ?? [],
146
- total,
147
- page,
148
- perPage,
149
- hasMore: offset + (rows?.length ?? 0) < total
150
- };
151
- } catch (error$1) {
152
- const mastraError = new error.MastraError(
153
- {
154
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_EVALS_FAILED",
155
- domain: error.ErrorDomain.STORAGE,
156
- category: error.ErrorCategory.THIRD_PARTY,
157
- details: {
158
- agentName: agentName || "all",
159
- type: type || "all",
160
- page,
161
- perPage
162
- }
163
- },
164
- error$1
165
- );
166
- this.logger?.error?.(mastraError.toString());
167
- this.logger?.trackException(mastraError);
168
- throw mastraError;
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;
169
84
  }
170
- }
171
- };
85
+ });
86
+ return result;
87
+ }
88
+
89
+ // src/storage/domains/memory/index.ts
172
90
  var MemoryMSSQL = class extends storage.MemoryStorage {
173
91
  pool;
174
92
  schema;
@@ -200,7 +118,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
200
118
  }
201
119
  async getThreadById({ threadId }) {
202
120
  try {
203
- const sql6 = `SELECT
121
+ const sql5 = `SELECT
204
122
  id,
205
123
  [resourceId],
206
124
  title,
@@ -211,7 +129,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
211
129
  WHERE id = @threadId`;
212
130
  const request = this.pool.request();
213
131
  request.input("threadId", threadId);
214
- const resultSet = await request.query(sql6);
132
+ const resultSet = await request.query(sql5);
215
133
  const thread = resultSet.recordset[0] || null;
216
134
  if (!thread) {
217
135
  return null;
@@ -257,7 +175,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
257
175
  };
258
176
  }
259
177
  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`;
178
+ const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
179
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
261
180
  const dataRequest = this.pool.request();
262
181
  dataRequest.input("resourceId", resourceId);
263
182
  dataRequest.input("perPage", perPage);
@@ -314,7 +233,12 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
314
233
  req.input("id", thread.id);
315
234
  req.input("resourceId", thread.resourceId);
316
235
  req.input("title", thread.title);
317
- req.input("metadata", thread.metadata ? JSON.stringify(thread.metadata) : null);
236
+ const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
237
+ if (metadata === null) {
238
+ req.input("metadata", sql2__default.default.NVarChar, null);
239
+ } else {
240
+ req.input("metadata", metadata);
241
+ }
318
242
  req.input("createdAt", sql2__default.default.DateTime2, thread.createdAt);
319
243
  req.input("updatedAt", sql2__default.default.DateTime2, thread.updatedAt);
320
244
  await req.query(mergeSql);
@@ -341,7 +265,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
341
265
  try {
342
266
  const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
343
267
  const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
344
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection}`;
268
+ const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
269
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
345
270
  const request = this.pool.request();
346
271
  request.input("resourceId", resourceId);
347
272
  const resultSet = await request.query(dataQuery);
@@ -384,7 +309,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
384
309
  };
385
310
  try {
386
311
  const table = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
387
- const sql6 = `UPDATE ${table}
312
+ const sql5 = `UPDATE ${table}
388
313
  SET title = @title,
389
314
  metadata = @metadata,
390
315
  [updatedAt] = @updatedAt
@@ -395,7 +320,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
395
320
  req.input("title", title);
396
321
  req.input("metadata", JSON.stringify(mergedMetadata));
397
322
  req.input("updatedAt", /* @__PURE__ */ new Date());
398
- const result = await req.query(sql6);
323
+ const result = await req.query(sql5);
399
324
  let thread = result.recordset && result.recordset[0];
400
325
  if (thread && "seq_id" in thread) {
401
326
  const { seq_id, ...rest } = thread;
@@ -590,7 +515,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
590
515
  error$1
591
516
  );
592
517
  this.logger?.error?.(mastraError.toString());
593
- this.logger?.trackException(mastraError);
518
+ this.logger?.trackException?.(mastraError);
594
519
  return [];
595
520
  }
596
521
  }
@@ -630,10 +555,24 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
630
555
  error$1
631
556
  );
632
557
  this.logger?.error?.(mastraError.toString());
633
- this.logger?.trackException(mastraError);
558
+ this.logger?.trackException?.(mastraError);
634
559
  return [];
635
560
  }
636
561
  }
562
+ async listMessages(_args) {
563
+ throw new Error(
564
+ `listMessages is not yet implemented by this storage adapter (${this.constructor.name}). This method is currently being rolled out across all storage adapters. Please use getMessages or getMessagesPaginated as an alternative, or wait for the implementation.`
565
+ );
566
+ }
567
+ async listMessagesById({ messageIds }) {
568
+ return this.getMessagesById({ messageIds, format: "v2" });
569
+ }
570
+ async listThreadsByResourceId(args) {
571
+ const { resourceId, limit, offset, orderBy, sortDirection } = args;
572
+ const page = Math.floor(offset / limit);
573
+ const perPage = limit;
574
+ return this.getThreadsByResourceIdPaginated({ resourceId, page, perPage, orderBy, sortDirection });
575
+ }
637
576
  async getMessagesPaginated(args) {
638
577
  const { threadId, resourceId, format, selectBy } = args;
639
578
  const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
@@ -692,7 +631,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
692
631
  const parsed = this._parseAndFormatMessages(messages, format);
693
632
  return {
694
633
  messages: parsed,
695
- total: total + excludeIds.length,
634
+ total,
696
635
  page,
697
636
  perPage,
698
637
  hasMore: currentOffset + rows.length < total
@@ -712,7 +651,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
712
651
  error$1
713
652
  );
714
653
  this.logger?.error?.(mastraError.toString());
715
- this.logger?.trackException(mastraError);
654
+ this.logger?.trackException?.(mastraError);
716
655
  return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
717
656
  }
718
657
  }
@@ -979,8 +918,10 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
979
918
  return null;
980
919
  }
981
920
  return {
982
- ...result,
983
- workingMemory: typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
921
+ id: result.id,
922
+ createdAt: result.createdAt,
923
+ updatedAt: result.updatedAt,
924
+ workingMemory: result.workingMemory,
984
925
  metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
985
926
  };
986
927
  } catch (error$1) {
@@ -994,7 +935,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
994
935
  error$1
995
936
  );
996
937
  this.logger?.error?.(mastraError.toString());
997
- this.logger?.trackException(mastraError);
938
+ this.logger?.trackException?.(mastraError);
998
939
  throw mastraError;
999
940
  }
1000
941
  }
@@ -1003,7 +944,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1003
944
  tableName: storage.TABLE_RESOURCES,
1004
945
  record: {
1005
946
  ...resource,
1006
- metadata: JSON.stringify(resource.metadata)
947
+ metadata: resource.metadata
1007
948
  }
1008
949
  });
1009
950
  return resource;
@@ -1061,20 +1002,337 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1061
1002
  error$1
1062
1003
  );
1063
1004
  this.logger?.error?.(mastraError.toString());
1064
- this.logger?.trackException(mastraError);
1005
+ this.logger?.trackException?.(mastraError);
1065
1006
  throw mastraError;
1066
1007
  }
1067
1008
  }
1068
1009
  };
1010
+ var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
1011
+ pool;
1012
+ operations;
1013
+ schema;
1014
+ constructor({
1015
+ pool,
1016
+ operations,
1017
+ schema
1018
+ }) {
1019
+ super();
1020
+ this.pool = pool;
1021
+ this.operations = operations;
1022
+ this.schema = schema;
1023
+ }
1024
+ get aiTracingStrategy() {
1025
+ return {
1026
+ preferred: "batch-with-updates",
1027
+ supported: ["batch-with-updates", "insert-only"]
1028
+ };
1029
+ }
1030
+ async createAISpan(span) {
1031
+ try {
1032
+ const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
1033
+ const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
1034
+ const record = {
1035
+ ...span,
1036
+ startedAt,
1037
+ endedAt
1038
+ // Note: createdAt/updatedAt will be set by default values
1039
+ };
1040
+ return this.operations.insert({ tableName: storage.TABLE_AI_SPANS, record });
1041
+ } catch (error$1) {
1042
+ throw new error.MastraError(
1043
+ {
1044
+ id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
1045
+ domain: error.ErrorDomain.STORAGE,
1046
+ category: error.ErrorCategory.USER,
1047
+ details: {
1048
+ spanId: span.spanId,
1049
+ traceId: span.traceId,
1050
+ spanType: span.spanType,
1051
+ spanName: span.name
1052
+ }
1053
+ },
1054
+ error$1
1055
+ );
1056
+ }
1057
+ }
1058
+ async getAITrace(traceId) {
1059
+ try {
1060
+ const tableName = getTableName({
1061
+ indexName: storage.TABLE_AI_SPANS,
1062
+ schemaName: getSchemaName(this.schema)
1063
+ });
1064
+ const request = this.pool.request();
1065
+ request.input("traceId", traceId);
1066
+ const result = await request.query(
1067
+ `SELECT
1068
+ [traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
1069
+ [attributes], [metadata], [links], [input], [output], [error], [isEvent],
1070
+ [startedAt], [endedAt], [createdAt], [updatedAt]
1071
+ FROM ${tableName}
1072
+ WHERE [traceId] = @traceId
1073
+ ORDER BY [startedAt] DESC`
1074
+ );
1075
+ if (!result.recordset || result.recordset.length === 0) {
1076
+ return null;
1077
+ }
1078
+ return {
1079
+ traceId,
1080
+ spans: result.recordset.map(
1081
+ (span) => transformFromSqlRow({
1082
+ tableName: storage.TABLE_AI_SPANS,
1083
+ sqlRow: span
1084
+ })
1085
+ )
1086
+ };
1087
+ } catch (error$1) {
1088
+ throw new error.MastraError(
1089
+ {
1090
+ id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
1091
+ domain: error.ErrorDomain.STORAGE,
1092
+ category: error.ErrorCategory.USER,
1093
+ details: {
1094
+ traceId
1095
+ }
1096
+ },
1097
+ error$1
1098
+ );
1099
+ }
1100
+ }
1101
+ async updateAISpan({
1102
+ spanId,
1103
+ traceId,
1104
+ updates
1105
+ }) {
1106
+ try {
1107
+ const data = { ...updates };
1108
+ if (data.endedAt instanceof Date) {
1109
+ data.endedAt = data.endedAt.toISOString();
1110
+ }
1111
+ if (data.startedAt instanceof Date) {
1112
+ data.startedAt = data.startedAt.toISOString();
1113
+ }
1114
+ await this.operations.update({
1115
+ tableName: storage.TABLE_AI_SPANS,
1116
+ keys: { spanId, traceId },
1117
+ data
1118
+ });
1119
+ } catch (error$1) {
1120
+ throw new error.MastraError(
1121
+ {
1122
+ id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
1123
+ domain: error.ErrorDomain.STORAGE,
1124
+ category: error.ErrorCategory.USER,
1125
+ details: {
1126
+ spanId,
1127
+ traceId
1128
+ }
1129
+ },
1130
+ error$1
1131
+ );
1132
+ }
1133
+ }
1134
+ async getAITracesPaginated({
1135
+ filters,
1136
+ pagination
1137
+ }) {
1138
+ const page = pagination?.page ?? 0;
1139
+ const perPage = pagination?.perPage ?? 10;
1140
+ const { entityId, entityType, ...actualFilters } = filters || {};
1141
+ const filtersWithDateRange = {
1142
+ ...actualFilters,
1143
+ ...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
1144
+ parentSpanId: null
1145
+ // Only get root spans for traces
1146
+ };
1147
+ const whereClause = prepareWhereClause(filtersWithDateRange);
1148
+ let actualWhereClause = whereClause.sql;
1149
+ const params = { ...whereClause.params };
1150
+ let currentParamIndex = Object.keys(params).length + 1;
1151
+ if (entityId && entityType) {
1152
+ let name = "";
1153
+ if (entityType === "workflow") {
1154
+ name = `workflow run: '${entityId}'`;
1155
+ } else if (entityType === "agent") {
1156
+ name = `agent run: '${entityId}'`;
1157
+ } else {
1158
+ const error$1 = new error.MastraError({
1159
+ id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
1160
+ domain: error.ErrorDomain.STORAGE,
1161
+ category: error.ErrorCategory.USER,
1162
+ details: {
1163
+ entityType
1164
+ },
1165
+ text: `Cannot filter by entity type: ${entityType}`
1166
+ });
1167
+ throw error$1;
1168
+ }
1169
+ const entityParam = `p${currentParamIndex++}`;
1170
+ if (actualWhereClause) {
1171
+ actualWhereClause += ` AND [name] = @${entityParam}`;
1172
+ } else {
1173
+ actualWhereClause = ` WHERE [name] = @${entityParam}`;
1174
+ }
1175
+ params[entityParam] = name;
1176
+ }
1177
+ const tableName = getTableName({
1178
+ indexName: storage.TABLE_AI_SPANS,
1179
+ schemaName: getSchemaName(this.schema)
1180
+ });
1181
+ try {
1182
+ const countRequest = this.pool.request();
1183
+ Object.entries(params).forEach(([key, value]) => {
1184
+ countRequest.input(key, value);
1185
+ });
1186
+ const countResult = await countRequest.query(
1187
+ `SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
1188
+ );
1189
+ const total = countResult.recordset[0]?.count ?? 0;
1190
+ if (total === 0) {
1191
+ return {
1192
+ pagination: {
1193
+ total: 0,
1194
+ page,
1195
+ perPage,
1196
+ hasMore: false
1197
+ },
1198
+ spans: []
1199
+ };
1200
+ }
1201
+ const dataRequest = this.pool.request();
1202
+ Object.entries(params).forEach(([key, value]) => {
1203
+ dataRequest.input(key, value);
1204
+ });
1205
+ dataRequest.input("offset", page * perPage);
1206
+ dataRequest.input("limit", perPage);
1207
+ const dataResult = await dataRequest.query(
1208
+ `SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
1209
+ );
1210
+ const spans = dataResult.recordset.map(
1211
+ (row) => transformFromSqlRow({
1212
+ tableName: storage.TABLE_AI_SPANS,
1213
+ sqlRow: row
1214
+ })
1215
+ );
1216
+ return {
1217
+ pagination: {
1218
+ total,
1219
+ page,
1220
+ perPage,
1221
+ hasMore: (page + 1) * perPage < total
1222
+ },
1223
+ spans
1224
+ };
1225
+ } catch (error$1) {
1226
+ throw new error.MastraError(
1227
+ {
1228
+ id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
1229
+ domain: error.ErrorDomain.STORAGE,
1230
+ category: error.ErrorCategory.USER
1231
+ },
1232
+ error$1
1233
+ );
1234
+ }
1235
+ }
1236
+ async batchCreateAISpans(args) {
1237
+ if (!args.records || args.records.length === 0) {
1238
+ return;
1239
+ }
1240
+ try {
1241
+ await this.operations.batchInsert({
1242
+ tableName: storage.TABLE_AI_SPANS,
1243
+ records: args.records.map((span) => ({
1244
+ ...span,
1245
+ startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
1246
+ endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
1247
+ }))
1248
+ });
1249
+ } catch (error$1) {
1250
+ throw new error.MastraError(
1251
+ {
1252
+ id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
1253
+ domain: error.ErrorDomain.STORAGE,
1254
+ category: error.ErrorCategory.USER,
1255
+ details: {
1256
+ count: args.records.length
1257
+ }
1258
+ },
1259
+ error$1
1260
+ );
1261
+ }
1262
+ }
1263
+ async batchUpdateAISpans(args) {
1264
+ if (!args.records || args.records.length === 0) {
1265
+ return;
1266
+ }
1267
+ try {
1268
+ const updates = args.records.map(({ traceId, spanId, updates: data }) => {
1269
+ const processedData = { ...data };
1270
+ if (processedData.endedAt instanceof Date) {
1271
+ processedData.endedAt = processedData.endedAt.toISOString();
1272
+ }
1273
+ if (processedData.startedAt instanceof Date) {
1274
+ processedData.startedAt = processedData.startedAt.toISOString();
1275
+ }
1276
+ return {
1277
+ keys: { spanId, traceId },
1278
+ data: processedData
1279
+ };
1280
+ });
1281
+ await this.operations.batchUpdate({
1282
+ tableName: storage.TABLE_AI_SPANS,
1283
+ updates
1284
+ });
1285
+ } catch (error$1) {
1286
+ throw new error.MastraError(
1287
+ {
1288
+ id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
1289
+ domain: error.ErrorDomain.STORAGE,
1290
+ category: error.ErrorCategory.USER,
1291
+ details: {
1292
+ count: args.records.length
1293
+ }
1294
+ },
1295
+ error$1
1296
+ );
1297
+ }
1298
+ }
1299
+ async batchDeleteAITraces(args) {
1300
+ if (!args.traceIds || args.traceIds.length === 0) {
1301
+ return;
1302
+ }
1303
+ try {
1304
+ const keys = args.traceIds.map((traceId) => ({ traceId }));
1305
+ await this.operations.batchDelete({
1306
+ tableName: storage.TABLE_AI_SPANS,
1307
+ keys
1308
+ });
1309
+ } catch (error$1) {
1310
+ throw new error.MastraError(
1311
+ {
1312
+ id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
1313
+ domain: error.ErrorDomain.STORAGE,
1314
+ category: error.ErrorCategory.USER,
1315
+ details: {
1316
+ count: args.traceIds.length
1317
+ }
1318
+ },
1319
+ error$1
1320
+ );
1321
+ }
1322
+ }
1323
+ };
1069
1324
  var StoreOperationsMSSQL = class extends storage.StoreOperations {
1070
1325
  pool;
1071
1326
  schemaName;
1072
1327
  setupSchemaPromise = null;
1073
1328
  schemaSetupComplete = void 0;
1074
- getSqlType(type, isPrimaryKey = false) {
1329
+ getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
1075
1330
  switch (type) {
1076
1331
  case "text":
1077
- return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(MAX)";
1332
+ if (useLargeStorage) {
1333
+ return "NVARCHAR(MAX)";
1334
+ }
1335
+ return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
1078
1336
  case "timestamp":
1079
1337
  return "DATETIME2(7)";
1080
1338
  case "uuid":
@@ -1087,6 +1345,8 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1087
1345
  return "BIGINT";
1088
1346
  case "float":
1089
1347
  return "FLOAT";
1348
+ case "boolean":
1349
+ return "BIT";
1090
1350
  default:
1091
1351
  throw new error.MastraError({
1092
1352
  id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
@@ -1149,20 +1409,26 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1149
1409
  }
1150
1410
  await this.setupSchemaPromise;
1151
1411
  }
1152
- async insert({ tableName, record }) {
1412
+ async insert({
1413
+ tableName,
1414
+ record,
1415
+ transaction
1416
+ }) {
1153
1417
  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));
1418
+ const columns = Object.keys(record);
1419
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
1420
+ const paramNames = columns.map((_, i) => `@param${i}`);
1421
+ const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
1422
+ const request = transaction ? transaction.request() : this.pool.request();
1423
+ columns.forEach((col, i) => {
1424
+ const value = record[col];
1425
+ const preparedValue = this.prepareValue(value, col, tableName);
1426
+ if (preparedValue instanceof Date) {
1427
+ request.input(`param${i}`, sql2__default.default.DateTime2, preparedValue);
1428
+ } else if (preparedValue === null || preparedValue === void 0) {
1429
+ request.input(`param${i}`, this.getMssqlType(tableName, col), null);
1164
1430
  } else {
1165
- request.input(`param${i}`, value);
1431
+ request.input(`param${i}`, preparedValue);
1166
1432
  }
1167
1433
  });
1168
1434
  await request.query(insertSql);
@@ -1186,7 +1452,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1186
1452
  try {
1187
1453
  await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
1188
1454
  } catch (truncateError) {
1189
- if (truncateError.message && truncateError.message.includes("foreign key")) {
1455
+ if (truncateError?.number === 4712) {
1190
1456
  await this.pool.request().query(`DELETE FROM ${fullTableName}`);
1191
1457
  } else {
1192
1458
  throw truncateError;
@@ -1209,9 +1475,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1209
1475
  getDefaultValue(type) {
1210
1476
  switch (type) {
1211
1477
  case "timestamp":
1212
- return "DEFAULT SYSDATETIMEOFFSET()";
1478
+ return "DEFAULT SYSUTCDATETIME()";
1213
1479
  case "jsonb":
1214
1480
  return "DEFAULT N'{}'";
1481
+ case "boolean":
1482
+ return "DEFAULT 0";
1215
1483
  default:
1216
1484
  return super.getDefaultValue(type);
1217
1485
  }
@@ -1222,13 +1490,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1222
1490
  }) {
1223
1491
  try {
1224
1492
  const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
1493
+ const largeDataColumns = [
1494
+ "workingMemory",
1495
+ "snapshot",
1496
+ "metadata",
1497
+ "content",
1498
+ // messages.content - can be very long conversation content
1499
+ "input",
1500
+ // evals.input - test input data
1501
+ "output",
1502
+ // evals.output - test output data
1503
+ "instructions",
1504
+ // evals.instructions - evaluation instructions
1505
+ "other"
1506
+ // traces.other - additional trace data
1507
+ ];
1225
1508
  const columns = Object.entries(schema).map(([name, def]) => {
1226
1509
  const parsedName = utils.parseSqlIdentifier(name, "column name");
1227
1510
  const constraints = [];
1228
1511
  if (def.primaryKey) constraints.push("PRIMARY KEY");
1229
1512
  if (!def.nullable) constraints.push("NOT NULL");
1230
1513
  const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
1231
- return `[${parsedName}] ${this.getSqlType(def.type, isIndexed)} ${constraints.join(" ")}`.trim();
1514
+ const useLargeStorage = largeDataColumns.includes(name);
1515
+ return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
1232
1516
  }).join(",\n");
1233
1517
  if (this.schemaName) {
1234
1518
  await this.setupSchema();
@@ -1315,7 +1599,19 @@ ${columns}
1315
1599
  const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1316
1600
  if (!columnExists) {
1317
1601
  const columnDef = schema[columnName];
1318
- const sqlType = this.getSqlType(columnDef.type);
1602
+ const largeDataColumns = [
1603
+ "workingMemory",
1604
+ "snapshot",
1605
+ "metadata",
1606
+ "content",
1607
+ "input",
1608
+ "output",
1609
+ "instructions",
1610
+ "other"
1611
+ ];
1612
+ const useLargeStorage = largeDataColumns.includes(columnName);
1613
+ const isIndexed = !!columnDef.primaryKey;
1614
+ const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
1319
1615
  const nullable = columnDef.nullable === false ? "NOT NULL" : "";
1320
1616
  const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
1321
1617
  const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
@@ -1343,13 +1639,17 @@ ${columns}
1343
1639
  try {
1344
1640
  const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
1345
1641
  const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
1346
- const values = keyEntries.map(([_, value]) => value);
1347
- const sql6 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
1642
+ const sql5 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
1348
1643
  const request = this.pool.request();
1349
- values.forEach((value, i) => {
1350
- request.input(`param${i}`, value);
1644
+ keyEntries.forEach(([key, value], i) => {
1645
+ const preparedValue = this.prepareValue(value, key, tableName);
1646
+ if (preparedValue === null || preparedValue === void 0) {
1647
+ request.input(`param${i}`, this.getMssqlType(tableName, key), null);
1648
+ } else {
1649
+ request.input(`param${i}`, preparedValue);
1650
+ }
1351
1651
  });
1352
- const resultSet = await request.query(sql6);
1652
+ const resultSet = await request.query(sql5);
1353
1653
  const result = resultSet.recordset[0] || null;
1354
1654
  if (!result) {
1355
1655
  return null;
@@ -1381,7 +1681,7 @@ ${columns}
1381
1681
  try {
1382
1682
  await transaction.begin();
1383
1683
  for (const record of records) {
1384
- await this.insert({ tableName, record });
1684
+ await this.insert({ tableName, record, transaction });
1385
1685
  }
1386
1686
  await transaction.commit();
1387
1687
  } catch (error$1) {
@@ -1418,26 +1718,562 @@ ${columns}
1418
1718
  );
1419
1719
  }
1420
1720
  }
1421
- };
1422
- function parseJSON(jsonString) {
1423
- try {
1424
- return JSON.parse(jsonString);
1425
- } catch {
1426
- return jsonString;
1721
+ /**
1722
+ * Prepares a value for database operations, handling Date objects and JSON serialization
1723
+ */
1724
+ prepareValue(value, columnName, tableName) {
1725
+ if (value === null || value === void 0) {
1726
+ return value;
1727
+ }
1728
+ if (value instanceof Date) {
1729
+ return value;
1730
+ }
1731
+ const schema = storage.TABLE_SCHEMAS[tableName];
1732
+ const columnSchema = schema?.[columnName];
1733
+ if (columnSchema?.type === "boolean") {
1734
+ return value ? 1 : 0;
1735
+ }
1736
+ if (columnSchema?.type === "jsonb") {
1737
+ return JSON.stringify(value);
1738
+ }
1739
+ if (typeof value === "object") {
1740
+ return JSON.stringify(value);
1741
+ }
1742
+ return value;
1427
1743
  }
1428
- }
1744
+ /**
1745
+ * Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
1746
+ */
1747
+ getMssqlType(tableName, columnName) {
1748
+ const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
1749
+ switch (col?.type) {
1750
+ case "text":
1751
+ return sql2__default.default.NVarChar;
1752
+ case "timestamp":
1753
+ return sql2__default.default.DateTime2;
1754
+ case "uuid":
1755
+ return sql2__default.default.UniqueIdentifier;
1756
+ case "jsonb":
1757
+ return sql2__default.default.NVarChar;
1758
+ case "integer":
1759
+ return sql2__default.default.Int;
1760
+ case "bigint":
1761
+ return sql2__default.default.BigInt;
1762
+ case "float":
1763
+ return sql2__default.default.Float;
1764
+ case "boolean":
1765
+ return sql2__default.default.Bit;
1766
+ default:
1767
+ return sql2__default.default.NVarChar;
1768
+ }
1769
+ }
1770
+ /**
1771
+ * Update a single record in the database
1772
+ */
1773
+ async update({
1774
+ tableName,
1775
+ keys,
1776
+ data,
1777
+ transaction
1778
+ }) {
1779
+ try {
1780
+ if (!data || Object.keys(data).length === 0) {
1781
+ throw new error.MastraError({
1782
+ id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
1783
+ domain: error.ErrorDomain.STORAGE,
1784
+ category: error.ErrorCategory.USER,
1785
+ text: "Cannot update with empty data payload"
1786
+ });
1787
+ }
1788
+ if (!keys || Object.keys(keys).length === 0) {
1789
+ throw new error.MastraError({
1790
+ id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
1791
+ domain: error.ErrorDomain.STORAGE,
1792
+ category: error.ErrorCategory.USER,
1793
+ text: "Cannot update without keys to identify records"
1794
+ });
1795
+ }
1796
+ const setClauses = [];
1797
+ const request = transaction ? transaction.request() : this.pool.request();
1798
+ let paramIndex = 0;
1799
+ Object.entries(data).forEach(([key, value]) => {
1800
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1801
+ const paramName = `set${paramIndex++}`;
1802
+ setClauses.push(`[${parsedKey}] = @${paramName}`);
1803
+ const preparedValue = this.prepareValue(value, key, tableName);
1804
+ if (preparedValue === null || preparedValue === void 0) {
1805
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1806
+ } else {
1807
+ request.input(paramName, preparedValue);
1808
+ }
1809
+ });
1810
+ const whereConditions = [];
1811
+ Object.entries(keys).forEach(([key, value]) => {
1812
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1813
+ const paramName = `where${paramIndex++}`;
1814
+ whereConditions.push(`[${parsedKey}] = @${paramName}`);
1815
+ const preparedValue = this.prepareValue(value, key, tableName);
1816
+ if (preparedValue === null || preparedValue === void 0) {
1817
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1818
+ } else {
1819
+ request.input(paramName, preparedValue);
1820
+ }
1821
+ });
1822
+ const tableName_ = getTableName({
1823
+ indexName: tableName,
1824
+ schemaName: getSchemaName(this.schemaName)
1825
+ });
1826
+ const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
1827
+ await request.query(updateSql);
1828
+ } catch (error$1) {
1829
+ throw new error.MastraError(
1830
+ {
1831
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
1832
+ domain: error.ErrorDomain.STORAGE,
1833
+ category: error.ErrorCategory.THIRD_PARTY,
1834
+ details: {
1835
+ tableName
1836
+ }
1837
+ },
1838
+ error$1
1839
+ );
1840
+ }
1841
+ }
1842
+ /**
1843
+ * Update multiple records in a single batch transaction
1844
+ */
1845
+ async batchUpdate({
1846
+ tableName,
1847
+ updates
1848
+ }) {
1849
+ const transaction = this.pool.transaction();
1850
+ try {
1851
+ await transaction.begin();
1852
+ for (const { keys, data } of updates) {
1853
+ await this.update({ tableName, keys, data, transaction });
1854
+ }
1855
+ await transaction.commit();
1856
+ } catch (error$1) {
1857
+ await transaction.rollback();
1858
+ throw new error.MastraError(
1859
+ {
1860
+ id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
1861
+ domain: error.ErrorDomain.STORAGE,
1862
+ category: error.ErrorCategory.THIRD_PARTY,
1863
+ details: {
1864
+ tableName,
1865
+ numberOfRecords: updates.length
1866
+ }
1867
+ },
1868
+ error$1
1869
+ );
1870
+ }
1871
+ }
1872
+ /**
1873
+ * Delete multiple records by keys
1874
+ */
1875
+ async batchDelete({ tableName, keys }) {
1876
+ if (keys.length === 0) {
1877
+ return;
1878
+ }
1879
+ const tableName_ = getTableName({
1880
+ indexName: tableName,
1881
+ schemaName: getSchemaName(this.schemaName)
1882
+ });
1883
+ const transaction = this.pool.transaction();
1884
+ try {
1885
+ await transaction.begin();
1886
+ for (const keySet of keys) {
1887
+ const conditions = [];
1888
+ const request = transaction.request();
1889
+ let paramIndex = 0;
1890
+ Object.entries(keySet).forEach(([key, value]) => {
1891
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1892
+ const paramName = `p${paramIndex++}`;
1893
+ conditions.push(`[${parsedKey}] = @${paramName}`);
1894
+ const preparedValue = this.prepareValue(value, key, tableName);
1895
+ if (preparedValue === null || preparedValue === void 0) {
1896
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1897
+ } else {
1898
+ request.input(paramName, preparedValue);
1899
+ }
1900
+ });
1901
+ const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
1902
+ await request.query(deleteSql);
1903
+ }
1904
+ await transaction.commit();
1905
+ } catch (error$1) {
1906
+ await transaction.rollback();
1907
+ throw new error.MastraError(
1908
+ {
1909
+ id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
1910
+ domain: error.ErrorDomain.STORAGE,
1911
+ category: error.ErrorCategory.THIRD_PARTY,
1912
+ details: {
1913
+ tableName,
1914
+ numberOfRecords: keys.length
1915
+ }
1916
+ },
1917
+ error$1
1918
+ );
1919
+ }
1920
+ }
1921
+ /**
1922
+ * Create a new index on a table
1923
+ */
1924
+ async createIndex(options) {
1925
+ try {
1926
+ const { name, table, columns, unique = false, where } = options;
1927
+ const schemaName = this.schemaName || "dbo";
1928
+ const fullTableName = getTableName({
1929
+ indexName: table,
1930
+ schemaName: getSchemaName(this.schemaName)
1931
+ });
1932
+ const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
1933
+ const checkRequest = this.pool.request();
1934
+ checkRequest.input("indexName", indexNameSafe);
1935
+ checkRequest.input("schemaName", schemaName);
1936
+ checkRequest.input("tableName", table);
1937
+ const indexExists = await checkRequest.query(`
1938
+ SELECT 1 as found
1939
+ FROM sys.indexes i
1940
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
1941
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
1942
+ WHERE i.name = @indexName
1943
+ AND s.name = @schemaName
1944
+ AND t.name = @tableName
1945
+ `);
1946
+ if (indexExists.recordset && indexExists.recordset.length > 0) {
1947
+ return;
1948
+ }
1949
+ const uniqueStr = unique ? "UNIQUE " : "";
1950
+ const columnsStr = columns.map((col) => {
1951
+ if (col.includes(" DESC") || col.includes(" ASC")) {
1952
+ const [colName, ...modifiers] = col.split(" ");
1953
+ if (!colName) {
1954
+ throw new Error(`Invalid column specification: ${col}`);
1955
+ }
1956
+ return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
1957
+ }
1958
+ return `[${utils.parseSqlIdentifier(col, "column name")}]`;
1959
+ }).join(", ");
1960
+ const whereStr = where ? ` WHERE ${where}` : "";
1961
+ const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
1962
+ await this.pool.request().query(createIndexSql);
1963
+ } catch (error$1) {
1964
+ throw new error.MastraError(
1965
+ {
1966
+ id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
1967
+ domain: error.ErrorDomain.STORAGE,
1968
+ category: error.ErrorCategory.THIRD_PARTY,
1969
+ details: {
1970
+ indexName: options.name,
1971
+ tableName: options.table
1972
+ }
1973
+ },
1974
+ error$1
1975
+ );
1976
+ }
1977
+ }
1978
+ /**
1979
+ * Drop an existing index
1980
+ */
1981
+ async dropIndex(indexName) {
1982
+ try {
1983
+ const schemaName = this.schemaName || "dbo";
1984
+ const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
1985
+ const checkRequest = this.pool.request();
1986
+ checkRequest.input("indexName", indexNameSafe);
1987
+ checkRequest.input("schemaName", schemaName);
1988
+ const result = await checkRequest.query(`
1989
+ SELECT t.name as table_name
1990
+ FROM sys.indexes i
1991
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
1992
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
1993
+ WHERE i.name = @indexName
1994
+ AND s.name = @schemaName
1995
+ `);
1996
+ if (!result.recordset || result.recordset.length === 0) {
1997
+ return;
1998
+ }
1999
+ if (result.recordset.length > 1) {
2000
+ const tables = result.recordset.map((r) => r.table_name).join(", ");
2001
+ throw new error.MastraError({
2002
+ id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
2003
+ domain: error.ErrorDomain.STORAGE,
2004
+ category: error.ErrorCategory.USER,
2005
+ text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
2006
+ });
2007
+ }
2008
+ const tableName = result.recordset[0].table_name;
2009
+ const fullTableName = getTableName({
2010
+ indexName: tableName,
2011
+ schemaName: getSchemaName(this.schemaName)
2012
+ });
2013
+ const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
2014
+ await this.pool.request().query(dropSql);
2015
+ } catch (error$1) {
2016
+ throw new error.MastraError(
2017
+ {
2018
+ id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
2019
+ domain: error.ErrorDomain.STORAGE,
2020
+ category: error.ErrorCategory.THIRD_PARTY,
2021
+ details: {
2022
+ indexName
2023
+ }
2024
+ },
2025
+ error$1
2026
+ );
2027
+ }
2028
+ }
2029
+ /**
2030
+ * List indexes for a specific table or all tables
2031
+ */
2032
+ async listIndexes(tableName) {
2033
+ try {
2034
+ const schemaName = this.schemaName || "dbo";
2035
+ let query;
2036
+ const request = this.pool.request();
2037
+ request.input("schemaName", schemaName);
2038
+ if (tableName) {
2039
+ query = `
2040
+ SELECT
2041
+ i.name as name,
2042
+ o.name as [table],
2043
+ i.is_unique as is_unique,
2044
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2045
+ FROM sys.indexes i
2046
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2047
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2048
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2049
+ WHERE sch.name = @schemaName
2050
+ AND o.name = @tableName
2051
+ AND i.name IS NOT NULL
2052
+ GROUP BY i.name, o.name, i.is_unique
2053
+ `;
2054
+ request.input("tableName", tableName);
2055
+ } else {
2056
+ query = `
2057
+ SELECT
2058
+ i.name as name,
2059
+ o.name as [table],
2060
+ i.is_unique as is_unique,
2061
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2062
+ FROM sys.indexes i
2063
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2064
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2065
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2066
+ WHERE sch.name = @schemaName
2067
+ AND i.name IS NOT NULL
2068
+ GROUP BY i.name, o.name, i.is_unique
2069
+ `;
2070
+ }
2071
+ const result = await request.query(query);
2072
+ const indexes = [];
2073
+ for (const row of result.recordset) {
2074
+ const colRequest = this.pool.request();
2075
+ colRequest.input("indexName", row.name);
2076
+ colRequest.input("schemaName", schemaName);
2077
+ const colResult = await colRequest.query(`
2078
+ SELECT c.name as column_name
2079
+ FROM sys.indexes i
2080
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2081
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2082
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2083
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2084
+ WHERE i.name = @indexName
2085
+ AND s.name = @schemaName
2086
+ ORDER BY ic.key_ordinal
2087
+ `);
2088
+ indexes.push({
2089
+ name: row.name,
2090
+ table: row.table,
2091
+ columns: colResult.recordset.map((c) => c.column_name),
2092
+ unique: row.is_unique || false,
2093
+ size: row.size || "0 MB",
2094
+ definition: ""
2095
+ // MSSQL doesn't store definition like PG
2096
+ });
2097
+ }
2098
+ return indexes;
2099
+ } catch (error$1) {
2100
+ throw new error.MastraError(
2101
+ {
2102
+ id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
2103
+ domain: error.ErrorDomain.STORAGE,
2104
+ category: error.ErrorCategory.THIRD_PARTY,
2105
+ details: tableName ? {
2106
+ tableName
2107
+ } : {}
2108
+ },
2109
+ error$1
2110
+ );
2111
+ }
2112
+ }
2113
+ /**
2114
+ * Get detailed statistics for a specific index
2115
+ */
2116
+ async describeIndex(indexName) {
2117
+ try {
2118
+ const schemaName = this.schemaName || "dbo";
2119
+ const request = this.pool.request();
2120
+ request.input("indexName", indexName);
2121
+ request.input("schemaName", schemaName);
2122
+ const query = `
2123
+ SELECT
2124
+ i.name as name,
2125
+ o.name as [table],
2126
+ i.is_unique as is_unique,
2127
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
2128
+ i.type_desc as method,
2129
+ ISNULL(us.user_scans, 0) as scans,
2130
+ ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
2131
+ ISNULL(us.user_lookups, 0) as tuples_fetched
2132
+ FROM sys.indexes i
2133
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2134
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2135
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2136
+ LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
2137
+ WHERE i.name = @indexName
2138
+ AND sch.name = @schemaName
2139
+ GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
2140
+ `;
2141
+ const result = await request.query(query);
2142
+ if (!result.recordset || result.recordset.length === 0) {
2143
+ throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
2144
+ }
2145
+ const row = result.recordset[0];
2146
+ const colRequest = this.pool.request();
2147
+ colRequest.input("indexName", indexName);
2148
+ colRequest.input("schemaName", schemaName);
2149
+ const colResult = await colRequest.query(`
2150
+ SELECT c.name as column_name
2151
+ FROM sys.indexes i
2152
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2153
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2154
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2155
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2156
+ WHERE i.name = @indexName
2157
+ AND s.name = @schemaName
2158
+ ORDER BY ic.key_ordinal
2159
+ `);
2160
+ return {
2161
+ name: row.name,
2162
+ table: row.table,
2163
+ columns: colResult.recordset.map((c) => c.column_name),
2164
+ unique: row.is_unique || false,
2165
+ size: row.size || "0 MB",
2166
+ definition: "",
2167
+ method: row.method?.toLowerCase() || "nonclustered",
2168
+ scans: Number(row.scans) || 0,
2169
+ tuples_read: Number(row.tuples_read) || 0,
2170
+ tuples_fetched: Number(row.tuples_fetched) || 0
2171
+ };
2172
+ } catch (error$1) {
2173
+ throw new error.MastraError(
2174
+ {
2175
+ id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
2176
+ domain: error.ErrorDomain.STORAGE,
2177
+ category: error.ErrorCategory.THIRD_PARTY,
2178
+ details: {
2179
+ indexName
2180
+ }
2181
+ },
2182
+ error$1
2183
+ );
2184
+ }
2185
+ }
2186
+ /**
2187
+ * Returns definitions for automatic performance indexes
2188
+ * IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
2189
+ * NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
2190
+ */
2191
+ getAutomaticIndexDefinitions() {
2192
+ const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
2193
+ return [
2194
+ // Composite indexes for optimal filtering + sorting performance
2195
+ // NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
2196
+ {
2197
+ name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
2198
+ table: storage.TABLE_THREADS,
2199
+ columns: ["resourceId", "seq_id DESC"]
2200
+ },
2201
+ {
2202
+ name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
2203
+ table: storage.TABLE_MESSAGES,
2204
+ columns: ["thread_id", "seq_id DESC"]
2205
+ },
2206
+ {
2207
+ name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
2208
+ table: storage.TABLE_TRACES,
2209
+ columns: ["name", "seq_id DESC"]
2210
+ },
2211
+ {
2212
+ name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
2213
+ table: storage.TABLE_SCORERS,
2214
+ columns: ["traceId", "spanId", "seq_id DESC"]
2215
+ },
2216
+ // AI Spans indexes for optimal trace querying
2217
+ {
2218
+ name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
2219
+ table: storage.TABLE_AI_SPANS,
2220
+ columns: ["traceId", "startedAt DESC"]
2221
+ },
2222
+ {
2223
+ name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
2224
+ table: storage.TABLE_AI_SPANS,
2225
+ columns: ["parentSpanId", "startedAt DESC"]
2226
+ },
2227
+ {
2228
+ name: `${schemaPrefix}mastra_ai_spans_name_idx`,
2229
+ table: storage.TABLE_AI_SPANS,
2230
+ columns: ["name"]
2231
+ },
2232
+ {
2233
+ name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
2234
+ table: storage.TABLE_AI_SPANS,
2235
+ columns: ["spanType", "startedAt DESC"]
2236
+ }
2237
+ ];
2238
+ }
2239
+ /**
2240
+ * Creates automatic indexes for optimal query performance
2241
+ * Uses getAutomaticIndexDefinitions() to determine which indexes to create
2242
+ */
2243
+ async createAutomaticIndexes() {
2244
+ try {
2245
+ const indexes = this.getAutomaticIndexDefinitions();
2246
+ for (const indexOptions of indexes) {
2247
+ try {
2248
+ await this.createIndex(indexOptions);
2249
+ } catch (error) {
2250
+ this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
2251
+ }
2252
+ }
2253
+ } catch (error$1) {
2254
+ throw new error.MastraError(
2255
+ {
2256
+ id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
2257
+ domain: error.ErrorDomain.STORAGE,
2258
+ category: error.ErrorCategory.THIRD_PARTY
2259
+ },
2260
+ error$1
2261
+ );
2262
+ }
2263
+ }
2264
+ };
1429
2265
  function transformScoreRow(row) {
1430
2266
  return {
1431
2267
  ...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),
2268
+ input: storage.safelyParseJSON(row.input),
2269
+ scorer: storage.safelyParseJSON(row.scorer),
2270
+ preprocessStepResult: storage.safelyParseJSON(row.preprocessStepResult),
2271
+ analyzeStepResult: storage.safelyParseJSON(row.analyzeStepResult),
2272
+ metadata: storage.safelyParseJSON(row.metadata),
2273
+ output: storage.safelyParseJSON(row.output),
2274
+ additionalContext: storage.safelyParseJSON(row.additionalContext),
2275
+ requestContext: storage.safelyParseJSON(row.requestContext),
2276
+ entity: storage.safelyParseJSON(row.entity),
1441
2277
  createdAt: row.createdAt,
1442
2278
  updatedAt: row.updatedAt
1443
2279
  };
@@ -1503,7 +2339,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1503
2339
  input,
1504
2340
  output,
1505
2341
  additionalContext,
1506
- runtimeContext,
2342
+ requestContext,
1507
2343
  entity,
1508
2344
  ...rest
1509
2345
  } = validatedScore;
@@ -1512,15 +2348,15 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1512
2348
  record: {
1513
2349
  id: scoreId,
1514
2350
  ...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,
2351
+ input: input || "",
2352
+ output: output || "",
2353
+ preprocessStepResult: preprocessStepResult || null,
2354
+ analyzeStepResult: analyzeStepResult || null,
2355
+ metadata: metadata || null,
2356
+ additionalContext: additionalContext || null,
2357
+ requestContext: requestContext || null,
2358
+ entity: entity || null,
2359
+ scorer: scorer || null,
1524
2360
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1525
2361
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1526
2362
  }
@@ -1540,14 +2376,37 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1540
2376
  }
1541
2377
  async getScoresByScorerId({
1542
2378
  scorerId,
1543
- pagination
2379
+ pagination,
2380
+ entityId,
2381
+ entityType,
2382
+ source
1544
2383
  }) {
1545
2384
  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
- );
2385
+ const conditions = ["[scorerId] = @p1"];
2386
+ const params = { p1: scorerId };
2387
+ let paramIndex = 2;
2388
+ if (entityId) {
2389
+ conditions.push(`[entityId] = @p${paramIndex}`);
2390
+ params[`p${paramIndex}`] = entityId;
2391
+ paramIndex++;
2392
+ }
2393
+ if (entityType) {
2394
+ conditions.push(`[entityType] = @p${paramIndex}`);
2395
+ params[`p${paramIndex}`] = entityType;
2396
+ paramIndex++;
2397
+ }
2398
+ if (source) {
2399
+ conditions.push(`[source] = @p${paramIndex}`);
2400
+ params[`p${paramIndex}`] = source;
2401
+ paramIndex++;
2402
+ }
2403
+ const whereClause = conditions.join(" AND ");
2404
+ const tableName = getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
2405
+ const countRequest = this.pool.request();
2406
+ Object.entries(params).forEach(([key, value]) => {
2407
+ countRequest.input(key, value);
2408
+ });
2409
+ const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
1551
2410
  const total = totalResult.recordset[0]?.count || 0;
1552
2411
  if (total === 0) {
1553
2412
  return {
@@ -1561,12 +2420,13 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1561
2420
  };
1562
2421
  }
1563
2422
  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
- );
2423
+ Object.entries(params).forEach(([key, value]) => {
2424
+ dataRequest.input(key, value);
2425
+ });
2426
+ dataRequest.input("perPage", pagination.perPage);
2427
+ dataRequest.input("offset", pagination.page * pagination.perPage);
2428
+ const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
2429
+ const result = await dataRequest.query(dataQuery);
1570
2430
  return {
1571
2431
  pagination: {
1572
2432
  total: Number(total),
@@ -1746,24 +2606,6 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1746
2606
  }
1747
2607
  }
1748
2608
  };
1749
- function parseWorkflowRun(row) {
1750
- let parsedSnapshot = row.snapshot;
1751
- if (typeof parsedSnapshot === "string") {
1752
- try {
1753
- parsedSnapshot = JSON.parse(row.snapshot);
1754
- } catch (e) {
1755
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1756
- }
1757
- }
1758
- return {
1759
- workflowName: row.workflow_name,
1760
- runId: row.run_id,
1761
- snapshot: parsedSnapshot,
1762
- createdAt: row.createdAt,
1763
- updatedAt: row.updatedAt,
1764
- resourceId: row.resourceId
1765
- };
1766
- }
1767
2609
  var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1768
2610
  pool;
1769
2611
  operations;
@@ -1778,21 +2620,163 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1778
2620
  this.operations = operations;
1779
2621
  this.schema = schema;
1780
2622
  }
1781
- updateWorkflowResults({
1782
- // workflowName,
1783
- // runId,
1784
- // stepId,
1785
- // result,
1786
- // runtimeContext,
2623
+ parseWorkflowRun(row) {
2624
+ let parsedSnapshot = row.snapshot;
2625
+ if (typeof parsedSnapshot === "string") {
2626
+ try {
2627
+ parsedSnapshot = JSON.parse(row.snapshot);
2628
+ } catch (e) {
2629
+ this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
2630
+ }
2631
+ }
2632
+ return {
2633
+ workflowName: row.workflow_name,
2634
+ runId: row.run_id,
2635
+ snapshot: parsedSnapshot,
2636
+ createdAt: row.createdAt,
2637
+ updatedAt: row.updatedAt,
2638
+ resourceId: row.resourceId
2639
+ };
2640
+ }
2641
+ async updateWorkflowResults({
2642
+ workflowName,
2643
+ runId,
2644
+ stepId,
2645
+ result,
2646
+ requestContext
1787
2647
  }) {
1788
- throw new Error("Method not implemented.");
2648
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2649
+ const transaction = this.pool.transaction();
2650
+ try {
2651
+ await transaction.begin();
2652
+ const selectRequest = new sql2__default.default.Request(transaction);
2653
+ selectRequest.input("workflow_name", workflowName);
2654
+ selectRequest.input("run_id", runId);
2655
+ const existingSnapshotResult = await selectRequest.query(
2656
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
2657
+ );
2658
+ let snapshot;
2659
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
2660
+ snapshot = {
2661
+ context: {},
2662
+ activePaths: [],
2663
+ timestamp: Date.now(),
2664
+ suspendedPaths: {},
2665
+ resumeLabels: {},
2666
+ serializedStepGraph: [],
2667
+ value: {},
2668
+ waitingPaths: {},
2669
+ status: "pending",
2670
+ runId,
2671
+ requestContext: {}
2672
+ };
2673
+ } else {
2674
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
2675
+ snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2676
+ }
2677
+ snapshot.context[stepId] = result;
2678
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
2679
+ const upsertReq = new sql2__default.default.Request(transaction);
2680
+ upsertReq.input("workflow_name", workflowName);
2681
+ upsertReq.input("run_id", runId);
2682
+ upsertReq.input("snapshot", JSON.stringify(snapshot));
2683
+ upsertReq.input("createdAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
2684
+ upsertReq.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
2685
+ await upsertReq.query(
2686
+ `MERGE ${table} AS target
2687
+ USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
2688
+ ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
2689
+ WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
2690
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
2691
+ VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
2692
+ );
2693
+ await transaction.commit();
2694
+ return snapshot.context;
2695
+ } catch (error$1) {
2696
+ try {
2697
+ await transaction.rollback();
2698
+ } catch {
2699
+ }
2700
+ throw new error.MastraError(
2701
+ {
2702
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
2703
+ domain: error.ErrorDomain.STORAGE,
2704
+ category: error.ErrorCategory.THIRD_PARTY,
2705
+ details: {
2706
+ workflowName,
2707
+ runId,
2708
+ stepId
2709
+ }
2710
+ },
2711
+ error$1
2712
+ );
2713
+ }
1789
2714
  }
1790
- updateWorkflowState({
1791
- // workflowName,
1792
- // runId,
1793
- // opts,
2715
+ async updateWorkflowState({
2716
+ workflowName,
2717
+ runId,
2718
+ opts
1794
2719
  }) {
1795
- throw new Error("Method not implemented.");
2720
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2721
+ const transaction = this.pool.transaction();
2722
+ try {
2723
+ await transaction.begin();
2724
+ const selectRequest = new sql2__default.default.Request(transaction);
2725
+ selectRequest.input("workflow_name", workflowName);
2726
+ selectRequest.input("run_id", runId);
2727
+ const existingSnapshotResult = await selectRequest.query(
2728
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
2729
+ );
2730
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
2731
+ await transaction.rollback();
2732
+ return void 0;
2733
+ }
2734
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
2735
+ const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2736
+ if (!snapshot || !snapshot?.context) {
2737
+ await transaction.rollback();
2738
+ throw new error.MastraError(
2739
+ {
2740
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
2741
+ domain: error.ErrorDomain.STORAGE,
2742
+ category: error.ErrorCategory.SYSTEM,
2743
+ details: {
2744
+ workflowName,
2745
+ runId
2746
+ }
2747
+ },
2748
+ new Error(`Snapshot not found for runId ${runId}`)
2749
+ );
2750
+ }
2751
+ const updatedSnapshot = { ...snapshot, ...opts };
2752
+ const updateRequest = new sql2__default.default.Request(transaction);
2753
+ updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
2754
+ updateRequest.input("workflow_name", workflowName);
2755
+ updateRequest.input("run_id", runId);
2756
+ updateRequest.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
2757
+ await updateRequest.query(
2758
+ `UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
2759
+ );
2760
+ await transaction.commit();
2761
+ return updatedSnapshot;
2762
+ } catch (error$1) {
2763
+ try {
2764
+ await transaction.rollback();
2765
+ } catch {
2766
+ }
2767
+ throw new error.MastraError(
2768
+ {
2769
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
2770
+ domain: error.ErrorDomain.STORAGE,
2771
+ category: error.ErrorCategory.THIRD_PARTY,
2772
+ details: {
2773
+ workflowName,
2774
+ runId
2775
+ }
2776
+ },
2777
+ error$1
2778
+ );
2779
+ }
1796
2780
  }
1797
2781
  async persistWorkflowSnapshot({
1798
2782
  workflowName,
@@ -1890,7 +2874,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1890
2874
  if (!result.recordset || result.recordset.length === 0) {
1891
2875
  return null;
1892
2876
  }
1893
- return parseWorkflowRun(result.recordset[0]);
2877
+ return this.parseWorkflowRun(result.recordset[0]);
1894
2878
  } catch (error$1) {
1895
2879
  throw new error.MastraError(
1896
2880
  {
@@ -1927,7 +2911,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1927
2911
  conditions.push(`[resourceId] = @resourceId`);
1928
2912
  paramMap["resourceId"] = resourceId;
1929
2913
  } else {
1930
- console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
2914
+ this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
1931
2915
  }
1932
2916
  }
1933
2917
  if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
@@ -1961,7 +2945,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1961
2945
  request.input("offset", offset);
1962
2946
  }
1963
2947
  const result = await request.query(query);
1964
- const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
2948
+ const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
1965
2949
  return { runs, total: total || runs.length };
1966
2950
  } catch (error$1) {
1967
2951
  throw new error.MastraError(
@@ -1977,6 +2961,9 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1977
2961
  );
1978
2962
  }
1979
2963
  }
2964
+ async listWorkflowRuns(args) {
2965
+ return this.getWorkflowRuns(args);
2966
+ }
1980
2967
  };
1981
2968
 
1982
2969
  // src/storage/index.ts
@@ -2009,17 +2996,17 @@ var MSSQLStore = class extends storage.MastraStorage {
2009
2996
  port: config.port,
2010
2997
  options: config.options || { encrypt: true, trustServerCertificate: true }
2011
2998
  });
2012
- const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
2013
2999
  const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
2014
3000
  const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
2015
3001
  const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
2016
3002
  const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
3003
+ const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
2017
3004
  this.stores = {
2018
3005
  operations,
2019
3006
  scores,
2020
3007
  workflows,
2021
- legacyEvals,
2022
- memory
3008
+ memory,
3009
+ observability
2023
3010
  };
2024
3011
  } catch (e) {
2025
3012
  throw new error.MastraError(
@@ -2039,6 +3026,11 @@ var MSSQLStore = class extends storage.MastraStorage {
2039
3026
  try {
2040
3027
  await this.isConnected;
2041
3028
  await super.init();
3029
+ try {
3030
+ await this.stores.operations.createAutomaticIndexes();
3031
+ } catch (indexError) {
3032
+ this.logger?.warn?.("Failed to create indexes:", indexError);
3033
+ }
2042
3034
  } catch (error$1) {
2043
3035
  this.isConnected = null;
2044
3036
  throw new error.MastraError(
@@ -2066,16 +3058,11 @@ var MSSQLStore = class extends storage.MastraStorage {
2066
3058
  hasColumn: true,
2067
3059
  createTable: true,
2068
3060
  deleteMessages: true,
2069
- getScoresBySpan: true
3061
+ getScoresBySpan: true,
3062
+ aiTracing: true,
3063
+ indexManagement: true
2070
3064
  };
2071
3065
  }
2072
- /** @deprecated use getEvals instead */
2073
- async getEvalsByAgentName(agentName, type) {
2074
- return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2075
- }
2076
- async getEvals(options = {}) {
2077
- return this.stores.legacyEvals.getEvals(options);
2078
- }
2079
3066
  async createTable({
2080
3067
  tableName,
2081
3068
  schema
@@ -2176,9 +3163,9 @@ var MSSQLStore = class extends storage.MastraStorage {
2176
3163
  runId,
2177
3164
  stepId,
2178
3165
  result,
2179
- runtimeContext
3166
+ requestContext
2180
3167
  }) {
2181
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
3168
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2182
3169
  }
2183
3170
  async updateWorkflowState({
2184
3171
  workflowName,
@@ -2220,6 +3207,60 @@ var MSSQLStore = class extends storage.MastraStorage {
2220
3207
  async close() {
2221
3208
  await this.pool.close();
2222
3209
  }
3210
+ /**
3211
+ * Index Management
3212
+ */
3213
+ async createIndex(options) {
3214
+ return this.stores.operations.createIndex(options);
3215
+ }
3216
+ async listIndexes(tableName) {
3217
+ return this.stores.operations.listIndexes(tableName);
3218
+ }
3219
+ async describeIndex(indexName) {
3220
+ return this.stores.operations.describeIndex(indexName);
3221
+ }
3222
+ async dropIndex(indexName) {
3223
+ return this.stores.operations.dropIndex(indexName);
3224
+ }
3225
+ /**
3226
+ * AI Tracing / Observability
3227
+ */
3228
+ getObservabilityStore() {
3229
+ if (!this.stores.observability) {
3230
+ throw new error.MastraError({
3231
+ id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
3232
+ domain: error.ErrorDomain.STORAGE,
3233
+ category: error.ErrorCategory.SYSTEM,
3234
+ text: "Observability storage is not initialized"
3235
+ });
3236
+ }
3237
+ return this.stores.observability;
3238
+ }
3239
+ async createAISpan(span) {
3240
+ return this.getObservabilityStore().createAISpan(span);
3241
+ }
3242
+ async updateAISpan({
3243
+ spanId,
3244
+ traceId,
3245
+ updates
3246
+ }) {
3247
+ return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
3248
+ }
3249
+ async getAITrace(traceId) {
3250
+ return this.getObservabilityStore().getAITrace(traceId);
3251
+ }
3252
+ async getAITracesPaginated(args) {
3253
+ return this.getObservabilityStore().getAITracesPaginated(args);
3254
+ }
3255
+ async batchCreateAISpans(args) {
3256
+ return this.getObservabilityStore().batchCreateAISpans(args);
3257
+ }
3258
+ async batchUpdateAISpans(args) {
3259
+ return this.getObservabilityStore().batchUpdateAISpans(args);
3260
+ }
3261
+ async batchDeleteAITraces(args) {
3262
+ return this.getObservabilityStore().batchDeleteAITraces(args);
3263
+ }
2223
3264
  /**
2224
3265
  * Scorers
2225
3266
  */
@@ -2228,9 +3269,18 @@ var MSSQLStore = class extends storage.MastraStorage {
2228
3269
  }
2229
3270
  async getScoresByScorerId({
2230
3271
  scorerId: _scorerId,
2231
- pagination: _pagination
3272
+ pagination: _pagination,
3273
+ entityId: _entityId,
3274
+ entityType: _entityType,
3275
+ source: _source
2232
3276
  }) {
2233
- return this.stores.scores.getScoresByScorerId({ scorerId: _scorerId, pagination: _pagination });
3277
+ return this.stores.scores.getScoresByScorerId({
3278
+ scorerId: _scorerId,
3279
+ pagination: _pagination,
3280
+ entityId: _entityId,
3281
+ entityType: _entityType,
3282
+ source: _source
3283
+ });
2234
3284
  }
2235
3285
  async saveScore(_score) {
2236
3286
  return this.stores.scores.saveScore(_score);