@mastra/mssql 0.0.0-feat-support-ai-sdk-5-again-20250813225910 → 0.0.0-feat-add-query-option-to-playground-20251209160219

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +1004 -3
  2. package/README.md +324 -37
  3. package/dist/index.cjs +1847 -756
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1848 -757
  8. package/dist/index.js.map +1 -1
  9. package/dist/storage/domains/memory/index.d.ts +15 -36
  10. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  11. package/dist/storage/domains/observability/index.d.ts +44 -0
  12. package/dist/storage/domains/observability/index.d.ts.map +1 -0
  13. package/dist/storage/domains/operations/index.d.ts +67 -4
  14. package/dist/storage/domains/operations/index.d.ts.map +1 -1
  15. package/dist/storage/domains/scores/index.d.ts +15 -6
  16. package/dist/storage/domains/scores/index.d.ts.map +1 -1
  17. package/dist/storage/domains/utils.d.ts +19 -0
  18. package/dist/storage/domains/utils.d.ts.map +1 -1
  19. package/dist/storage/domains/workflows/index.d.ts +28 -10
  20. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  21. package/dist/storage/index.d.ts +116 -74
  22. package/dist/storage/index.d.ts.map +1 -1
  23. package/package.json +30 -12
  24. package/dist/storage/domains/legacy-evals/index.d.ts +0 -20
  25. package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
  26. package/dist/storage/domains/traces/index.d.ts +0 -37
  27. package/dist/storage/domains/traces/index.d.ts.map +0 -1
  28. package/docker-compose.yaml +0 -14
  29. package/eslint.config.js +0 -6
  30. package/src/index.ts +0 -2
  31. package/src/storage/domains/legacy-evals/index.ts +0 -175
  32. package/src/storage/domains/memory/index.ts +0 -1024
  33. package/src/storage/domains/operations/index.ts +0 -401
  34. package/src/storage/domains/scores/index.ts +0 -316
  35. package/src/storage/domains/traces/index.ts +0 -212
  36. package/src/storage/domains/utils.ts +0 -12
  37. package/src/storage/domains/workflows/index.ts +0 -259
  38. package/src/storage/index.test.ts +0 -2228
  39. package/src/storage/index.ts +0 -448
  40. package/tsconfig.build.json +0 -9
  41. package/tsconfig.json +0 -5
  42. package/tsup.config.ts +0 -17
  43. package/vitest.config.ts +0 -12
package/dist/index.cjs CHANGED
@@ -2,13 +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');
6
- var utils = require('@mastra/core/utils');
5
+ var sql3 = require('mssql');
7
6
  var agent = require('@mastra/core/agent');
7
+ var utils = require('@mastra/core/utils');
8
+ var crypto = require('crypto');
9
+ var evals = require('@mastra/core/evals');
8
10
 
9
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
12
 
11
- var sql2__default = /*#__PURE__*/_interopDefault(sql2);
13
+ var sql3__default = /*#__PURE__*/_interopDefault(sql3);
12
14
 
13
15
  // src/storage/index.ts
14
16
  function getSchemaName(schema) {
@@ -20,154 +22,109 @@ function getTableName({ indexName, schemaName }) {
20
22
  const quotedSchemaName = schemaName;
21
23
  return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
22
24
  }
23
-
24
- // src/storage/domains/legacy-evals/index.ts
25
- function transformEvalRow(row) {
26
- let testInfoValue = null, resultValue = null;
27
- if (row.test_info) {
28
- try {
29
- testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
30
- } catch {
31
- }
25
+ function buildDateRangeFilter(dateRange, fieldName) {
26
+ const filters = {};
27
+ if (dateRange?.start) {
28
+ filters[`${fieldName}_gte`] = dateRange.start;
32
29
  }
33
- if (row.test_info) {
34
- try {
35
- resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
36
- } catch {
37
- }
30
+ if (dateRange?.end) {
31
+ filters[`${fieldName}_lte`] = dateRange.end;
38
32
  }
39
- return {
40
- agentName: row.agent_name,
41
- input: row.input,
42
- output: row.output,
43
- result: resultValue,
44
- metricName: row.metric_name,
45
- instructions: row.instructions,
46
- testInfo: testInfoValue,
47
- globalRunId: row.global_run_id,
48
- runId: row.run_id,
49
- createdAt: row.created_at
50
- };
33
+ return filters;
51
34
  }
52
- var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
53
- pool;
54
- schema;
55
- constructor({ pool, schema }) {
56
- super();
57
- this.pool = pool;
58
- this.schema = schema;
59
- }
60
- /** @deprecated use getEvals instead */
61
- async getEvalsByAgentName(agentName, type) {
62
- try {
63
- let query = `SELECT * FROM ${getTableName({ indexName: storage.TABLE_EVALS, schemaName: getSchemaName(this.schema) })} WHERE agent_name = @p1`;
64
- if (type === "test") {
65
- query += " AND test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL";
66
- } else if (type === "live") {
67
- query += " AND (test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)";
68
- }
69
- query += " ORDER BY created_at DESC";
70
- const request = this.pool.request();
71
- request.input("p1", agentName);
72
- const result = await request.query(query);
73
- const rows = result.recordset;
74
- return typeof transformEvalRow === "function" ? rows?.map((row) => transformEvalRow(row)) ?? [] : rows ?? [];
75
- } catch (error) {
76
- if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
77
- return [];
78
- }
79
- console.error("Failed to get evals for the specified agent: " + error?.message);
80
- throw error;
81
- }
82
- }
83
- async getEvals(options = {}) {
84
- const { agentName, type, page = 0, perPage = 100, dateRange } = options;
85
- const fromDate = dateRange?.start;
86
- const toDate = dateRange?.end;
87
- const where = [];
88
- const params = {};
89
- if (agentName) {
90
- where.push("agent_name = @agentName");
91
- params["agentName"] = agentName;
92
- }
93
- if (type === "test") {
94
- where.push("test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL");
95
- } else if (type === "live") {
96
- where.push("(test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)");
97
- }
98
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
99
- where.push(`[created_at] >= @fromDate`);
100
- params[`fromDate`] = fromDate.toISOString();
101
- }
102
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
103
- where.push(`[created_at] <= @toDate`);
104
- params[`toDate`] = toDate.toISOString();
105
- }
106
- const whereClause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
107
- const tableName = getTableName({ indexName: storage.TABLE_EVALS, schemaName: getSchemaName(this.schema) });
108
- const offset = page * perPage;
109
- const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
110
- const dataQuery = `SELECT * FROM ${tableName} ${whereClause} ORDER BY seq_id DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
111
- try {
112
- const countReq = this.pool.request();
113
- Object.entries(params).forEach(([key, value]) => {
114
- if (value instanceof Date) {
115
- countReq.input(key, sql2__default.default.DateTime, value);
116
- } else {
117
- countReq.input(key, value);
35
+ function isInOperator(value) {
36
+ return typeof value === "object" && value !== null && "$in" in value && Array.isArray(value.$in);
37
+ }
38
+ function prepareWhereClause(filters, _schema) {
39
+ const conditions = [];
40
+ const params = {};
41
+ let paramIndex = 1;
42
+ Object.entries(filters).forEach(([key, value]) => {
43
+ if (value === void 0) return;
44
+ if (key.endsWith("_gte")) {
45
+ const paramName = `p${paramIndex++}`;
46
+ const fieldName = key.slice(0, -4);
47
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
48
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
49
+ } else if (key.endsWith("_lte")) {
50
+ const paramName = `p${paramIndex++}`;
51
+ const fieldName = key.slice(0, -4);
52
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
53
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
54
+ } else if (value === null) {
55
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
56
+ } else if (isInOperator(value)) {
57
+ const inValues = value.$in;
58
+ if (inValues.length === 0) {
59
+ conditions.push("1 = 0");
60
+ } else if (inValues.length === 1) {
61
+ const paramName = `p${paramIndex++}`;
62
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
63
+ params[paramName] = inValues[0] instanceof Date ? inValues[0].toISOString() : inValues[0];
64
+ } else {
65
+ const inParamNames = [];
66
+ for (const item of inValues) {
67
+ const paramName = `p${paramIndex++}`;
68
+ inParamNames.push(`@${paramName}`);
69
+ params[paramName] = item instanceof Date ? item.toISOString() : item;
118
70
  }
119
- });
120
- const countResult = await countReq.query(countQuery);
121
- const total = countResult.recordset[0]?.total || 0;
122
- if (total === 0) {
123
- return {
124
- evals: [],
125
- total: 0,
126
- page,
127
- perPage,
128
- hasMore: false
129
- };
71
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IN (${inParamNames.join(", ")})`);
130
72
  }
131
- const req = this.pool.request();
132
- Object.entries(params).forEach(([key, value]) => {
133
- if (value instanceof Date) {
134
- req.input(key, sql2__default.default.DateTime, value);
135
- } else {
136
- req.input(key, value);
73
+ } else if (Array.isArray(value)) {
74
+ if (value.length === 0) {
75
+ conditions.push("1 = 0");
76
+ } else if (value.length === 1) {
77
+ const paramName = `p${paramIndex++}`;
78
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
79
+ params[paramName] = value[0] instanceof Date ? value[0].toISOString() : value[0];
80
+ } else {
81
+ const inParamNames = [];
82
+ for (const item of value) {
83
+ const paramName = `p${paramIndex++}`;
84
+ inParamNames.push(`@${paramName}`);
85
+ params[paramName] = item instanceof Date ? item.toISOString() : item;
137
86
  }
138
- });
139
- req.input("offset", offset);
140
- req.input("perPage", perPage);
141
- const result = await req.query(dataQuery);
142
- const rows = result.recordset;
143
- return {
144
- evals: rows?.map((row) => transformEvalRow(row)) ?? [],
145
- total,
146
- page,
147
- perPage,
148
- hasMore: offset + (rows?.length ?? 0) < total
149
- };
150
- } catch (error$1) {
151
- const mastraError = new error.MastraError(
152
- {
153
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_EVALS_FAILED",
154
- domain: error.ErrorDomain.STORAGE,
155
- category: error.ErrorCategory.THIRD_PARTY,
156
- details: {
157
- agentName: agentName || "all",
158
- type: type || "all",
159
- page,
160
- perPage
161
- }
162
- },
163
- error$1
164
- );
165
- this.logger?.error?.(mastraError.toString());
166
- this.logger?.trackException(mastraError);
167
- throw mastraError;
87
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IN (${inParamNames.join(", ")})`);
88
+ }
89
+ } else {
90
+ const paramName = `p${paramIndex++}`;
91
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
92
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
168
93
  }
169
- }
170
- };
94
+ });
95
+ return {
96
+ sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
97
+ params
98
+ };
99
+ }
100
+ function transformFromSqlRow({
101
+ tableName,
102
+ sqlRow
103
+ }) {
104
+ const schema = storage.TABLE_SCHEMAS[tableName];
105
+ const result = {};
106
+ Object.entries(sqlRow).forEach(([key, value]) => {
107
+ const columnSchema = schema?.[key];
108
+ if (columnSchema?.type === "jsonb" && typeof value === "string") {
109
+ try {
110
+ result[key] = JSON.parse(value);
111
+ } catch {
112
+ result[key] = value;
113
+ }
114
+ } else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
115
+ result[key] = new Date(value);
116
+ } else if (columnSchema?.type === "timestamp" && value instanceof Date) {
117
+ result[key] = value;
118
+ } else if (columnSchema?.type === "boolean") {
119
+ result[key] = Boolean(value);
120
+ } else {
121
+ result[key] = value;
122
+ }
123
+ });
124
+ return result;
125
+ }
126
+
127
+ // src/storage/domains/memory/index.ts
171
128
  var MemoryMSSQL = class extends storage.MemoryStorage {
172
129
  pool;
173
130
  schema;
@@ -185,7 +142,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
185
142
  });
186
143
  const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
187
144
  const list = new agent.MessageList().add(cleanMessages, "memory");
188
- return format === "v2" ? list.get.all.v2() : list.get.all.v1();
145
+ return format === "v2" ? list.get.all.db() : list.get.all.v1();
189
146
  }
190
147
  constructor({
191
148
  pool,
@@ -199,7 +156,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
199
156
  }
200
157
  async getThreadById({ threadId }) {
201
158
  try {
202
- const sql7 = `SELECT
159
+ const sql5 = `SELECT
203
160
  id,
204
161
  [resourceId],
205
162
  title,
@@ -210,7 +167,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
210
167
  WHERE id = @threadId`;
211
168
  const request = this.pool.request();
212
169
  request.input("threadId", threadId);
213
- const resultSet = await request.query(sql7);
170
+ const resultSet = await request.query(sql5);
214
171
  const thread = resultSet.recordset[0] || null;
215
172
  if (!thread) {
216
173
  return null;
@@ -224,7 +181,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
224
181
  } catch (error$1) {
225
182
  throw new error.MastraError(
226
183
  {
227
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_THREAD_BY_ID_FAILED",
184
+ id: storage.createStorageErrorId("MSSQL", "GET_THREAD_BY_ID", "FAILED"),
228
185
  domain: error.ErrorDomain.STORAGE,
229
186
  category: error.ErrorCategory.THIRD_PARTY,
230
187
  details: {
@@ -235,11 +192,24 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
235
192
  );
236
193
  }
237
194
  }
238
- async getThreadsByResourceIdPaginated(args) {
239
- const { resourceId, page = 0, perPage: perPageInput, orderBy = "createdAt", sortDirection = "DESC" } = args;
195
+ async listThreadsByResourceId(args) {
196
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
197
+ if (page < 0) {
198
+ throw new error.MastraError({
199
+ id: storage.createStorageErrorId("MSSQL", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
200
+ domain: error.ErrorDomain.STORAGE,
201
+ category: error.ErrorCategory.USER,
202
+ text: "Page number must be non-negative",
203
+ details: {
204
+ resourceId,
205
+ page
206
+ }
207
+ });
208
+ }
209
+ const perPage = storage.normalizePerPage(perPageInput, 100);
210
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
211
+ const { field, direction } = this.parseOrderBy(orderBy);
240
212
  try {
241
- const perPage = perPageInput !== void 0 ? perPageInput : 100;
242
- const currentOffset = page * perPage;
243
213
  const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
244
214
  const countQuery = `SELECT COUNT(*) as count ${baseQuery}`;
245
215
  const countRequest = this.pool.request();
@@ -251,16 +221,22 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
251
221
  threads: [],
252
222
  total: 0,
253
223
  page,
254
- perPage,
224
+ perPage: perPageForResponse,
255
225
  hasMore: false
256
226
  };
257
227
  }
258
- const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
259
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
228
+ const orderByField = field === "createdAt" ? "[createdAt]" : "[updatedAt]";
229
+ const dir = (direction || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
230
+ const limitValue = perPageInput === false ? total : perPage;
231
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
260
232
  const dataRequest = this.pool.request();
261
233
  dataRequest.input("resourceId", resourceId);
262
- dataRequest.input("perPage", perPage);
263
- dataRequest.input("offset", currentOffset);
234
+ dataRequest.input("offset", offset);
235
+ if (limitValue > 2147483647) {
236
+ dataRequest.input("perPage", sql3__default.default.BigInt, limitValue);
237
+ } else {
238
+ dataRequest.input("perPage", limitValue);
239
+ }
264
240
  const rowsResult = await dataRequest.query(dataQuery);
265
241
  const rows = rowsResult.recordset || [];
266
242
  const threads = rows.map((thread) => ({
@@ -273,13 +249,13 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
273
249
  threads,
274
250
  total,
275
251
  page,
276
- perPage,
277
- hasMore: currentOffset + threads.length < total
252
+ perPage: perPageForResponse,
253
+ hasMore: perPageInput === false ? false : offset + perPage < total
278
254
  };
279
255
  } catch (error$1) {
280
256
  const mastraError = new error.MastraError(
281
257
  {
282
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
258
+ id: storage.createStorageErrorId("MSSQL", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
283
259
  domain: error.ErrorDomain.STORAGE,
284
260
  category: error.ErrorCategory.THIRD_PARTY,
285
261
  details: {
@@ -291,7 +267,13 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
291
267
  );
292
268
  this.logger?.error?.(mastraError.toString());
293
269
  this.logger?.trackException?.(mastraError);
294
- return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
270
+ return {
271
+ threads: [],
272
+ total: 0,
273
+ page,
274
+ perPage: perPageForResponse,
275
+ hasMore: false
276
+ };
295
277
  }
296
278
  }
297
279
  async saveThread({ thread }) {
@@ -313,15 +295,20 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
313
295
  req.input("id", thread.id);
314
296
  req.input("resourceId", thread.resourceId);
315
297
  req.input("title", thread.title);
316
- req.input("metadata", thread.metadata ? JSON.stringify(thread.metadata) : null);
317
- req.input("createdAt", sql2__default.default.DateTime2, thread.createdAt);
318
- req.input("updatedAt", sql2__default.default.DateTime2, thread.updatedAt);
298
+ const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
299
+ if (metadata === null) {
300
+ req.input("metadata", sql3__default.default.NVarChar, null);
301
+ } else {
302
+ req.input("metadata", metadata);
303
+ }
304
+ req.input("createdAt", sql3__default.default.DateTime2, thread.createdAt);
305
+ req.input("updatedAt", sql3__default.default.DateTime2, thread.updatedAt);
319
306
  await req.query(mergeSql);
320
307
  return thread;
321
308
  } catch (error$1) {
322
309
  throw new error.MastraError(
323
310
  {
324
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_THREAD_FAILED",
311
+ id: storage.createStorageErrorId("MSSQL", "SAVE_THREAD", "FAILED"),
325
312
  domain: error.ErrorDomain.STORAGE,
326
313
  category: error.ErrorCategory.THIRD_PARTY,
327
314
  details: {
@@ -332,30 +319,6 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
332
319
  );
333
320
  }
334
321
  }
335
- /**
336
- * @deprecated use getThreadsByResourceIdPaginated instead
337
- */
338
- async getThreadsByResourceId(args) {
339
- const { resourceId, orderBy = "createdAt", sortDirection = "DESC" } = args;
340
- try {
341
- const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
342
- const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
343
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection}`;
344
- const request = this.pool.request();
345
- request.input("resourceId", resourceId);
346
- const resultSet = await request.query(dataQuery);
347
- const rows = resultSet.recordset || [];
348
- return rows.map((thread) => ({
349
- ...thread,
350
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
351
- createdAt: thread.createdAt,
352
- updatedAt: thread.updatedAt
353
- }));
354
- } catch (error) {
355
- this.logger?.error?.(`Error getting threads for resource ${resourceId}:`, error);
356
- return [];
357
- }
358
- }
359
322
  /**
360
323
  * Updates a thread's title and metadata, merging with existing metadata. Returns the updated thread.
361
324
  */
@@ -367,7 +330,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
367
330
  const existingThread = await this.getThreadById({ threadId: id });
368
331
  if (!existingThread) {
369
332
  throw new error.MastraError({
370
- id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_THREAD_FAILED",
333
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "NOT_FOUND"),
371
334
  domain: error.ErrorDomain.STORAGE,
372
335
  category: error.ErrorCategory.USER,
373
336
  text: `Thread ${id} not found`,
@@ -383,7 +346,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
383
346
  };
384
347
  try {
385
348
  const table = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
386
- const sql7 = `UPDATE ${table}
349
+ const sql5 = `UPDATE ${table}
387
350
  SET title = @title,
388
351
  metadata = @metadata,
389
352
  [updatedAt] = @updatedAt
@@ -394,7 +357,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
394
357
  req.input("title", title);
395
358
  req.input("metadata", JSON.stringify(mergedMetadata));
396
359
  req.input("updatedAt", /* @__PURE__ */ new Date());
397
- const result = await req.query(sql7);
360
+ const result = await req.query(sql5);
398
361
  let thread = result.recordset && result.recordset[0];
399
362
  if (thread && "seq_id" in thread) {
400
363
  const { seq_id, ...rest } = thread;
@@ -402,7 +365,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
402
365
  }
403
366
  if (!thread) {
404
367
  throw new error.MastraError({
405
- id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_THREAD_FAILED",
368
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "NOT_FOUND"),
406
369
  domain: error.ErrorDomain.STORAGE,
407
370
  category: error.ErrorCategory.USER,
408
371
  text: `Thread ${id} not found after update`,
@@ -421,7 +384,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
421
384
  } catch (error$1) {
422
385
  throw new error.MastraError(
423
386
  {
424
- id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_THREAD_FAILED",
387
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "FAILED"),
425
388
  domain: error.ErrorDomain.STORAGE,
426
389
  category: error.ErrorCategory.THIRD_PARTY,
427
390
  details: {
@@ -451,7 +414,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
451
414
  });
452
415
  throw new error.MastraError(
453
416
  {
454
- id: "MASTRA_STORAGE_MSSQL_STORE_DELETE_THREAD_FAILED",
417
+ id: storage.createStorageErrorId("MSSQL", "DELETE_THREAD", "FAILED"),
455
418
  domain: error.ErrorDomain.STORAGE,
456
419
  category: error.ErrorCategory.THIRD_PARTY,
457
420
  details: {
@@ -462,24 +425,18 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
462
425
  );
463
426
  }
464
427
  }
465
- async _getIncludedMessages({
466
- threadId,
467
- selectBy,
468
- orderByStatement
469
- }) {
470
- const include = selectBy?.include;
471
- if (!include) return null;
428
+ async _getIncludedMessages({ include }) {
429
+ if (!include || include.length === 0) return null;
472
430
  const unionQueries = [];
473
431
  const paramValues = [];
474
432
  let paramIdx = 1;
475
433
  const paramNames = [];
434
+ const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
476
435
  for (const inc of include) {
477
436
  const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
478
- const searchId = inc.threadId || threadId;
479
- const pThreadId = `@p${paramIdx}`;
480
- const pId = `@p${paramIdx + 1}`;
481
- const pPrev = `@p${paramIdx + 2}`;
482
- const pNext = `@p${paramIdx + 3}`;
437
+ const pId = `@p${paramIdx}`;
438
+ const pPrev = `@p${paramIdx + 1}`;
439
+ const pNext = `@p${paramIdx + 2}`;
483
440
  unionQueries.push(
484
441
  `
485
442
  SELECT
@@ -492,30 +449,32 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
492
449
  m.[resourceId],
493
450
  m.seq_id
494
451
  FROM (
495
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
496
- FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
497
- WHERE [thread_id] = ${pThreadId}
452
+ SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
453
+ FROM ${tableName}
454
+ WHERE [thread_id] = (SELECT thread_id FROM ${tableName} WHERE id = ${pId})
498
455
  ) AS m
499
456
  WHERE m.id = ${pId}
500
457
  OR EXISTS (
501
458
  SELECT 1
502
459
  FROM (
503
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
504
- FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
505
- WHERE [thread_id] = ${pThreadId}
460
+ SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
461
+ FROM ${tableName}
462
+ WHERE [thread_id] = (SELECT thread_id FROM ${tableName} WHERE id = ${pId})
506
463
  ) AS target
507
464
  WHERE target.id = ${pId}
508
465
  AND (
509
- (m.row_num <= target.row_num + ${pPrev} AND m.row_num > target.row_num)
466
+ -- Get previous messages (messages that come BEFORE the target)
467
+ (m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
510
468
  OR
511
- (m.row_num >= target.row_num - ${pNext} AND m.row_num < target.row_num)
469
+ -- Get next messages (messages that come AFTER the target)
470
+ (m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
512
471
  )
513
472
  )
514
473
  `
515
474
  );
516
- paramValues.push(searchId, id, withPreviousMessages, withNextMessages);
517
- paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}`, `p${paramIdx + 3}`);
518
- paramIdx += 4;
475
+ paramValues.push(id, withPreviousMessages, withNextMessages);
476
+ paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}`);
477
+ paramIdx += 3;
519
478
  }
520
479
  const finalQuery = `
521
480
  SELECT * FROM (
@@ -537,33 +496,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
537
496
  });
538
497
  return dedupedRows;
539
498
  }
540
- async getMessages(args) {
541
- const { threadId, format, selectBy } = args;
499
+ async listMessagesById({ messageIds }) {
500
+ if (messageIds.length === 0) return { messages: [] };
542
501
  const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
543
502
  const orderByStatement = `ORDER BY [seq_id] DESC`;
544
- const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
545
503
  try {
546
504
  let rows = [];
547
- const include = selectBy?.include || [];
548
- if (include?.length) {
549
- const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
550
- if (includeMessages) {
551
- rows.push(...includeMessages);
552
- }
553
- }
554
- const excludeIds = rows.map((m) => m.id).filter(Boolean);
555
- let query = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [thread_id] = @threadId`;
505
+ let query = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
556
506
  const request = this.pool.request();
557
- request.input("threadId", threadId);
558
- if (excludeIds.length > 0) {
559
- const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
560
- query += ` AND id NOT IN (${excludeParams.join(", ")})`;
561
- excludeIds.forEach((id, idx) => {
562
- request.input(`id${idx}`, id);
563
- });
564
- }
565
- query += ` ${orderByStatement} OFFSET 0 ROWS FETCH NEXT @limit ROWS ONLY`;
566
- request.input("limit", limit);
507
+ messageIds.forEach((id, i) => request.input(`id${i}`, id));
508
+ query += ` ${orderByStatement}`;
567
509
  const result = await request.query(query);
568
510
  const remainingRows = result.recordset || [];
569
511
  rows.push(...remainingRows);
@@ -571,120 +513,177 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
571
513
  const timeDiff = a.seq_id - b.seq_id;
572
514
  return timeDiff;
573
515
  });
574
- rows = rows.map(({ seq_id, ...rest }) => rest);
575
- return this._parseAndFormatMessages(rows, format);
516
+ const messagesWithParsedContent = rows.map((row) => {
517
+ if (typeof row.content === "string") {
518
+ try {
519
+ return { ...row, content: JSON.parse(row.content) };
520
+ } catch {
521
+ return row;
522
+ }
523
+ }
524
+ return row;
525
+ });
526
+ const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
527
+ const list = new agent.MessageList().add(cleanMessages, "memory");
528
+ return { messages: list.get.all.db() };
576
529
  } catch (error$1) {
577
530
  const mastraError = new error.MastraError(
578
531
  {
579
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_FAILED",
532
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES_BY_ID", "FAILED"),
580
533
  domain: error.ErrorDomain.STORAGE,
581
534
  category: error.ErrorCategory.THIRD_PARTY,
582
535
  details: {
583
- threadId
536
+ messageIds: JSON.stringify(messageIds)
584
537
  }
585
538
  },
586
539
  error$1
587
540
  );
588
541
  this.logger?.error?.(mastraError.toString());
589
- this.logger?.trackException(mastraError);
590
- return [];
542
+ this.logger?.trackException?.(mastraError);
543
+ return { messages: [] };
591
544
  }
592
545
  }
593
- async getMessagesPaginated(args) {
594
- const { threadId, selectBy } = args;
595
- const { page = 0, perPage: perPageInput } = selectBy?.pagination || {};
596
- const orderByStatement = `ORDER BY [seq_id] DESC`;
597
- if (selectBy?.include?.length) {
598
- await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
546
+ async listMessages(args) {
547
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
548
+ const threadIds = Array.isArray(threadId) ? threadId : [threadId];
549
+ if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
550
+ throw new error.MastraError(
551
+ {
552
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "INVALID_THREAD_ID"),
553
+ domain: error.ErrorDomain.STORAGE,
554
+ category: error.ErrorCategory.THIRD_PARTY,
555
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
556
+ },
557
+ new Error("threadId must be a non-empty string or array of non-empty strings")
558
+ );
559
+ }
560
+ if (page < 0) {
561
+ throw new error.MastraError({
562
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "INVALID_PAGE"),
563
+ domain: error.ErrorDomain.STORAGE,
564
+ category: error.ErrorCategory.USER,
565
+ text: "Page number must be non-negative",
566
+ details: {
567
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
568
+ page
569
+ }
570
+ });
599
571
  }
572
+ const perPage = storage.normalizePerPage(perPageInput, 40);
573
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
600
574
  try {
601
- const { threadId: threadId2, format, selectBy: selectBy2 } = args;
602
- const { page: page2 = 0, perPage: perPageInput2, dateRange } = selectBy2?.pagination || {};
603
- const fromDate = dateRange?.start;
604
- const toDate = dateRange?.end;
605
- const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
606
- const orderByStatement2 = `ORDER BY [seq_id] DESC`;
607
- let messages2 = [];
608
- if (selectBy2?.include?.length) {
609
- const includeMessages = await this._getIncludedMessages({ threadId: threadId2, selectBy: selectBy2, orderByStatement: orderByStatement2 });
610
- if (includeMessages) messages2.push(...includeMessages);
611
- }
612
- const perPage = perPageInput2 !== void 0 ? perPageInput2 : storage.resolveMessageLimit({ last: selectBy2?.last, defaultLimit: 40 });
613
- const currentOffset = page2 * perPage;
614
- const conditions = ["[thread_id] = @threadId"];
615
- const request = this.pool.request();
616
- request.input("threadId", threadId2);
617
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
618
- conditions.push("[createdAt] >= @fromDate");
619
- request.input("fromDate", fromDate.toISOString());
620
- }
621
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
622
- conditions.push("[createdAt] <= @toDate");
623
- request.input("toDate", toDate.toISOString());
624
- }
625
- const whereClause = `WHERE ${conditions.join(" AND ")}`;
626
- const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
627
- const countResult = await request.query(countQuery);
575
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
576
+ const orderByStatement = `ORDER BY [${field}] ${direction}, [seq_id] ${direction}`;
577
+ const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
578
+ const baseQuery = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId FROM ${tableName}`;
579
+ const filters = {
580
+ thread_id: threadIds.length === 1 ? threadIds[0] : { $in: threadIds },
581
+ ...resourceId ? { resourceId } : {},
582
+ ...buildDateRangeFilter(filter?.dateRange, "createdAt")
583
+ };
584
+ const { sql: actualWhereClause = "", params: whereParams } = prepareWhereClause(
585
+ filters);
586
+ const bindWhereParams = (req) => {
587
+ Object.entries(whereParams).forEach(([paramName, paramValue]) => req.input(paramName, paramValue));
588
+ };
589
+ const countRequest = this.pool.request();
590
+ bindWhereParams(countRequest);
591
+ const countResult = await countRequest.query(`SELECT COUNT(*) as total FROM ${tableName}${actualWhereClause}`);
628
592
  const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
629
- if (total === 0 && messages2.length > 0) {
630
- const parsedIncluded = this._parseAndFormatMessages(messages2, format);
593
+ const fetchBaseMessages = async () => {
594
+ const request = this.pool.request();
595
+ bindWhereParams(request);
596
+ if (perPageInput === false) {
597
+ const result2 = await request.query(`${baseQuery}${actualWhereClause} ${orderByStatement}`);
598
+ return result2.recordset || [];
599
+ }
600
+ request.input("offset", offset);
601
+ request.input("limit", perPage > 2147483647 ? sql3__default.default.BigInt : sql3__default.default.Int, perPage);
602
+ const result = await request.query(
603
+ `${baseQuery}${actualWhereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
604
+ );
605
+ return result.recordset || [];
606
+ };
607
+ const baseRows = perPage === 0 ? [] : await fetchBaseMessages();
608
+ const messages = [...baseRows];
609
+ const seqById = /* @__PURE__ */ new Map();
610
+ messages.forEach((msg) => {
611
+ if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
612
+ });
613
+ if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
631
614
  return {
632
- messages: parsedIncluded,
633
- total: parsedIncluded.length,
634
- page: page2,
635
- perPage,
615
+ messages: [],
616
+ total: 0,
617
+ page,
618
+ perPage: perPageForResponse,
636
619
  hasMore: false
637
620
  };
638
621
  }
639
- const excludeIds = messages2.map((m) => m.id);
640
- if (excludeIds.length > 0) {
641
- const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
642
- conditions.push(`id NOT IN (${excludeParams.join(", ")})`);
643
- excludeIds.forEach((id, idx) => request.input(`id${idx}`, id));
644
- }
645
- const finalWhereClause = `WHERE ${conditions.join(" AND ")}`;
646
- const dataQuery = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${finalWhereClause} ${orderByStatement2} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
647
- request.input("offset", currentOffset);
648
- request.input("limit", perPage);
649
- const rowsResult = await request.query(dataQuery);
650
- const rows = rowsResult.recordset || [];
651
- rows.sort((a, b) => a.seq_id - b.seq_id);
652
- messages2.push(...rows);
653
- const parsed = this._parseAndFormatMessages(messages2, format);
622
+ if (include?.length) {
623
+ const messageIds = new Set(messages.map((m) => m.id));
624
+ const includeMessages = await this._getIncludedMessages({ include });
625
+ includeMessages?.forEach((msg) => {
626
+ if (!messageIds.has(msg.id)) {
627
+ messages.push(msg);
628
+ messageIds.add(msg.id);
629
+ if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
630
+ }
631
+ });
632
+ }
633
+ const parsed = this._parseAndFormatMessages(messages, "v2");
634
+ const mult = direction === "ASC" ? 1 : -1;
635
+ const finalMessages = parsed.sort((a, b) => {
636
+ const aVal = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
637
+ const bVal = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
638
+ if (aVal == null || bVal == null) {
639
+ return aVal == null && bVal == null ? a.id.localeCompare(b.id) : aVal == null ? 1 : -1;
640
+ }
641
+ const diff = (typeof aVal === "number" && typeof bVal === "number" ? aVal - bVal : String(aVal).localeCompare(String(bVal))) * mult;
642
+ if (diff !== 0) return diff;
643
+ const seqA = seqById.get(a.id);
644
+ const seqB = seqById.get(b.id);
645
+ return seqA != null && seqB != null ? (seqA - seqB) * mult : a.id.localeCompare(b.id);
646
+ });
647
+ const threadIdSet = new Set(threadIds);
648
+ const returnedThreadMessageCount = finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).length;
649
+ const hasMore = perPageInput !== false && returnedThreadMessageCount < total && offset + perPage < total;
654
650
  return {
655
- messages: parsed,
656
- total: total + excludeIds.length,
657
- page: page2,
658
- perPage,
659
- hasMore: currentOffset + rows.length < total
651
+ messages: finalMessages,
652
+ total,
653
+ page,
654
+ perPage: perPageForResponse,
655
+ hasMore
660
656
  };
661
657
  } catch (error$1) {
662
658
  const mastraError = new error.MastraError(
663
659
  {
664
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_PAGINATED_FAILED",
660
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "FAILED"),
665
661
  domain: error.ErrorDomain.STORAGE,
666
662
  category: error.ErrorCategory.THIRD_PARTY,
667
663
  details: {
668
- threadId,
669
- page
664
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
665
+ resourceId: resourceId ?? ""
670
666
  }
671
667
  },
672
668
  error$1
673
669
  );
674
670
  this.logger?.error?.(mastraError.toString());
675
- this.logger?.trackException(mastraError);
676
- return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
671
+ this.logger?.trackException?.(mastraError);
672
+ return {
673
+ messages: [],
674
+ total: 0,
675
+ page,
676
+ perPage: perPageForResponse,
677
+ hasMore: false
678
+ };
677
679
  }
678
680
  }
679
- async saveMessages({
680
- messages,
681
- format
682
- }) {
683
- if (messages.length === 0) return messages;
681
+ async saveMessages({ messages }) {
682
+ if (messages.length === 0) return { messages: [] };
684
683
  const threadId = messages[0]?.threadId;
685
684
  if (!threadId) {
686
685
  throw new error.MastraError({
687
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
686
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "INVALID_THREAD_ID"),
688
687
  domain: error.ErrorDomain.STORAGE,
689
688
  category: error.ErrorCategory.THIRD_PARTY,
690
689
  text: `Thread ID is required`
@@ -693,7 +692,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
693
692
  const thread = await this.getThreadById({ threadId });
694
693
  if (!thread) {
695
694
  throw new error.MastraError({
696
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
695
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "THREAD_NOT_FOUND"),
697
696
  domain: error.ErrorDomain.STORAGE,
698
697
  category: error.ErrorCategory.THIRD_PARTY,
699
698
  text: `Thread ${threadId} not found`,
@@ -724,7 +723,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
724
723
  "content",
725
724
  typeof message.content === "string" ? message.content : JSON.stringify(message.content)
726
725
  );
727
- request.input("createdAt", sql2__default.default.DateTime2, message.createdAt);
726
+ request.input("createdAt", sql3__default.default.DateTime2, message.createdAt);
728
727
  request.input("role", message.role);
729
728
  request.input("type", message.type || "v2");
730
729
  request.input("resourceId", message.resourceId);
@@ -743,7 +742,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
743
742
  await request.query(mergeSql);
744
743
  }
745
744
  const threadReq = transaction.request();
746
- threadReq.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
745
+ threadReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
747
746
  threadReq.input("id", threadId);
748
747
  await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
749
748
  await transaction.commit();
@@ -762,12 +761,11 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
762
761
  return message;
763
762
  });
764
763
  const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
765
- if (format === "v2") return list.get.all.v2();
766
- return list.get.all.v1();
764
+ return { messages: list.get.all.db() };
767
765
  } catch (error$1) {
768
766
  throw new error.MastraError(
769
767
  {
770
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
768
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "FAILED"),
771
769
  domain: error.ErrorDomain.STORAGE,
772
770
  category: error.ErrorCategory.THIRD_PARTY,
773
771
  details: { threadId }
@@ -858,7 +856,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
858
856
  await transaction.rollback();
859
857
  throw new error.MastraError(
860
858
  {
861
- id: "MASTRA_STORAGE_MSSQL_UPDATE_MESSAGES_FAILED",
859
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_MESSAGES", "FAILED"),
862
860
  domain: error.ErrorDomain.STORAGE,
863
861
  category: error.ErrorCategory.THIRD_PARTY
864
862
  },
@@ -920,7 +918,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
920
918
  } catch (error$1) {
921
919
  throw new error.MastraError(
922
920
  {
923
- id: "MASTRA_STORAGE_MSSQL_STORE_DELETE_MESSAGES_FAILED",
921
+ id: storage.createStorageErrorId("MSSQL", "DELETE_MESSAGES", "FAILED"),
924
922
  domain: error.ErrorDomain.STORAGE,
925
923
  category: error.ErrorCategory.THIRD_PARTY,
926
924
  details: { messageIds: messageIds.join(", ") }
@@ -939,14 +937,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
939
937
  return null;
940
938
  }
941
939
  return {
942
- ...result,
943
- workingMemory: typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
940
+ id: result.id,
941
+ createdAt: result.createdAt,
942
+ updatedAt: result.updatedAt,
943
+ workingMemory: result.workingMemory,
944
944
  metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
945
945
  };
946
946
  } catch (error$1) {
947
947
  const mastraError = new error.MastraError(
948
948
  {
949
- id: "MASTRA_STORAGE_MSSQL_GET_RESOURCE_BY_ID_FAILED",
949
+ id: storage.createStorageErrorId("MSSQL", "GET_RESOURCE_BY_ID", "FAILED"),
950
950
  domain: error.ErrorDomain.STORAGE,
951
951
  category: error.ErrorCategory.THIRD_PARTY,
952
952
  details: { resourceId }
@@ -954,7 +954,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
954
954
  error$1
955
955
  );
956
956
  this.logger?.error?.(mastraError.toString());
957
- this.logger?.trackException(mastraError);
957
+ this.logger?.trackException?.(mastraError);
958
958
  throw mastraError;
959
959
  }
960
960
  }
@@ -963,7 +963,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
963
963
  tableName: storage.TABLE_RESOURCES,
964
964
  record: {
965
965
  ...resource,
966
- metadata: JSON.stringify(resource.metadata)
966
+ metadata: resource.metadata
967
967
  }
968
968
  });
969
969
  return resource;
@@ -1013,7 +1013,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1013
1013
  } catch (error$1) {
1014
1014
  const mastraError = new error.MastraError(
1015
1015
  {
1016
- id: "MASTRA_STORAGE_MSSQL_UPDATE_RESOURCE_FAILED",
1016
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_RESOURCE", "FAILED"),
1017
1017
  domain: error.ErrorDomain.STORAGE,
1018
1018
  category: error.ErrorCategory.THIRD_PARTY,
1019
1019
  details: { resourceId }
@@ -1021,115 +1021,440 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1021
1021
  error$1
1022
1022
  );
1023
1023
  this.logger?.error?.(mastraError.toString());
1024
- this.logger?.trackException(mastraError);
1024
+ this.logger?.trackException?.(mastraError);
1025
1025
  throw mastraError;
1026
1026
  }
1027
1027
  }
1028
1028
  };
1029
- var StoreOperationsMSSQL = class extends storage.StoreOperations {
1029
+ var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
1030
1030
  pool;
1031
- schemaName;
1032
- setupSchemaPromise = null;
1033
- schemaSetupComplete = void 0;
1034
- getSqlType(type, isPrimaryKey = false) {
1035
- switch (type) {
1036
- case "text":
1037
- return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(MAX)";
1038
- case "timestamp":
1039
- return "DATETIME2(7)";
1040
- case "uuid":
1041
- return "UNIQUEIDENTIFIER";
1042
- case "jsonb":
1043
- return "NVARCHAR(MAX)";
1044
- case "integer":
1045
- return "INT";
1046
- case "bigint":
1047
- return "BIGINT";
1048
- case "float":
1049
- return "FLOAT";
1050
- default:
1051
- throw new error.MastraError({
1052
- id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
1053
- domain: error.ErrorDomain.STORAGE,
1054
- category: error.ErrorCategory.THIRD_PARTY
1055
- });
1056
- }
1057
- }
1058
- constructor({ pool, schemaName }) {
1031
+ operations;
1032
+ schema;
1033
+ constructor({
1034
+ pool,
1035
+ operations,
1036
+ schema
1037
+ }) {
1059
1038
  super();
1060
1039
  this.pool = pool;
1061
- this.schemaName = schemaName;
1062
- }
1063
- async hasColumn(table, column) {
1064
- const schema = this.schemaName || "dbo";
1065
- const request = this.pool.request();
1066
- request.input("schema", schema);
1067
- request.input("table", table);
1068
- request.input("column", column);
1069
- request.input("columnLower", column.toLowerCase());
1070
- const result = await request.query(
1071
- `SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
1072
- );
1073
- return result.recordset.length > 0;
1040
+ this.operations = operations;
1041
+ this.schema = schema;
1074
1042
  }
1075
- async setupSchema() {
1076
- if (!this.schemaName || this.schemaSetupComplete) {
1077
- return;
1078
- }
1079
- if (!this.setupSchemaPromise) {
1080
- this.setupSchemaPromise = (async () => {
1081
- try {
1082
- const checkRequest = this.pool.request();
1083
- checkRequest.input("schemaName", this.schemaName);
1084
- const checkResult = await checkRequest.query(`
1085
- SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
1086
- `);
1087
- const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1088
- if (!schemaExists) {
1089
- try {
1090
- await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
1091
- this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
1092
- } catch (error) {
1093
- this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
1094
- throw new Error(
1095
- `Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
1096
- );
1097
- }
1098
- }
1099
- this.schemaSetupComplete = true;
1100
- this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
1101
- } catch (error) {
1102
- this.schemaSetupComplete = void 0;
1103
- this.setupSchemaPromise = null;
1104
- throw error;
1105
- } finally {
1106
- this.setupSchemaPromise = null;
1107
- }
1108
- })();
1109
- }
1110
- await this.setupSchemaPromise;
1043
+ get tracingStrategy() {
1044
+ return {
1045
+ preferred: "batch-with-updates",
1046
+ supported: ["batch-with-updates", "insert-only"]
1047
+ };
1111
1048
  }
1112
- async insert({ tableName, record }) {
1049
+ async createSpan(span) {
1113
1050
  try {
1114
- const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
1115
- const values = Object.values(record);
1116
- const paramNames = values.map((_, i) => `@param${i}`);
1117
- const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${columns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
1118
- const request = this.pool.request();
1119
- values.forEach((value, i) => {
1120
- if (value instanceof Date) {
1121
- request.input(`param${i}`, sql2__default.default.DateTime2, value);
1122
- } else if (typeof value === "object" && value !== null) {
1123
- request.input(`param${i}`, JSON.stringify(value));
1051
+ const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
1052
+ const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
1053
+ const record = {
1054
+ ...span,
1055
+ startedAt,
1056
+ endedAt
1057
+ // Note: createdAt/updatedAt will be set by default values
1058
+ };
1059
+ return this.operations.insert({ tableName: storage.TABLE_SPANS, record });
1060
+ } catch (error$1) {
1061
+ throw new error.MastraError(
1062
+ {
1063
+ id: storage.createStorageErrorId("MSSQL", "CREATE_SPAN", "FAILED"),
1064
+ domain: error.ErrorDomain.STORAGE,
1065
+ category: error.ErrorCategory.USER,
1066
+ details: {
1067
+ spanId: span.spanId,
1068
+ traceId: span.traceId,
1069
+ spanType: span.spanType,
1070
+ spanName: span.name
1071
+ }
1072
+ },
1073
+ error$1
1074
+ );
1075
+ }
1076
+ }
1077
+ async getTrace(traceId) {
1078
+ try {
1079
+ const tableName = getTableName({
1080
+ indexName: storage.TABLE_SPANS,
1081
+ schemaName: getSchemaName(this.schema)
1082
+ });
1083
+ const request = this.pool.request();
1084
+ request.input("traceId", traceId);
1085
+ const result = await request.query(
1086
+ `SELECT
1087
+ [traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
1088
+ [attributes], [metadata], [links], [input], [output], [error], [isEvent],
1089
+ [startedAt], [endedAt], [createdAt], [updatedAt]
1090
+ FROM ${tableName}
1091
+ WHERE [traceId] = @traceId
1092
+ ORDER BY [startedAt] DESC`
1093
+ );
1094
+ if (!result.recordset || result.recordset.length === 0) {
1095
+ return null;
1096
+ }
1097
+ return {
1098
+ traceId,
1099
+ spans: result.recordset.map(
1100
+ (span) => transformFromSqlRow({
1101
+ tableName: storage.TABLE_SPANS,
1102
+ sqlRow: span
1103
+ })
1104
+ )
1105
+ };
1106
+ } catch (error$1) {
1107
+ throw new error.MastraError(
1108
+ {
1109
+ id: storage.createStorageErrorId("MSSQL", "GET_TRACE", "FAILED"),
1110
+ domain: error.ErrorDomain.STORAGE,
1111
+ category: error.ErrorCategory.USER,
1112
+ details: {
1113
+ traceId
1114
+ }
1115
+ },
1116
+ error$1
1117
+ );
1118
+ }
1119
+ }
1120
+ async updateSpan({
1121
+ spanId,
1122
+ traceId,
1123
+ updates
1124
+ }) {
1125
+ try {
1126
+ const data = { ...updates };
1127
+ if (data.endedAt instanceof Date) {
1128
+ data.endedAt = data.endedAt.toISOString();
1129
+ }
1130
+ if (data.startedAt instanceof Date) {
1131
+ data.startedAt = data.startedAt.toISOString();
1132
+ }
1133
+ await this.operations.update({
1134
+ tableName: storage.TABLE_SPANS,
1135
+ keys: { spanId, traceId },
1136
+ data
1137
+ });
1138
+ } catch (error$1) {
1139
+ throw new error.MastraError(
1140
+ {
1141
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_SPAN", "FAILED"),
1142
+ domain: error.ErrorDomain.STORAGE,
1143
+ category: error.ErrorCategory.USER,
1144
+ details: {
1145
+ spanId,
1146
+ traceId
1147
+ }
1148
+ },
1149
+ error$1
1150
+ );
1151
+ }
1152
+ }
1153
+ async getTracesPaginated({
1154
+ filters,
1155
+ pagination
1156
+ }) {
1157
+ const page = pagination?.page ?? 0;
1158
+ const perPage = pagination?.perPage ?? 10;
1159
+ const { entityId, entityType, ...actualFilters } = filters || {};
1160
+ const filtersWithDateRange = {
1161
+ ...actualFilters,
1162
+ ...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
1163
+ parentSpanId: null
1164
+ // Only get root spans for traces
1165
+ };
1166
+ const whereClause = prepareWhereClause(filtersWithDateRange);
1167
+ let actualWhereClause = whereClause.sql;
1168
+ const params = { ...whereClause.params };
1169
+ let currentParamIndex = Object.keys(params).length + 1;
1170
+ if (entityId && entityType) {
1171
+ let name = "";
1172
+ if (entityType === "workflow") {
1173
+ name = `workflow run: '${entityId}'`;
1174
+ } else if (entityType === "agent") {
1175
+ name = `agent run: '${entityId}'`;
1176
+ } else {
1177
+ const error$1 = new error.MastraError({
1178
+ id: storage.createStorageErrorId("MSSQL", "GET_TRACES_PAGINATED", "INVALID_ENTITY_TYPE"),
1179
+ domain: error.ErrorDomain.STORAGE,
1180
+ category: error.ErrorCategory.USER,
1181
+ details: {
1182
+ entityType
1183
+ },
1184
+ text: `Cannot filter by entity type: ${entityType}`
1185
+ });
1186
+ throw error$1;
1187
+ }
1188
+ const entityParam = `p${currentParamIndex++}`;
1189
+ if (actualWhereClause) {
1190
+ actualWhereClause += ` AND [name] = @${entityParam}`;
1191
+ } else {
1192
+ actualWhereClause = ` WHERE [name] = @${entityParam}`;
1193
+ }
1194
+ params[entityParam] = name;
1195
+ }
1196
+ const tableName = getTableName({
1197
+ indexName: storage.TABLE_SPANS,
1198
+ schemaName: getSchemaName(this.schema)
1199
+ });
1200
+ try {
1201
+ const countRequest = this.pool.request();
1202
+ Object.entries(params).forEach(([key, value]) => {
1203
+ countRequest.input(key, value);
1204
+ });
1205
+ const countResult = await countRequest.query(
1206
+ `SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
1207
+ );
1208
+ const total = countResult.recordset[0]?.count ?? 0;
1209
+ if (total === 0) {
1210
+ return {
1211
+ pagination: {
1212
+ total: 0,
1213
+ page,
1214
+ perPage,
1215
+ hasMore: false
1216
+ },
1217
+ spans: []
1218
+ };
1219
+ }
1220
+ const dataRequest = this.pool.request();
1221
+ Object.entries(params).forEach(([key, value]) => {
1222
+ dataRequest.input(key, value);
1223
+ });
1224
+ dataRequest.input("offset", page * perPage);
1225
+ dataRequest.input("limit", perPage);
1226
+ const dataResult = await dataRequest.query(
1227
+ `SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
1228
+ );
1229
+ const spans = dataResult.recordset.map(
1230
+ (row) => transformFromSqlRow({
1231
+ tableName: storage.TABLE_SPANS,
1232
+ sqlRow: row
1233
+ })
1234
+ );
1235
+ return {
1236
+ pagination: {
1237
+ total,
1238
+ page,
1239
+ perPage,
1240
+ hasMore: (page + 1) * perPage < total
1241
+ },
1242
+ spans
1243
+ };
1244
+ } catch (error$1) {
1245
+ throw new error.MastraError(
1246
+ {
1247
+ id: storage.createStorageErrorId("MSSQL", "GET_TRACES_PAGINATED", "FAILED"),
1248
+ domain: error.ErrorDomain.STORAGE,
1249
+ category: error.ErrorCategory.USER
1250
+ },
1251
+ error$1
1252
+ );
1253
+ }
1254
+ }
1255
+ async batchCreateSpans(args) {
1256
+ if (!args.records || args.records.length === 0) {
1257
+ return;
1258
+ }
1259
+ try {
1260
+ await this.operations.batchInsert({
1261
+ tableName: storage.TABLE_SPANS,
1262
+ records: args.records.map((span) => ({
1263
+ ...span,
1264
+ startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
1265
+ endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
1266
+ }))
1267
+ });
1268
+ } catch (error$1) {
1269
+ throw new error.MastraError(
1270
+ {
1271
+ id: storage.createStorageErrorId("MSSQL", "BATCH_CREATE_SPANS", "FAILED"),
1272
+ domain: error.ErrorDomain.STORAGE,
1273
+ category: error.ErrorCategory.USER,
1274
+ details: {
1275
+ count: args.records.length
1276
+ }
1277
+ },
1278
+ error$1
1279
+ );
1280
+ }
1281
+ }
1282
+ async batchUpdateSpans(args) {
1283
+ if (!args.records || args.records.length === 0) {
1284
+ return;
1285
+ }
1286
+ try {
1287
+ const updates = args.records.map(({ traceId, spanId, updates: data }) => {
1288
+ const processedData = { ...data };
1289
+ if (processedData.endedAt instanceof Date) {
1290
+ processedData.endedAt = processedData.endedAt.toISOString();
1291
+ }
1292
+ if (processedData.startedAt instanceof Date) {
1293
+ processedData.startedAt = processedData.startedAt.toISOString();
1294
+ }
1295
+ return {
1296
+ keys: { spanId, traceId },
1297
+ data: processedData
1298
+ };
1299
+ });
1300
+ await this.operations.batchUpdate({
1301
+ tableName: storage.TABLE_SPANS,
1302
+ updates
1303
+ });
1304
+ } catch (error$1) {
1305
+ throw new error.MastraError(
1306
+ {
1307
+ id: storage.createStorageErrorId("MSSQL", "BATCH_UPDATE_SPANS", "FAILED"),
1308
+ domain: error.ErrorDomain.STORAGE,
1309
+ category: error.ErrorCategory.USER,
1310
+ details: {
1311
+ count: args.records.length
1312
+ }
1313
+ },
1314
+ error$1
1315
+ );
1316
+ }
1317
+ }
1318
+ async batchDeleteTraces(args) {
1319
+ if (!args.traceIds || args.traceIds.length === 0) {
1320
+ return;
1321
+ }
1322
+ try {
1323
+ const keys = args.traceIds.map((traceId) => ({ traceId }));
1324
+ await this.operations.batchDelete({
1325
+ tableName: storage.TABLE_SPANS,
1326
+ keys
1327
+ });
1328
+ } catch (error$1) {
1329
+ throw new error.MastraError(
1330
+ {
1331
+ id: storage.createStorageErrorId("MSSQL", "BATCH_DELETE_TRACES", "FAILED"),
1332
+ domain: error.ErrorDomain.STORAGE,
1333
+ category: error.ErrorCategory.USER,
1334
+ details: {
1335
+ count: args.traceIds.length
1336
+ }
1337
+ },
1338
+ error$1
1339
+ );
1340
+ }
1341
+ }
1342
+ };
1343
+ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1344
+ pool;
1345
+ schemaName;
1346
+ setupSchemaPromise = null;
1347
+ schemaSetupComplete = void 0;
1348
+ getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
1349
+ switch (type) {
1350
+ case "text":
1351
+ if (useLargeStorage) {
1352
+ return "NVARCHAR(MAX)";
1353
+ }
1354
+ return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
1355
+ case "timestamp":
1356
+ return "DATETIME2(7)";
1357
+ case "uuid":
1358
+ return "UNIQUEIDENTIFIER";
1359
+ case "jsonb":
1360
+ return "NVARCHAR(MAX)";
1361
+ case "integer":
1362
+ return "INT";
1363
+ case "bigint":
1364
+ return "BIGINT";
1365
+ case "float":
1366
+ return "FLOAT";
1367
+ case "boolean":
1368
+ return "BIT";
1369
+ default:
1370
+ throw new error.MastraError({
1371
+ id: storage.createStorageErrorId("MSSQL", "TYPE", "NOT_SUPPORTED"),
1372
+ domain: error.ErrorDomain.STORAGE,
1373
+ category: error.ErrorCategory.THIRD_PARTY
1374
+ });
1375
+ }
1376
+ }
1377
+ constructor({ pool, schemaName }) {
1378
+ super();
1379
+ this.pool = pool;
1380
+ this.schemaName = schemaName;
1381
+ }
1382
+ async hasColumn(table, column) {
1383
+ const schema = this.schemaName || "dbo";
1384
+ const request = this.pool.request();
1385
+ request.input("schema", schema);
1386
+ request.input("table", table);
1387
+ request.input("column", column);
1388
+ request.input("columnLower", column.toLowerCase());
1389
+ const result = await request.query(
1390
+ `SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
1391
+ );
1392
+ return result.recordset.length > 0;
1393
+ }
1394
+ async setupSchema() {
1395
+ if (!this.schemaName || this.schemaSetupComplete) {
1396
+ return;
1397
+ }
1398
+ if (!this.setupSchemaPromise) {
1399
+ this.setupSchemaPromise = (async () => {
1400
+ try {
1401
+ const checkRequest = this.pool.request();
1402
+ checkRequest.input("schemaName", this.schemaName);
1403
+ const checkResult = await checkRequest.query(`
1404
+ SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
1405
+ `);
1406
+ const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1407
+ if (!schemaExists) {
1408
+ try {
1409
+ await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
1410
+ this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
1411
+ } catch (error) {
1412
+ this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
1413
+ throw new Error(
1414
+ `Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
1415
+ );
1416
+ }
1417
+ }
1418
+ this.schemaSetupComplete = true;
1419
+ this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
1420
+ } catch (error) {
1421
+ this.schemaSetupComplete = void 0;
1422
+ this.setupSchemaPromise = null;
1423
+ throw error;
1424
+ } finally {
1425
+ this.setupSchemaPromise = null;
1426
+ }
1427
+ })();
1428
+ }
1429
+ await this.setupSchemaPromise;
1430
+ }
1431
+ async insert({
1432
+ tableName,
1433
+ record,
1434
+ transaction
1435
+ }) {
1436
+ try {
1437
+ const columns = Object.keys(record);
1438
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
1439
+ const paramNames = columns.map((_, i) => `@param${i}`);
1440
+ const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
1441
+ const request = transaction ? transaction.request() : this.pool.request();
1442
+ columns.forEach((col, i) => {
1443
+ const value = record[col];
1444
+ const preparedValue = this.prepareValue(value, col, tableName);
1445
+ if (preparedValue instanceof Date) {
1446
+ request.input(`param${i}`, sql3__default.default.DateTime2, preparedValue);
1447
+ } else if (preparedValue === null || preparedValue === void 0) {
1448
+ request.input(`param${i}`, this.getMssqlType(tableName, col), null);
1124
1449
  } else {
1125
- request.input(`param${i}`, value);
1450
+ request.input(`param${i}`, preparedValue);
1126
1451
  }
1127
1452
  });
1128
1453
  await request.query(insertSql);
1129
1454
  } catch (error$1) {
1130
1455
  throw new error.MastraError(
1131
1456
  {
1132
- id: "MASTRA_STORAGE_MSSQL_STORE_INSERT_FAILED",
1457
+ id: storage.createStorageErrorId("MSSQL", "INSERT", "FAILED"),
1133
1458
  domain: error.ErrorDomain.STORAGE,
1134
1459
  category: error.ErrorCategory.THIRD_PARTY,
1135
1460
  details: {
@@ -1146,7 +1471,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1146
1471
  try {
1147
1472
  await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
1148
1473
  } catch (truncateError) {
1149
- if (truncateError.message && truncateError.message.includes("foreign key")) {
1474
+ if (truncateError?.number === 4712) {
1150
1475
  await this.pool.request().query(`DELETE FROM ${fullTableName}`);
1151
1476
  } else {
1152
1477
  throw truncateError;
@@ -1155,7 +1480,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1155
1480
  } catch (error$1) {
1156
1481
  throw new error.MastraError(
1157
1482
  {
1158
- id: "MASTRA_STORAGE_MSSQL_STORE_CLEAR_TABLE_FAILED",
1483
+ id: storage.createStorageErrorId("MSSQL", "CLEAR_TABLE", "FAILED"),
1159
1484
  domain: error.ErrorDomain.STORAGE,
1160
1485
  category: error.ErrorCategory.THIRD_PARTY,
1161
1486
  details: {
@@ -1169,9 +1494,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1169
1494
  getDefaultValue(type) {
1170
1495
  switch (type) {
1171
1496
  case "timestamp":
1172
- return "DEFAULT SYSDATETIMEOFFSET()";
1497
+ return "DEFAULT SYSUTCDATETIME()";
1173
1498
  case "jsonb":
1174
1499
  return "DEFAULT N'{}'";
1500
+ case "boolean":
1501
+ return "DEFAULT 0";
1175
1502
  default:
1176
1503
  return super.getDefaultValue(type);
1177
1504
  }
@@ -1182,13 +1509,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1182
1509
  }) {
1183
1510
  try {
1184
1511
  const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
1512
+ const largeDataColumns = [
1513
+ "workingMemory",
1514
+ "snapshot",
1515
+ "metadata",
1516
+ "content",
1517
+ // messages.content - can be very long conversation content
1518
+ "input",
1519
+ // evals.input - test input data
1520
+ "output",
1521
+ // evals.output - test output data
1522
+ "instructions",
1523
+ // evals.instructions - evaluation instructions
1524
+ "other"
1525
+ // traces.other - additional trace data
1526
+ ];
1185
1527
  const columns = Object.entries(schema).map(([name, def]) => {
1186
1528
  const parsedName = utils.parseSqlIdentifier(name, "column name");
1187
1529
  const constraints = [];
1188
1530
  if (def.primaryKey) constraints.push("PRIMARY KEY");
1189
1531
  if (!def.nullable) constraints.push("NOT NULL");
1190
1532
  const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
1191
- return `[${parsedName}] ${this.getSqlType(def.type, isIndexed)} ${constraints.join(" ")}`.trim();
1533
+ const useLargeStorage = largeDataColumns.includes(name);
1534
+ return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
1192
1535
  }).join(",\n");
1193
1536
  if (this.schemaName) {
1194
1537
  await this.setupSchema();
@@ -1240,7 +1583,7 @@ ${columns}
1240
1583
  } catch (error$1) {
1241
1584
  throw new error.MastraError(
1242
1585
  {
1243
- id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_TABLE_FAILED",
1586
+ id: storage.createStorageErrorId("MSSQL", "CREATE_TABLE", "FAILED"),
1244
1587
  domain: error.ErrorDomain.STORAGE,
1245
1588
  category: error.ErrorCategory.THIRD_PARTY,
1246
1589
  details: {
@@ -1275,7 +1618,19 @@ ${columns}
1275
1618
  const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1276
1619
  if (!columnExists) {
1277
1620
  const columnDef = schema[columnName];
1278
- const sqlType = this.getSqlType(columnDef.type);
1621
+ const largeDataColumns = [
1622
+ "workingMemory",
1623
+ "snapshot",
1624
+ "metadata",
1625
+ "content",
1626
+ "input",
1627
+ "output",
1628
+ "instructions",
1629
+ "other"
1630
+ ];
1631
+ const useLargeStorage = largeDataColumns.includes(columnName);
1632
+ const isIndexed = !!columnDef.primaryKey;
1633
+ const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
1279
1634
  const nullable = columnDef.nullable === false ? "NOT NULL" : "";
1280
1635
  const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
1281
1636
  const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
@@ -1288,7 +1643,7 @@ ${columns}
1288
1643
  } catch (error$1) {
1289
1644
  throw new error.MastraError(
1290
1645
  {
1291
- id: "MASTRA_STORAGE_MSSQL_STORE_ALTER_TABLE_FAILED",
1646
+ id: storage.createStorageErrorId("MSSQL", "ALTER_TABLE", "FAILED"),
1292
1647
  domain: error.ErrorDomain.STORAGE,
1293
1648
  category: error.ErrorCategory.THIRD_PARTY,
1294
1649
  details: {
@@ -1303,13 +1658,17 @@ ${columns}
1303
1658
  try {
1304
1659
  const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
1305
1660
  const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
1306
- const values = keyEntries.map(([_, value]) => value);
1307
- const sql7 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
1661
+ const sql5 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
1308
1662
  const request = this.pool.request();
1309
- values.forEach((value, i) => {
1310
- request.input(`param${i}`, value);
1663
+ keyEntries.forEach(([key, value], i) => {
1664
+ const preparedValue = this.prepareValue(value, key, tableName);
1665
+ if (preparedValue === null || preparedValue === void 0) {
1666
+ request.input(`param${i}`, this.getMssqlType(tableName, key), null);
1667
+ } else {
1668
+ request.input(`param${i}`, preparedValue);
1669
+ }
1311
1670
  });
1312
- const resultSet = await request.query(sql7);
1671
+ const resultSet = await request.query(sql5);
1313
1672
  const result = resultSet.recordset[0] || null;
1314
1673
  if (!result) {
1315
1674
  return null;
@@ -1325,7 +1684,7 @@ ${columns}
1325
1684
  } catch (error$1) {
1326
1685
  throw new error.MastraError(
1327
1686
  {
1328
- id: "MASTRA_STORAGE_MSSQL_STORE_LOAD_FAILED",
1687
+ id: storage.createStorageErrorId("MSSQL", "LOAD", "FAILED"),
1329
1688
  domain: error.ErrorDomain.STORAGE,
1330
1689
  category: error.ErrorCategory.THIRD_PARTY,
1331
1690
  details: {
@@ -1341,14 +1700,14 @@ ${columns}
1341
1700
  try {
1342
1701
  await transaction.begin();
1343
1702
  for (const record of records) {
1344
- await this.insert({ tableName, record });
1703
+ await this.insert({ tableName, record, transaction });
1345
1704
  }
1346
1705
  await transaction.commit();
1347
1706
  } catch (error$1) {
1348
1707
  await transaction.rollback();
1349
1708
  throw new error.MastraError(
1350
1709
  {
1351
- id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
1710
+ id: storage.createStorageErrorId("MSSQL", "BATCH_INSERT", "FAILED"),
1352
1711
  domain: error.ErrorDomain.STORAGE,
1353
1712
  category: error.ErrorCategory.THIRD_PARTY,
1354
1713
  details: {
@@ -1367,7 +1726,7 @@ ${columns}
1367
1726
  } catch (error$1) {
1368
1727
  throw new error.MastraError(
1369
1728
  {
1370
- id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
1729
+ id: storage.createStorageErrorId("MSSQL", "DROP_TABLE", "FAILED"),
1371
1730
  domain: error.ErrorDomain.STORAGE,
1372
1731
  category: error.ErrorCategory.THIRD_PARTY,
1373
1732
  details: {
@@ -1378,29 +1737,568 @@ ${columns}
1378
1737
  );
1379
1738
  }
1380
1739
  }
1381
- };
1382
- function parseJSON(jsonString) {
1383
- try {
1384
- return JSON.parse(jsonString);
1385
- } catch {
1386
- return jsonString;
1740
+ /**
1741
+ * Prepares a value for database operations, handling Date objects and JSON serialization
1742
+ */
1743
+ prepareValue(value, columnName, tableName) {
1744
+ if (value === null || value === void 0) {
1745
+ return value;
1746
+ }
1747
+ if (value instanceof Date) {
1748
+ return value;
1749
+ }
1750
+ const schema = storage.TABLE_SCHEMAS[tableName];
1751
+ const columnSchema = schema?.[columnName];
1752
+ if (columnSchema?.type === "boolean") {
1753
+ return value ? 1 : 0;
1754
+ }
1755
+ if (columnSchema?.type === "jsonb") {
1756
+ if (typeof value === "string") {
1757
+ const trimmed = value.trim();
1758
+ if (trimmed.length > 0) {
1759
+ try {
1760
+ JSON.parse(trimmed);
1761
+ return trimmed;
1762
+ } catch {
1763
+ }
1764
+ }
1765
+ return JSON.stringify(value);
1766
+ }
1767
+ if (typeof value === "bigint") {
1768
+ return value.toString();
1769
+ }
1770
+ return JSON.stringify(value);
1771
+ }
1772
+ if (typeof value === "object") {
1773
+ return JSON.stringify(value);
1774
+ }
1775
+ return value;
1387
1776
  }
1388
- }
1777
+ /**
1778
+ * Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
1779
+ */
1780
+ getMssqlType(tableName, columnName) {
1781
+ const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
1782
+ switch (col?.type) {
1783
+ case "text":
1784
+ return sql3__default.default.NVarChar;
1785
+ case "timestamp":
1786
+ return sql3__default.default.DateTime2;
1787
+ case "uuid":
1788
+ return sql3__default.default.UniqueIdentifier;
1789
+ case "jsonb":
1790
+ return sql3__default.default.NVarChar;
1791
+ case "integer":
1792
+ return sql3__default.default.Int;
1793
+ case "bigint":
1794
+ return sql3__default.default.BigInt;
1795
+ case "float":
1796
+ return sql3__default.default.Float;
1797
+ case "boolean":
1798
+ return sql3__default.default.Bit;
1799
+ default:
1800
+ return sql3__default.default.NVarChar;
1801
+ }
1802
+ }
1803
+ /**
1804
+ * Update a single record in the database
1805
+ */
1806
+ async update({
1807
+ tableName,
1808
+ keys,
1809
+ data,
1810
+ transaction
1811
+ }) {
1812
+ try {
1813
+ if (!data || Object.keys(data).length === 0) {
1814
+ throw new error.MastraError({
1815
+ id: storage.createStorageErrorId("MSSQL", "UPDATE", "EMPTY_DATA"),
1816
+ domain: error.ErrorDomain.STORAGE,
1817
+ category: error.ErrorCategory.USER,
1818
+ text: "Cannot update with empty data payload"
1819
+ });
1820
+ }
1821
+ if (!keys || Object.keys(keys).length === 0) {
1822
+ throw new error.MastraError({
1823
+ id: storage.createStorageErrorId("MSSQL", "UPDATE", "EMPTY_KEYS"),
1824
+ domain: error.ErrorDomain.STORAGE,
1825
+ category: error.ErrorCategory.USER,
1826
+ text: "Cannot update without keys to identify records"
1827
+ });
1828
+ }
1829
+ const setClauses = [];
1830
+ const request = transaction ? transaction.request() : this.pool.request();
1831
+ let paramIndex = 0;
1832
+ Object.entries(data).forEach(([key, value]) => {
1833
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1834
+ const paramName = `set${paramIndex++}`;
1835
+ setClauses.push(`[${parsedKey}] = @${paramName}`);
1836
+ const preparedValue = this.prepareValue(value, key, tableName);
1837
+ if (preparedValue === null || preparedValue === void 0) {
1838
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1839
+ } else {
1840
+ request.input(paramName, preparedValue);
1841
+ }
1842
+ });
1843
+ const whereConditions = [];
1844
+ Object.entries(keys).forEach(([key, value]) => {
1845
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1846
+ const paramName = `where${paramIndex++}`;
1847
+ whereConditions.push(`[${parsedKey}] = @${paramName}`);
1848
+ const preparedValue = this.prepareValue(value, key, tableName);
1849
+ if (preparedValue === null || preparedValue === void 0) {
1850
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1851
+ } else {
1852
+ request.input(paramName, preparedValue);
1853
+ }
1854
+ });
1855
+ const tableName_ = getTableName({
1856
+ indexName: tableName,
1857
+ schemaName: getSchemaName(this.schemaName)
1858
+ });
1859
+ const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
1860
+ await request.query(updateSql);
1861
+ } catch (error$1) {
1862
+ throw new error.MastraError(
1863
+ {
1864
+ id: storage.createStorageErrorId("MSSQL", "UPDATE", "FAILED"),
1865
+ domain: error.ErrorDomain.STORAGE,
1866
+ category: error.ErrorCategory.THIRD_PARTY,
1867
+ details: {
1868
+ tableName
1869
+ }
1870
+ },
1871
+ error$1
1872
+ );
1873
+ }
1874
+ }
1875
+ /**
1876
+ * Update multiple records in a single batch transaction
1877
+ */
1878
+ async batchUpdate({
1879
+ tableName,
1880
+ updates
1881
+ }) {
1882
+ const transaction = this.pool.transaction();
1883
+ try {
1884
+ await transaction.begin();
1885
+ for (const { keys, data } of updates) {
1886
+ await this.update({ tableName, keys, data, transaction });
1887
+ }
1888
+ await transaction.commit();
1889
+ } catch (error$1) {
1890
+ await transaction.rollback();
1891
+ throw new error.MastraError(
1892
+ {
1893
+ id: storage.createStorageErrorId("MSSQL", "BATCH_UPDATE", "FAILED"),
1894
+ domain: error.ErrorDomain.STORAGE,
1895
+ category: error.ErrorCategory.THIRD_PARTY,
1896
+ details: {
1897
+ tableName,
1898
+ numberOfRecords: updates.length
1899
+ }
1900
+ },
1901
+ error$1
1902
+ );
1903
+ }
1904
+ }
1905
+ /**
1906
+ * Delete multiple records by keys
1907
+ */
1908
+ async batchDelete({ tableName, keys }) {
1909
+ if (keys.length === 0) {
1910
+ return;
1911
+ }
1912
+ const tableName_ = getTableName({
1913
+ indexName: tableName,
1914
+ schemaName: getSchemaName(this.schemaName)
1915
+ });
1916
+ const transaction = this.pool.transaction();
1917
+ try {
1918
+ await transaction.begin();
1919
+ for (const keySet of keys) {
1920
+ const conditions = [];
1921
+ const request = transaction.request();
1922
+ let paramIndex = 0;
1923
+ Object.entries(keySet).forEach(([key, value]) => {
1924
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1925
+ const paramName = `p${paramIndex++}`;
1926
+ conditions.push(`[${parsedKey}] = @${paramName}`);
1927
+ const preparedValue = this.prepareValue(value, key, tableName);
1928
+ if (preparedValue === null || preparedValue === void 0) {
1929
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1930
+ } else {
1931
+ request.input(paramName, preparedValue);
1932
+ }
1933
+ });
1934
+ const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
1935
+ await request.query(deleteSql);
1936
+ }
1937
+ await transaction.commit();
1938
+ } catch (error$1) {
1939
+ await transaction.rollback();
1940
+ throw new error.MastraError(
1941
+ {
1942
+ id: storage.createStorageErrorId("MSSQL", "BATCH_DELETE", "FAILED"),
1943
+ domain: error.ErrorDomain.STORAGE,
1944
+ category: error.ErrorCategory.THIRD_PARTY,
1945
+ details: {
1946
+ tableName,
1947
+ numberOfRecords: keys.length
1948
+ }
1949
+ },
1950
+ error$1
1951
+ );
1952
+ }
1953
+ }
1954
+ /**
1955
+ * Create a new index on a table
1956
+ */
1957
+ async createIndex(options) {
1958
+ try {
1959
+ const { name, table, columns, unique = false, where } = options;
1960
+ const schemaName = this.schemaName || "dbo";
1961
+ const fullTableName = getTableName({
1962
+ indexName: table,
1963
+ schemaName: getSchemaName(this.schemaName)
1964
+ });
1965
+ const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
1966
+ const checkRequest = this.pool.request();
1967
+ checkRequest.input("indexName", indexNameSafe);
1968
+ checkRequest.input("schemaName", schemaName);
1969
+ checkRequest.input("tableName", table);
1970
+ const indexExists = await checkRequest.query(`
1971
+ SELECT 1 as found
1972
+ FROM sys.indexes i
1973
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
1974
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
1975
+ WHERE i.name = @indexName
1976
+ AND s.name = @schemaName
1977
+ AND t.name = @tableName
1978
+ `);
1979
+ if (indexExists.recordset && indexExists.recordset.length > 0) {
1980
+ return;
1981
+ }
1982
+ const uniqueStr = unique ? "UNIQUE " : "";
1983
+ const columnsStr = columns.map((col) => {
1984
+ if (col.includes(" DESC") || col.includes(" ASC")) {
1985
+ const [colName, ...modifiers] = col.split(" ");
1986
+ if (!colName) {
1987
+ throw new Error(`Invalid column specification: ${col}`);
1988
+ }
1989
+ return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
1990
+ }
1991
+ return `[${utils.parseSqlIdentifier(col, "column name")}]`;
1992
+ }).join(", ");
1993
+ const whereStr = where ? ` WHERE ${where}` : "";
1994
+ const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
1995
+ await this.pool.request().query(createIndexSql);
1996
+ } catch (error$1) {
1997
+ throw new error.MastraError(
1998
+ {
1999
+ id: storage.createStorageErrorId("MSSQL", "INDEX_CREATE", "FAILED"),
2000
+ domain: error.ErrorDomain.STORAGE,
2001
+ category: error.ErrorCategory.THIRD_PARTY,
2002
+ details: {
2003
+ indexName: options.name,
2004
+ tableName: options.table
2005
+ }
2006
+ },
2007
+ error$1
2008
+ );
2009
+ }
2010
+ }
2011
+ /**
2012
+ * Drop an existing index
2013
+ */
2014
+ async dropIndex(indexName) {
2015
+ try {
2016
+ const schemaName = this.schemaName || "dbo";
2017
+ const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
2018
+ const checkRequest = this.pool.request();
2019
+ checkRequest.input("indexName", indexNameSafe);
2020
+ checkRequest.input("schemaName", schemaName);
2021
+ const result = await checkRequest.query(`
2022
+ SELECT t.name as table_name
2023
+ FROM sys.indexes i
2024
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
2025
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
2026
+ WHERE i.name = @indexName
2027
+ AND s.name = @schemaName
2028
+ `);
2029
+ if (!result.recordset || result.recordset.length === 0) {
2030
+ return;
2031
+ }
2032
+ if (result.recordset.length > 1) {
2033
+ const tables = result.recordset.map((r) => r.table_name).join(", ");
2034
+ throw new error.MastraError({
2035
+ id: storage.createStorageErrorId("MSSQL", "INDEX", "AMBIGUOUS"),
2036
+ domain: error.ErrorDomain.STORAGE,
2037
+ category: error.ErrorCategory.USER,
2038
+ text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
2039
+ });
2040
+ }
2041
+ const tableName = result.recordset[0].table_name;
2042
+ const fullTableName = getTableName({
2043
+ indexName: tableName,
2044
+ schemaName: getSchemaName(this.schemaName)
2045
+ });
2046
+ const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
2047
+ await this.pool.request().query(dropSql);
2048
+ } catch (error$1) {
2049
+ throw new error.MastraError(
2050
+ {
2051
+ id: storage.createStorageErrorId("MSSQL", "INDEX_DROP", "FAILED"),
2052
+ domain: error.ErrorDomain.STORAGE,
2053
+ category: error.ErrorCategory.THIRD_PARTY,
2054
+ details: {
2055
+ indexName
2056
+ }
2057
+ },
2058
+ error$1
2059
+ );
2060
+ }
2061
+ }
2062
+ /**
2063
+ * List indexes for a specific table or all tables
2064
+ */
2065
+ async listIndexes(tableName) {
2066
+ try {
2067
+ const schemaName = this.schemaName || "dbo";
2068
+ let query;
2069
+ const request = this.pool.request();
2070
+ request.input("schemaName", schemaName);
2071
+ if (tableName) {
2072
+ query = `
2073
+ SELECT
2074
+ i.name as name,
2075
+ o.name as [table],
2076
+ i.is_unique as is_unique,
2077
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2078
+ FROM sys.indexes i
2079
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2080
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2081
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2082
+ WHERE sch.name = @schemaName
2083
+ AND o.name = @tableName
2084
+ AND i.name IS NOT NULL
2085
+ GROUP BY i.name, o.name, i.is_unique
2086
+ `;
2087
+ request.input("tableName", tableName);
2088
+ } else {
2089
+ query = `
2090
+ SELECT
2091
+ i.name as name,
2092
+ o.name as [table],
2093
+ i.is_unique as is_unique,
2094
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2095
+ FROM sys.indexes i
2096
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2097
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2098
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2099
+ WHERE sch.name = @schemaName
2100
+ AND i.name IS NOT NULL
2101
+ GROUP BY i.name, o.name, i.is_unique
2102
+ `;
2103
+ }
2104
+ const result = await request.query(query);
2105
+ const indexes = [];
2106
+ for (const row of result.recordset) {
2107
+ const colRequest = this.pool.request();
2108
+ colRequest.input("indexName", row.name);
2109
+ colRequest.input("schemaName", schemaName);
2110
+ const colResult = await colRequest.query(`
2111
+ SELECT c.name as column_name
2112
+ FROM sys.indexes i
2113
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2114
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2115
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2116
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2117
+ WHERE i.name = @indexName
2118
+ AND s.name = @schemaName
2119
+ ORDER BY ic.key_ordinal
2120
+ `);
2121
+ indexes.push({
2122
+ name: row.name,
2123
+ table: row.table,
2124
+ columns: colResult.recordset.map((c) => c.column_name),
2125
+ unique: row.is_unique || false,
2126
+ size: row.size || "0 MB",
2127
+ definition: ""
2128
+ // MSSQL doesn't store definition like PG
2129
+ });
2130
+ }
2131
+ return indexes;
2132
+ } catch (error$1) {
2133
+ throw new error.MastraError(
2134
+ {
2135
+ id: storage.createStorageErrorId("MSSQL", "INDEX_LIST", "FAILED"),
2136
+ domain: error.ErrorDomain.STORAGE,
2137
+ category: error.ErrorCategory.THIRD_PARTY,
2138
+ details: tableName ? {
2139
+ tableName
2140
+ } : {}
2141
+ },
2142
+ error$1
2143
+ );
2144
+ }
2145
+ }
2146
+ /**
2147
+ * Get detailed statistics for a specific index
2148
+ */
2149
+ async describeIndex(indexName) {
2150
+ try {
2151
+ const schemaName = this.schemaName || "dbo";
2152
+ const request = this.pool.request();
2153
+ request.input("indexName", indexName);
2154
+ request.input("schemaName", schemaName);
2155
+ const query = `
2156
+ SELECT
2157
+ i.name as name,
2158
+ o.name as [table],
2159
+ i.is_unique as is_unique,
2160
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
2161
+ i.type_desc as method,
2162
+ ISNULL(us.user_scans, 0) as scans,
2163
+ ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
2164
+ ISNULL(us.user_lookups, 0) as tuples_fetched
2165
+ FROM sys.indexes i
2166
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2167
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2168
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2169
+ LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
2170
+ WHERE i.name = @indexName
2171
+ AND sch.name = @schemaName
2172
+ GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
2173
+ `;
2174
+ const result = await request.query(query);
2175
+ if (!result.recordset || result.recordset.length === 0) {
2176
+ throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
2177
+ }
2178
+ const row = result.recordset[0];
2179
+ const colRequest = this.pool.request();
2180
+ colRequest.input("indexName", indexName);
2181
+ colRequest.input("schemaName", schemaName);
2182
+ const colResult = await colRequest.query(`
2183
+ SELECT c.name as column_name
2184
+ FROM sys.indexes i
2185
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2186
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2187
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2188
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2189
+ WHERE i.name = @indexName
2190
+ AND s.name = @schemaName
2191
+ ORDER BY ic.key_ordinal
2192
+ `);
2193
+ return {
2194
+ name: row.name,
2195
+ table: row.table,
2196
+ columns: colResult.recordset.map((c) => c.column_name),
2197
+ unique: row.is_unique || false,
2198
+ size: row.size || "0 MB",
2199
+ definition: "",
2200
+ method: row.method?.toLowerCase() || "nonclustered",
2201
+ scans: Number(row.scans) || 0,
2202
+ tuples_read: Number(row.tuples_read) || 0,
2203
+ tuples_fetched: Number(row.tuples_fetched) || 0
2204
+ };
2205
+ } catch (error$1) {
2206
+ throw new error.MastraError(
2207
+ {
2208
+ id: storage.createStorageErrorId("MSSQL", "INDEX_DESCRIBE", "FAILED"),
2209
+ domain: error.ErrorDomain.STORAGE,
2210
+ category: error.ErrorCategory.THIRD_PARTY,
2211
+ details: {
2212
+ indexName
2213
+ }
2214
+ },
2215
+ error$1
2216
+ );
2217
+ }
2218
+ }
2219
+ /**
2220
+ * Returns definitions for automatic performance indexes
2221
+ * IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
2222
+ * NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
2223
+ */
2224
+ getAutomaticIndexDefinitions() {
2225
+ const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
2226
+ return [
2227
+ // Composite indexes for optimal filtering + sorting performance
2228
+ // NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
2229
+ {
2230
+ name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
2231
+ table: storage.TABLE_THREADS,
2232
+ columns: ["resourceId", "seq_id DESC"]
2233
+ },
2234
+ {
2235
+ name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
2236
+ table: storage.TABLE_MESSAGES,
2237
+ columns: ["thread_id", "seq_id DESC"]
2238
+ },
2239
+ {
2240
+ name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
2241
+ table: storage.TABLE_TRACES,
2242
+ columns: ["name", "seq_id DESC"]
2243
+ },
2244
+ {
2245
+ name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
2246
+ table: storage.TABLE_SCORERS,
2247
+ columns: ["traceId", "spanId", "seq_id DESC"]
2248
+ },
2249
+ // Spans indexes for optimal trace querying
2250
+ {
2251
+ name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
2252
+ table: storage.TABLE_SPANS,
2253
+ columns: ["traceId", "startedAt DESC"]
2254
+ },
2255
+ {
2256
+ name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
2257
+ table: storage.TABLE_SPANS,
2258
+ columns: ["parentSpanId", "startedAt DESC"]
2259
+ },
2260
+ {
2261
+ name: `${schemaPrefix}mastra_ai_spans_name_idx`,
2262
+ table: storage.TABLE_SPANS,
2263
+ columns: ["name"]
2264
+ },
2265
+ {
2266
+ name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
2267
+ table: storage.TABLE_SPANS,
2268
+ columns: ["spanType", "startedAt DESC"]
2269
+ }
2270
+ ];
2271
+ }
2272
+ /**
2273
+ * Creates automatic indexes for optimal query performance
2274
+ * Uses getAutomaticIndexDefinitions() to determine which indexes to create
2275
+ */
2276
+ async createAutomaticIndexes() {
2277
+ try {
2278
+ const indexes = this.getAutomaticIndexDefinitions();
2279
+ for (const indexOptions of indexes) {
2280
+ try {
2281
+ await this.createIndex(indexOptions);
2282
+ } catch (error) {
2283
+ this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
2284
+ }
2285
+ }
2286
+ } catch (error$1) {
2287
+ throw new error.MastraError(
2288
+ {
2289
+ id: storage.createStorageErrorId("MSSQL", "CREATE_PERFORMANCE_INDEXES", "FAILED"),
2290
+ domain: error.ErrorDomain.STORAGE,
2291
+ category: error.ErrorCategory.THIRD_PARTY
2292
+ },
2293
+ error$1
2294
+ );
2295
+ }
2296
+ }
2297
+ };
1389
2298
  function transformScoreRow(row) {
1390
- return {
1391
- ...row,
1392
- input: parseJSON(row.input),
1393
- scorer: parseJSON(row.scorer),
1394
- preprocessStepResult: parseJSON(row.preprocessStepResult),
1395
- analyzeStepResult: parseJSON(row.analyzeStepResult),
1396
- metadata: parseJSON(row.metadata),
1397
- output: parseJSON(row.output),
1398
- additionalContext: parseJSON(row.additionalContext),
1399
- runtimeContext: parseJSON(row.runtimeContext),
1400
- entity: parseJSON(row.entity),
1401
- createdAt: row.createdAt,
1402
- updatedAt: row.updatedAt
1403
- };
2299
+ return storage.transformScoreRow(row, {
2300
+ convertTimestamps: true
2301
+ });
1404
2302
  }
1405
2303
  var ScoresMSSQL = class extends storage.ScoresStorage {
1406
2304
  pool;
@@ -1430,7 +2328,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1430
2328
  } catch (error$1) {
1431
2329
  throw new error.MastraError(
1432
2330
  {
1433
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORE_BY_ID_FAILED",
2331
+ id: storage.createStorageErrorId("MSSQL", "GET_SCORE_BY_ID", "FAILED"),
1434
2332
  domain: error.ErrorDomain.STORAGE,
1435
2333
  category: error.ErrorCategory.THIRD_PARTY,
1436
2334
  details: { id }
@@ -1438,10 +2336,31 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1438
2336
  error$1
1439
2337
  );
1440
2338
  }
1441
- }
1442
- async saveScore(score) {
2339
+ }
2340
+ async saveScore(score) {
2341
+ let validatedScore;
2342
+ try {
2343
+ validatedScore = evals.saveScorePayloadSchema.parse(score);
2344
+ } catch (error$1) {
2345
+ throw new error.MastraError(
2346
+ {
2347
+ id: storage.createStorageErrorId("MSSQL", "SAVE_SCORE", "VALIDATION_FAILED"),
2348
+ domain: error.ErrorDomain.STORAGE,
2349
+ category: error.ErrorCategory.USER,
2350
+ details: {
2351
+ scorer: score.scorer?.id ?? "unknown",
2352
+ entityId: score.entityId ?? "unknown",
2353
+ entityType: score.entityType ?? "unknown",
2354
+ traceId: score.traceId ?? "",
2355
+ spanId: score.spanId ?? ""
2356
+ }
2357
+ },
2358
+ error$1
2359
+ );
2360
+ }
1443
2361
  try {
1444
2362
  const scoreId = crypto.randomUUID();
2363
+ const now = /* @__PURE__ */ new Date();
1445
2364
  const {
1446
2365
  scorer,
1447
2366
  preprocessStepResult,
@@ -1450,34 +2369,33 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1450
2369
  input,
1451
2370
  output,
1452
2371
  additionalContext,
1453
- runtimeContext,
2372
+ requestContext,
1454
2373
  entity,
1455
2374
  ...rest
1456
- } = score;
2375
+ } = validatedScore;
1457
2376
  await this.operations.insert({
1458
2377
  tableName: storage.TABLE_SCORERS,
1459
2378
  record: {
1460
2379
  id: scoreId,
1461
2380
  ...rest,
1462
- input: JSON.stringify(input) || "",
1463
- output: JSON.stringify(output) || "",
1464
- preprocessStepResult: preprocessStepResult ? JSON.stringify(preprocessStepResult) : null,
1465
- analyzeStepResult: analyzeStepResult ? JSON.stringify(analyzeStepResult) : null,
1466
- metadata: metadata ? JSON.stringify(metadata) : null,
1467
- additionalContext: additionalContext ? JSON.stringify(additionalContext) : null,
1468
- runtimeContext: runtimeContext ? JSON.stringify(runtimeContext) : null,
1469
- entity: entity ? JSON.stringify(entity) : null,
1470
- scorer: scorer ? JSON.stringify(scorer) : null,
1471
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1472
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2381
+ input: input || "",
2382
+ output: output || "",
2383
+ preprocessStepResult: preprocessStepResult || null,
2384
+ analyzeStepResult: analyzeStepResult || null,
2385
+ metadata: metadata || null,
2386
+ additionalContext: additionalContext || null,
2387
+ requestContext: requestContext || null,
2388
+ entity: entity || null,
2389
+ scorer: scorer || null,
2390
+ createdAt: now.toISOString(),
2391
+ updatedAt: now.toISOString()
1473
2392
  }
1474
2393
  });
1475
- const scoreFromDb = await this.getScoreById({ id: scoreId });
1476
- return { score: scoreFromDb };
2394
+ return { score: { ...validatedScore, id: scoreId, createdAt: now, updatedAt: now } };
1477
2395
  } catch (error$1) {
1478
2396
  throw new error.MastraError(
1479
2397
  {
1480
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_FAILED",
2398
+ id: storage.createStorageErrorId("MSSQL", "SAVE_SCORE", "FAILED"),
1481
2399
  domain: error.ErrorDomain.STORAGE,
1482
2400
  category: error.ErrorCategory.THIRD_PARTY
1483
2401
  },
@@ -1485,48 +2403,77 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1485
2403
  );
1486
2404
  }
1487
2405
  }
1488
- async getScoresByScorerId({
2406
+ async listScoresByScorerId({
1489
2407
  scorerId,
1490
- pagination
2408
+ pagination,
2409
+ entityId,
2410
+ entityType,
2411
+ source
1491
2412
  }) {
1492
2413
  try {
1493
- const request = this.pool.request();
1494
- request.input("p1", scorerId);
1495
- const totalResult = await request.query(
1496
- `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [scorerId] = @p1`
1497
- );
2414
+ const conditions = ["[scorerId] = @p1"];
2415
+ const params = { p1: scorerId };
2416
+ let paramIndex = 2;
2417
+ if (entityId) {
2418
+ conditions.push(`[entityId] = @p${paramIndex}`);
2419
+ params[`p${paramIndex}`] = entityId;
2420
+ paramIndex++;
2421
+ }
2422
+ if (entityType) {
2423
+ conditions.push(`[entityType] = @p${paramIndex}`);
2424
+ params[`p${paramIndex}`] = entityType;
2425
+ paramIndex++;
2426
+ }
2427
+ if (source) {
2428
+ conditions.push(`[source] = @p${paramIndex}`);
2429
+ params[`p${paramIndex}`] = source;
2430
+ paramIndex++;
2431
+ }
2432
+ const whereClause = conditions.join(" AND ");
2433
+ const tableName = getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
2434
+ const countRequest = this.pool.request();
2435
+ Object.entries(params).forEach(([key, value]) => {
2436
+ countRequest.input(key, value);
2437
+ });
2438
+ const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
1498
2439
  const total = totalResult.recordset[0]?.count || 0;
2440
+ const { page, perPage: perPageInput } = pagination;
1499
2441
  if (total === 0) {
1500
2442
  return {
1501
2443
  pagination: {
1502
2444
  total: 0,
1503
- page: pagination.page,
1504
- perPage: pagination.perPage,
2445
+ page,
2446
+ perPage: perPageInput,
1505
2447
  hasMore: false
1506
2448
  },
1507
2449
  scores: []
1508
2450
  };
1509
2451
  }
2452
+ const perPage = storage.normalizePerPage(perPageInput, 100);
2453
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2454
+ const limitValue = perPageInput === false ? total : perPage;
2455
+ const end = perPageInput === false ? total : start + perPage;
1510
2456
  const dataRequest = this.pool.request();
1511
- dataRequest.input("p1", scorerId);
1512
- dataRequest.input("p2", pagination.perPage);
1513
- dataRequest.input("p3", pagination.page * pagination.perPage);
1514
- const result = await dataRequest.query(
1515
- `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`
1516
- );
2457
+ Object.entries(params).forEach(([key, value]) => {
2458
+ dataRequest.input(key, value);
2459
+ });
2460
+ dataRequest.input("perPage", limitValue);
2461
+ dataRequest.input("offset", start);
2462
+ const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
2463
+ const result = await dataRequest.query(dataQuery);
1517
2464
  return {
1518
2465
  pagination: {
1519
2466
  total: Number(total),
1520
- page: pagination.page,
1521
- perPage: pagination.perPage,
1522
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
2467
+ page,
2468
+ perPage: perPageForResponse,
2469
+ hasMore: end < total
1523
2470
  },
1524
2471
  scores: result.recordset.map((row) => transformScoreRow(row))
1525
2472
  };
1526
2473
  } catch (error$1) {
1527
2474
  throw new error.MastraError(
1528
2475
  {
1529
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
2476
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
1530
2477
  domain: error.ErrorDomain.STORAGE,
1531
2478
  category: error.ErrorCategory.THIRD_PARTY,
1532
2479
  details: { scorerId }
@@ -1535,7 +2482,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1535
2482
  );
1536
2483
  }
1537
2484
  }
1538
- async getScoresByRunId({
2485
+ async listScoresByRunId({
1539
2486
  runId,
1540
2487
  pagination
1541
2488
  }) {
@@ -1546,37 +2493,42 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1546
2493
  `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1`
1547
2494
  );
1548
2495
  const total = totalResult.recordset[0]?.count || 0;
2496
+ const { page, perPage: perPageInput } = pagination;
1549
2497
  if (total === 0) {
1550
2498
  return {
1551
2499
  pagination: {
1552
2500
  total: 0,
1553
- page: pagination.page,
1554
- perPage: pagination.perPage,
2501
+ page,
2502
+ perPage: perPageInput,
1555
2503
  hasMore: false
1556
2504
  },
1557
2505
  scores: []
1558
2506
  };
1559
2507
  }
2508
+ const perPage = storage.normalizePerPage(perPageInput, 100);
2509
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2510
+ const limitValue = perPageInput === false ? total : perPage;
2511
+ const end = perPageInput === false ? total : start + perPage;
1560
2512
  const dataRequest = this.pool.request();
1561
2513
  dataRequest.input("p1", runId);
1562
- dataRequest.input("p2", pagination.perPage);
1563
- dataRequest.input("p3", pagination.page * pagination.perPage);
2514
+ dataRequest.input("p2", limitValue);
2515
+ dataRequest.input("p3", start);
1564
2516
  const result = await dataRequest.query(
1565
2517
  `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1 ORDER BY [createdAt] DESC OFFSET @p3 ROWS FETCH NEXT @p2 ROWS ONLY`
1566
2518
  );
1567
2519
  return {
1568
2520
  pagination: {
1569
2521
  total: Number(total),
1570
- page: pagination.page,
1571
- perPage: pagination.perPage,
1572
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
2522
+ page,
2523
+ perPage: perPageForResponse,
2524
+ hasMore: end < total
1573
2525
  },
1574
2526
  scores: result.recordset.map((row) => transformScoreRow(row))
1575
2527
  };
1576
2528
  } catch (error$1) {
1577
2529
  throw new error.MastraError(
1578
2530
  {
1579
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_RUN_ID_FAILED",
2531
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_RUN_ID", "FAILED"),
1580
2532
  domain: error.ErrorDomain.STORAGE,
1581
2533
  category: error.ErrorCategory.THIRD_PARTY,
1582
2534
  details: { runId }
@@ -1585,7 +2537,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1585
2537
  );
1586
2538
  }
1587
2539
  }
1588
- async getScoresByEntityId({
2540
+ async listScoresByEntityId({
1589
2541
  entityId,
1590
2542
  entityType,
1591
2543
  pagination
@@ -1598,38 +2550,43 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1598
2550
  `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2`
1599
2551
  );
1600
2552
  const total = totalResult.recordset[0]?.count || 0;
2553
+ const { page, perPage: perPageInput } = pagination;
2554
+ const perPage = storage.normalizePerPage(perPageInput, 100);
2555
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1601
2556
  if (total === 0) {
1602
2557
  return {
1603
2558
  pagination: {
1604
2559
  total: 0,
1605
- page: pagination.page,
1606
- perPage: pagination.perPage,
2560
+ page,
2561
+ perPage: perPageForResponse,
1607
2562
  hasMore: false
1608
2563
  },
1609
2564
  scores: []
1610
2565
  };
1611
2566
  }
2567
+ const limitValue = perPageInput === false ? total : perPage;
2568
+ const end = perPageInput === false ? total : start + perPage;
1612
2569
  const dataRequest = this.pool.request();
1613
2570
  dataRequest.input("p1", entityId);
1614
2571
  dataRequest.input("p2", entityType);
1615
- dataRequest.input("p3", pagination.perPage);
1616
- dataRequest.input("p4", pagination.page * pagination.perPage);
2572
+ dataRequest.input("p3", limitValue);
2573
+ dataRequest.input("p4", start);
1617
2574
  const result = await dataRequest.query(
1618
2575
  `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
1619
2576
  );
1620
2577
  return {
1621
2578
  pagination: {
1622
2579
  total: Number(total),
1623
- page: pagination.page,
1624
- perPage: pagination.perPage,
1625
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
2580
+ page,
2581
+ perPage: perPageForResponse,
2582
+ hasMore: end < total
1626
2583
  },
1627
2584
  scores: result.recordset.map((row) => transformScoreRow(row))
1628
2585
  };
1629
2586
  } catch (error$1) {
1630
2587
  throw new error.MastraError(
1631
2588
  {
1632
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
2589
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
1633
2590
  domain: error.ErrorDomain.STORAGE,
1634
2591
  category: error.ErrorCategory.THIRD_PARTY,
1635
2592
  details: { entityId, entityType }
@@ -1638,8 +2595,66 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1638
2595
  );
1639
2596
  }
1640
2597
  }
2598
+ async listScoresBySpan({
2599
+ traceId,
2600
+ spanId,
2601
+ pagination
2602
+ }) {
2603
+ try {
2604
+ const request = this.pool.request();
2605
+ request.input("p1", traceId);
2606
+ request.input("p2", spanId);
2607
+ const totalResult = await request.query(
2608
+ `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
2609
+ );
2610
+ const total = totalResult.recordset[0]?.count || 0;
2611
+ const { page, perPage: perPageInput } = pagination;
2612
+ const perPage = storage.normalizePerPage(perPageInput, 100);
2613
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2614
+ if (total === 0) {
2615
+ return {
2616
+ pagination: {
2617
+ total: 0,
2618
+ page,
2619
+ perPage: perPageForResponse,
2620
+ hasMore: false
2621
+ },
2622
+ scores: []
2623
+ };
2624
+ }
2625
+ const limitValue = perPageInput === false ? total : perPage;
2626
+ const end = perPageInput === false ? total : start + perPage;
2627
+ const dataRequest = this.pool.request();
2628
+ dataRequest.input("p1", traceId);
2629
+ dataRequest.input("p2", spanId);
2630
+ dataRequest.input("p3", limitValue);
2631
+ dataRequest.input("p4", start);
2632
+ const result = await dataRequest.query(
2633
+ `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
2634
+ );
2635
+ return {
2636
+ pagination: {
2637
+ total: Number(total),
2638
+ page,
2639
+ perPage: perPageForResponse,
2640
+ hasMore: end < total
2641
+ },
2642
+ scores: result.recordset.map((row) => transformScoreRow(row))
2643
+ };
2644
+ } catch (error$1) {
2645
+ throw new error.MastraError(
2646
+ {
2647
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_SPAN", "FAILED"),
2648
+ domain: error.ErrorDomain.STORAGE,
2649
+ category: error.ErrorCategory.THIRD_PARTY,
2650
+ details: { traceId, spanId }
2651
+ },
2652
+ error$1
2653
+ );
2654
+ }
2655
+ }
1641
2656
  };
1642
- var TracesMSSQL = class extends storage.TracesStorage {
2657
+ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1643
2658
  pool;
1644
2659
  operations;
1645
2660
  schema;
@@ -1653,194 +2668,170 @@ var TracesMSSQL = class extends storage.TracesStorage {
1653
2668
  this.operations = operations;
1654
2669
  this.schema = schema;
1655
2670
  }
1656
- /** @deprecated use getTracesPaginated instead*/
1657
- async getTraces(args) {
1658
- if (args.fromDate || args.toDate) {
1659
- args.dateRange = {
1660
- start: args.fromDate,
1661
- end: args.toDate
1662
- };
2671
+ parseWorkflowRun(row) {
2672
+ let parsedSnapshot = row.snapshot;
2673
+ if (typeof parsedSnapshot === "string") {
2674
+ try {
2675
+ parsedSnapshot = JSON.parse(row.snapshot);
2676
+ } catch (e) {
2677
+ this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
2678
+ }
1663
2679
  }
1664
- const result = await this.getTracesPaginated(args);
1665
- return result.traces;
2680
+ return {
2681
+ workflowName: row.workflow_name,
2682
+ runId: row.run_id,
2683
+ snapshot: parsedSnapshot,
2684
+ createdAt: row.createdAt,
2685
+ updatedAt: row.updatedAt,
2686
+ resourceId: row.resourceId
2687
+ };
1666
2688
  }
1667
- async getTracesPaginated(args) {
1668
- const { name, scope, page = 0, perPage: perPageInput, attributes, filters, dateRange } = args;
1669
- const fromDate = dateRange?.start;
1670
- const toDate = dateRange?.end;
1671
- const perPage = perPageInput !== void 0 ? perPageInput : 100;
1672
- const currentOffset = page * perPage;
1673
- const paramMap = {};
1674
- const conditions = [];
1675
- let paramIndex = 1;
1676
- if (name) {
1677
- const paramName = `p${paramIndex++}`;
1678
- conditions.push(`[name] LIKE @${paramName}`);
1679
- paramMap[paramName] = `${name}%`;
1680
- }
1681
- if (scope) {
1682
- const paramName = `p${paramIndex++}`;
1683
- conditions.push(`[scope] = @${paramName}`);
1684
- paramMap[paramName] = scope;
1685
- }
1686
- if (attributes) {
1687
- Object.entries(attributes).forEach(([key, value]) => {
1688
- const parsedKey = utils.parseFieldKey(key);
1689
- const paramName = `p${paramIndex++}`;
1690
- conditions.push(`JSON_VALUE([attributes], '$.${parsedKey}') = @${paramName}`);
1691
- paramMap[paramName] = value;
1692
- });
1693
- }
1694
- if (filters) {
1695
- Object.entries(filters).forEach(([key, value]) => {
1696
- const parsedKey = utils.parseFieldKey(key);
1697
- const paramName = `p${paramIndex++}`;
1698
- conditions.push(`[${parsedKey}] = @${paramName}`);
1699
- paramMap[paramName] = value;
1700
- });
1701
- }
1702
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
1703
- const paramName = `p${paramIndex++}`;
1704
- conditions.push(`[createdAt] >= @${paramName}`);
1705
- paramMap[paramName] = fromDate.toISOString();
1706
- }
1707
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
1708
- const paramName = `p${paramIndex++}`;
1709
- conditions.push(`[createdAt] <= @${paramName}`);
1710
- paramMap[paramName] = toDate.toISOString();
1711
- }
1712
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1713
- const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
1714
- let total = 0;
2689
+ async updateWorkflowResults({
2690
+ workflowName,
2691
+ runId,
2692
+ stepId,
2693
+ result,
2694
+ requestContext
2695
+ }) {
2696
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2697
+ const transaction = this.pool.transaction();
1715
2698
  try {
1716
- const countRequest = this.pool.request();
1717
- Object.entries(paramMap).forEach(([key, value]) => {
1718
- if (value instanceof Date) {
1719
- countRequest.input(key, sql2__default.default.DateTime, value);
1720
- } else {
1721
- countRequest.input(key, value);
1722
- }
1723
- });
1724
- const countResult = await countRequest.query(countQuery);
1725
- total = parseInt(countResult.recordset[0].total, 10);
2699
+ await transaction.begin();
2700
+ const selectRequest = new sql3__default.default.Request(transaction);
2701
+ selectRequest.input("workflow_name", workflowName);
2702
+ selectRequest.input("run_id", runId);
2703
+ const existingSnapshotResult = await selectRequest.query(
2704
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
2705
+ );
2706
+ let snapshot;
2707
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
2708
+ snapshot = {
2709
+ context: {},
2710
+ activePaths: [],
2711
+ activeStepsPath: {},
2712
+ timestamp: Date.now(),
2713
+ suspendedPaths: {},
2714
+ resumeLabels: {},
2715
+ serializedStepGraph: [],
2716
+ status: "pending",
2717
+ value: {},
2718
+ waitingPaths: {},
2719
+ runId,
2720
+ requestContext: {}
2721
+ };
2722
+ } else {
2723
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
2724
+ snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2725
+ }
2726
+ snapshot.context[stepId] = result;
2727
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
2728
+ const upsertReq = new sql3__default.default.Request(transaction);
2729
+ upsertReq.input("workflow_name", workflowName);
2730
+ upsertReq.input("run_id", runId);
2731
+ upsertReq.input("snapshot", JSON.stringify(snapshot));
2732
+ upsertReq.input("createdAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
2733
+ upsertReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
2734
+ await upsertReq.query(
2735
+ `MERGE ${table} AS target
2736
+ USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
2737
+ ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
2738
+ WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
2739
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
2740
+ VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
2741
+ );
2742
+ await transaction.commit();
2743
+ return snapshot.context;
1726
2744
  } catch (error$1) {
2745
+ try {
2746
+ await transaction.rollback();
2747
+ } catch {
2748
+ }
1727
2749
  throw new error.MastraError(
1728
2750
  {
1729
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT",
2751
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
1730
2752
  domain: error.ErrorDomain.STORAGE,
1731
2753
  category: error.ErrorCategory.THIRD_PARTY,
1732
2754
  details: {
1733
- name: args.name ?? "",
1734
- scope: args.scope ?? ""
2755
+ workflowName,
2756
+ runId,
2757
+ stepId
1735
2758
  }
1736
2759
  },
1737
2760
  error$1
1738
2761
  );
1739
2762
  }
1740
- if (total === 0) {
1741
- return {
1742
- traces: [],
1743
- total: 0,
1744
- page,
1745
- perPage,
1746
- hasMore: false
1747
- };
1748
- }
1749
- const dataQuery = `SELECT * FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause} ORDER BY [seq_id] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
1750
- const dataRequest = this.pool.request();
1751
- Object.entries(paramMap).forEach(([key, value]) => {
1752
- if (value instanceof Date) {
1753
- dataRequest.input(key, sql2__default.default.DateTime, value);
1754
- } else {
1755
- dataRequest.input(key, value);
1756
- }
1757
- });
1758
- dataRequest.input("offset", currentOffset);
1759
- dataRequest.input("limit", perPage);
2763
+ }
2764
+ async updateWorkflowState({
2765
+ workflowName,
2766
+ runId,
2767
+ opts
2768
+ }) {
2769
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2770
+ const transaction = this.pool.transaction();
1760
2771
  try {
1761
- const rowsResult = await dataRequest.query(dataQuery);
1762
- const rows = rowsResult.recordset;
1763
- const traces = rows.map((row) => ({
1764
- id: row.id,
1765
- parentSpanId: row.parentSpanId,
1766
- traceId: row.traceId,
1767
- name: row.name,
1768
- scope: row.scope,
1769
- kind: row.kind,
1770
- status: JSON.parse(row.status),
1771
- events: JSON.parse(row.events),
1772
- links: JSON.parse(row.links),
1773
- attributes: JSON.parse(row.attributes),
1774
- startTime: row.startTime,
1775
- endTime: row.endTime,
1776
- other: row.other,
1777
- createdAt: row.createdAt
1778
- }));
1779
- return {
1780
- traces,
1781
- total,
1782
- page,
1783
- perPage,
1784
- hasMore: currentOffset + traces.length < total
1785
- };
2772
+ await transaction.begin();
2773
+ const selectRequest = new sql3__default.default.Request(transaction);
2774
+ selectRequest.input("workflow_name", workflowName);
2775
+ selectRequest.input("run_id", runId);
2776
+ const existingSnapshotResult = await selectRequest.query(
2777
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
2778
+ );
2779
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
2780
+ await transaction.rollback();
2781
+ return void 0;
2782
+ }
2783
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
2784
+ const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2785
+ if (!snapshot || !snapshot?.context) {
2786
+ await transaction.rollback();
2787
+ throw new error.MastraError(
2788
+ {
2789
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_STATE", "SNAPSHOT_NOT_FOUND"),
2790
+ domain: error.ErrorDomain.STORAGE,
2791
+ category: error.ErrorCategory.SYSTEM,
2792
+ details: {
2793
+ workflowName,
2794
+ runId
2795
+ }
2796
+ },
2797
+ new Error(`Snapshot not found for runId ${runId}`)
2798
+ );
2799
+ }
2800
+ const updatedSnapshot = { ...snapshot, ...opts };
2801
+ const updateRequest = new sql3__default.default.Request(transaction);
2802
+ updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
2803
+ updateRequest.input("workflow_name", workflowName);
2804
+ updateRequest.input("run_id", runId);
2805
+ updateRequest.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
2806
+ await updateRequest.query(
2807
+ `UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
2808
+ );
2809
+ await transaction.commit();
2810
+ return updatedSnapshot;
1786
2811
  } catch (error$1) {
2812
+ try {
2813
+ await transaction.rollback();
2814
+ } catch {
2815
+ }
2816
+ if (error$1 instanceof error.MastraError) throw error$1;
1787
2817
  throw new error.MastraError(
1788
2818
  {
1789
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES",
2819
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_STATE", "FAILED"),
1790
2820
  domain: error.ErrorDomain.STORAGE,
1791
2821
  category: error.ErrorCategory.THIRD_PARTY,
1792
2822
  details: {
1793
- name: args.name ?? "",
1794
- scope: args.scope ?? ""
2823
+ workflowName,
2824
+ runId
1795
2825
  }
1796
2826
  },
1797
2827
  error$1
1798
2828
  );
1799
2829
  }
1800
2830
  }
1801
- async batchTraceInsert({ records }) {
1802
- this.logger.debug("Batch inserting traces", { count: records.length });
1803
- await this.operations.batchInsert({
1804
- tableName: storage.TABLE_TRACES,
1805
- records
1806
- });
1807
- }
1808
- };
1809
- function parseWorkflowRun(row) {
1810
- let parsedSnapshot = row.snapshot;
1811
- if (typeof parsedSnapshot === "string") {
1812
- try {
1813
- parsedSnapshot = JSON.parse(row.snapshot);
1814
- } catch (e) {
1815
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1816
- }
1817
- }
1818
- return {
1819
- workflowName: row.workflow_name,
1820
- runId: row.run_id,
1821
- snapshot: parsedSnapshot,
1822
- createdAt: row.createdAt,
1823
- updatedAt: row.updatedAt,
1824
- resourceId: row.resourceId
1825
- };
1826
- }
1827
- var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1828
- pool;
1829
- operations;
1830
- schema;
1831
- constructor({
1832
- pool,
1833
- operations,
1834
- schema
1835
- }) {
1836
- super();
1837
- this.pool = pool;
1838
- this.operations = operations;
1839
- this.schema = schema;
1840
- }
1841
2831
  async persistWorkflowSnapshot({
1842
2832
  workflowName,
1843
2833
  runId,
2834
+ resourceId,
1844
2835
  snapshot
1845
2836
  }) {
1846
2837
  const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
@@ -1849,22 +2840,24 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1849
2840
  const request = this.pool.request();
1850
2841
  request.input("workflow_name", workflowName);
1851
2842
  request.input("run_id", runId);
2843
+ request.input("resourceId", resourceId);
1852
2844
  request.input("snapshot", JSON.stringify(snapshot));
1853
- request.input("createdAt", sql2__default.default.DateTime2, new Date(now));
1854
- request.input("updatedAt", sql2__default.default.DateTime2, new Date(now));
2845
+ request.input("createdAt", sql3__default.default.DateTime2, new Date(now));
2846
+ request.input("updatedAt", sql3__default.default.DateTime2, new Date(now));
1855
2847
  const mergeSql = `MERGE INTO ${table} AS target
1856
2848
  USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
1857
2849
  ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
1858
2850
  WHEN MATCHED THEN UPDATE SET
2851
+ resourceId = @resourceId,
1859
2852
  snapshot = @snapshot,
1860
2853
  [updatedAt] = @updatedAt
1861
- WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
1862
- VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
2854
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
2855
+ VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
1863
2856
  await request.query(mergeSql);
1864
2857
  } catch (error$1) {
1865
2858
  throw new error.MastraError(
1866
2859
  {
1867
- id: "MASTRA_STORAGE_MSSQL_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
2860
+ id: storage.createStorageErrorId("MSSQL", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
1868
2861
  domain: error.ErrorDomain.STORAGE,
1869
2862
  category: error.ErrorCategory.THIRD_PARTY,
1870
2863
  details: {
@@ -1895,7 +2888,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1895
2888
  } catch (error$1) {
1896
2889
  throw new error.MastraError(
1897
2890
  {
1898
- id: "MASTRA_STORAGE_MSSQL_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
2891
+ id: storage.createStorageErrorId("MSSQL", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
1899
2892
  domain: error.ErrorDomain.STORAGE,
1900
2893
  category: error.ErrorCategory.THIRD_PARTY,
1901
2894
  details: {
@@ -1931,11 +2924,11 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1931
2924
  if (!result.recordset || result.recordset.length === 0) {
1932
2925
  return null;
1933
2926
  }
1934
- return parseWorkflowRun(result.recordset[0]);
2927
+ return this.parseWorkflowRun(result.recordset[0]);
1935
2928
  } catch (error$1) {
1936
2929
  throw new error.MastraError(
1937
2930
  {
1938
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
2931
+ id: storage.createStorageErrorId("MSSQL", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1939
2932
  domain: error.ErrorDomain.STORAGE,
1940
2933
  category: error.ErrorCategory.THIRD_PARTY,
1941
2934
  details: {
@@ -1947,13 +2940,43 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1947
2940
  );
1948
2941
  }
1949
2942
  }
1950
- async getWorkflowRuns({
2943
+ async deleteWorkflowRunById({ runId, workflowName }) {
2944
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2945
+ const transaction = this.pool.transaction();
2946
+ try {
2947
+ await transaction.begin();
2948
+ const deleteRequest = new sql3__default.default.Request(transaction);
2949
+ deleteRequest.input("workflow_name", workflowName);
2950
+ deleteRequest.input("run_id", runId);
2951
+ await deleteRequest.query(`DELETE FROM ${table} WHERE workflow_name = @workflow_name AND run_id = @run_id`);
2952
+ await transaction.commit();
2953
+ } catch (error$1) {
2954
+ try {
2955
+ await transaction.rollback();
2956
+ } catch {
2957
+ }
2958
+ throw new error.MastraError(
2959
+ {
2960
+ id: storage.createStorageErrorId("MSSQL", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
2961
+ domain: error.ErrorDomain.STORAGE,
2962
+ category: error.ErrorCategory.THIRD_PARTY,
2963
+ details: {
2964
+ runId,
2965
+ workflowName
2966
+ }
2967
+ },
2968
+ error$1
2969
+ );
2970
+ }
2971
+ }
2972
+ async listWorkflowRuns({
1951
2973
  workflowName,
1952
2974
  fromDate,
1953
2975
  toDate,
1954
- limit,
1955
- offset,
1956
- resourceId
2976
+ page,
2977
+ perPage,
2978
+ resourceId,
2979
+ status
1957
2980
  } = {}) {
1958
2981
  try {
1959
2982
  const conditions = [];
@@ -1962,13 +2985,17 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1962
2985
  conditions.push(`[workflow_name] = @workflowName`);
1963
2986
  paramMap["workflowName"] = workflowName;
1964
2987
  }
2988
+ if (status) {
2989
+ conditions.push(`JSON_VALUE([snapshot], '$.status') = @status`);
2990
+ paramMap["status"] = status;
2991
+ }
1965
2992
  if (resourceId) {
1966
2993
  const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
1967
2994
  if (hasResourceId) {
1968
2995
  conditions.push(`[resourceId] = @resourceId`);
1969
2996
  paramMap["resourceId"] = resourceId;
1970
2997
  } else {
1971
- console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
2998
+ this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
1972
2999
  }
1973
3000
  }
1974
3001
  if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
@@ -1985,29 +3012,32 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1985
3012
  const request = this.pool.request();
1986
3013
  Object.entries(paramMap).forEach(([key, value]) => {
1987
3014
  if (value instanceof Date) {
1988
- request.input(key, sql2__default.default.DateTime, value);
3015
+ request.input(key, sql3__default.default.DateTime, value);
1989
3016
  } else {
1990
3017
  request.input(key, value);
1991
3018
  }
1992
3019
  });
1993
- if (limit !== void 0 && offset !== void 0) {
3020
+ const usePagination = typeof perPage === "number" && typeof page === "number";
3021
+ if (usePagination) {
1994
3022
  const countQuery = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
1995
3023
  const countResult = await request.query(countQuery);
1996
3024
  total = Number(countResult.recordset[0]?.count || 0);
1997
3025
  }
1998
3026
  let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY [seq_id] DESC`;
1999
- if (limit !== void 0 && offset !== void 0) {
2000
- query += ` OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
2001
- request.input("limit", limit);
3027
+ if (usePagination) {
3028
+ const normalizedPerPage = storage.normalizePerPage(perPage, Number.MAX_SAFE_INTEGER);
3029
+ const offset = page * normalizedPerPage;
3030
+ query += ` OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
3031
+ request.input("perPage", normalizedPerPage);
2002
3032
  request.input("offset", offset);
2003
3033
  }
2004
3034
  const result = await request.query(query);
2005
- const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
3035
+ const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
2006
3036
  return { runs, total: total || runs.length };
2007
3037
  } catch (error$1) {
2008
3038
  throw new error.MastraError(
2009
3039
  {
2010
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_WORKFLOW_RUNS_FAILED",
3040
+ id: storage.createStorageErrorId("MSSQL", "LIST_WORKFLOW_RUNS", "FAILED"),
2011
3041
  domain: error.ErrorDomain.STORAGE,
2012
3042
  category: error.ErrorCategory.THIRD_PARTY,
2013
3043
  details: {
@@ -2027,7 +3057,10 @@ var MSSQLStore = class extends storage.MastraStorage {
2027
3057
  isConnected = null;
2028
3058
  stores;
2029
3059
  constructor(config) {
2030
- super({ name: "MSSQLStore" });
3060
+ if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
3061
+ throw new Error("MSSQLStore: id must be provided and cannot be empty.");
3062
+ }
3063
+ super({ id: config.id, name: "MSSQLStore", disableInit: config.disableInit });
2031
3064
  try {
2032
3065
  if ("connectionString" in config) {
2033
3066
  if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
@@ -2042,7 +3075,7 @@ var MSSQLStore = class extends storage.MastraStorage {
2042
3075
  }
2043
3076
  }
2044
3077
  this.schema = config.schemaName || "dbo";
2045
- this.pool = "connectionString" in config ? new sql2__default.default.ConnectionPool(config.connectionString) : new sql2__default.default.ConnectionPool({
3078
+ this.pool = "connectionString" in config ? new sql3__default.default.ConnectionPool(config.connectionString) : new sql3__default.default.ConnectionPool({
2046
3079
  server: config.server,
2047
3080
  database: config.database,
2048
3081
  user: config.user,
@@ -2050,24 +3083,22 @@ var MSSQLStore = class extends storage.MastraStorage {
2050
3083
  port: config.port,
2051
3084
  options: config.options || { encrypt: true, trustServerCertificate: true }
2052
3085
  });
2053
- const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
2054
3086
  const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
2055
3087
  const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
2056
- const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
2057
3088
  const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
2058
3089
  const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
3090
+ const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
2059
3091
  this.stores = {
2060
3092
  operations,
2061
3093
  scores,
2062
- traces,
2063
3094
  workflows,
2064
- legacyEvals,
2065
- memory
3095
+ memory,
3096
+ observability
2066
3097
  };
2067
3098
  } catch (e) {
2068
3099
  throw new error.MastraError(
2069
3100
  {
2070
- id: "MASTRA_STORAGE_MSSQL_STORE_INITIALIZATION_FAILED",
3101
+ id: storage.createStorageErrorId("MSSQL", "INITIALIZATION", "FAILED"),
2071
3102
  domain: error.ErrorDomain.STORAGE,
2072
3103
  category: error.ErrorCategory.USER
2073
3104
  },
@@ -2082,11 +3113,16 @@ var MSSQLStore = class extends storage.MastraStorage {
2082
3113
  try {
2083
3114
  await this.isConnected;
2084
3115
  await super.init();
3116
+ try {
3117
+ await this.stores.operations.createAutomaticIndexes();
3118
+ } catch (indexError) {
3119
+ this.logger?.warn?.("Failed to create indexes:", indexError);
3120
+ }
2085
3121
  } catch (error$1) {
2086
3122
  this.isConnected = null;
2087
3123
  throw new error.MastraError(
2088
3124
  {
2089
- id: "MASTRA_STORAGE_MSSQL_STORE_INIT_FAILED",
3125
+ id: storage.createStorageErrorId("MSSQL", "INIT", "FAILED"),
2090
3126
  domain: error.ErrorDomain.STORAGE,
2091
3127
  category: error.ErrorCategory.THIRD_PARTY
2092
3128
  },
@@ -2108,28 +3144,12 @@ var MSSQLStore = class extends storage.MastraStorage {
2108
3144
  resourceWorkingMemory: true,
2109
3145
  hasColumn: true,
2110
3146
  createTable: true,
2111
- deleteMessages: true
3147
+ deleteMessages: true,
3148
+ listScoresBySpan: true,
3149
+ observabilityInstance: true,
3150
+ indexManagement: true
2112
3151
  };
2113
3152
  }
2114
- /** @deprecated use getEvals instead */
2115
- async getEvalsByAgentName(agentName, type) {
2116
- return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2117
- }
2118
- async getEvals(options = {}) {
2119
- return this.stores.legacyEvals.getEvals(options);
2120
- }
2121
- /**
2122
- * @deprecated use getTracesPaginated instead
2123
- */
2124
- async getTraces(args) {
2125
- return this.stores.traces.getTraces(args);
2126
- }
2127
- async getTracesPaginated(args) {
2128
- return this.stores.traces.getTracesPaginated(args);
2129
- }
2130
- async batchTraceInsert({ records }) {
2131
- return this.stores.traces.batchTraceInsert({ records });
2132
- }
2133
3153
  async createTable({
2134
3154
  tableName,
2135
3155
  schema
@@ -2164,15 +3184,6 @@ var MSSQLStore = class extends storage.MastraStorage {
2164
3184
  async getThreadById({ threadId }) {
2165
3185
  return this.stores.memory.getThreadById({ threadId });
2166
3186
  }
2167
- /**
2168
- * @deprecated use getThreadsByResourceIdPaginated instead
2169
- */
2170
- async getThreadsByResourceId(args) {
2171
- return this.stores.memory.getThreadsByResourceId(args);
2172
- }
2173
- async getThreadsByResourceIdPaginated(args) {
2174
- return this.stores.memory.getThreadsByResourceIdPaginated(args);
2175
- }
2176
3187
  async saveThread({ thread }) {
2177
3188
  return this.stores.memory.saveThread({ thread });
2178
3189
  }
@@ -2186,11 +3197,8 @@ var MSSQLStore = class extends storage.MastraStorage {
2186
3197
  async deleteThread({ threadId }) {
2187
3198
  return this.stores.memory.deleteThread({ threadId });
2188
3199
  }
2189
- async getMessages(args) {
2190
- return this.stores.memory.getMessages(args);
2191
- }
2192
- async getMessagesPaginated(args) {
2193
- return this.stores.memory.getMessagesPaginated(args);
3200
+ async listMessagesById({ messageIds }) {
3201
+ return this.stores.memory.listMessagesById({ messageIds });
2194
3202
  }
2195
3203
  async saveMessages(args) {
2196
3204
  return this.stores.memory.saveMessages(args);
@@ -2219,12 +3227,29 @@ var MSSQLStore = class extends storage.MastraStorage {
2219
3227
  /**
2220
3228
  * Workflows
2221
3229
  */
3230
+ async updateWorkflowResults({
3231
+ workflowName,
3232
+ runId,
3233
+ stepId,
3234
+ result,
3235
+ requestContext
3236
+ }) {
3237
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
3238
+ }
3239
+ async updateWorkflowState({
3240
+ workflowName,
3241
+ runId,
3242
+ opts
3243
+ }) {
3244
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
3245
+ }
2222
3246
  async persistWorkflowSnapshot({
2223
3247
  workflowName,
2224
3248
  runId,
3249
+ resourceId,
2225
3250
  snapshot
2226
3251
  }) {
2227
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
3252
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2228
3253
  }
2229
3254
  async loadWorkflowSnapshot({
2230
3255
  workflowName,
@@ -2232,15 +3257,8 @@ var MSSQLStore = class extends storage.MastraStorage {
2232
3257
  }) {
2233
3258
  return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2234
3259
  }
2235
- async getWorkflowRuns({
2236
- workflowName,
2237
- fromDate,
2238
- toDate,
2239
- limit,
2240
- offset,
2241
- resourceId
2242
- } = {}) {
2243
- return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
3260
+ async listWorkflowRuns(args = {}) {
3261
+ return this.stores.workflows.listWorkflowRuns(args);
2244
3262
  }
2245
3263
  async getWorkflowRunById({
2246
3264
  runId,
@@ -2248,41 +3266,114 @@ var MSSQLStore = class extends storage.MastraStorage {
2248
3266
  }) {
2249
3267
  return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2250
3268
  }
3269
+ async deleteWorkflowRunById({ runId, workflowName }) {
3270
+ return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
3271
+ }
2251
3272
  async close() {
2252
3273
  await this.pool.close();
2253
3274
  }
3275
+ /**
3276
+ * Index Management
3277
+ */
3278
+ async createIndex(options) {
3279
+ return this.stores.operations.createIndex(options);
3280
+ }
3281
+ async listIndexes(tableName) {
3282
+ return this.stores.operations.listIndexes(tableName);
3283
+ }
3284
+ async describeIndex(indexName) {
3285
+ return this.stores.operations.describeIndex(indexName);
3286
+ }
3287
+ async dropIndex(indexName) {
3288
+ return this.stores.operations.dropIndex(indexName);
3289
+ }
3290
+ /**
3291
+ * Tracing / Observability
3292
+ */
3293
+ getObservabilityStore() {
3294
+ if (!this.stores.observability) {
3295
+ throw new error.MastraError({
3296
+ id: storage.createStorageErrorId("MSSQL", "OBSERVABILITY", "NOT_INITIALIZED"),
3297
+ domain: error.ErrorDomain.STORAGE,
3298
+ category: error.ErrorCategory.SYSTEM,
3299
+ text: "Observability storage is not initialized"
3300
+ });
3301
+ }
3302
+ return this.stores.observability;
3303
+ }
3304
+ async createSpan(span) {
3305
+ return this.getObservabilityStore().createSpan(span);
3306
+ }
3307
+ async updateSpan({
3308
+ spanId,
3309
+ traceId,
3310
+ updates
3311
+ }) {
3312
+ return this.getObservabilityStore().updateSpan({ spanId, traceId, updates });
3313
+ }
3314
+ async getTrace(traceId) {
3315
+ return this.getObservabilityStore().getTrace(traceId);
3316
+ }
3317
+ async getTracesPaginated(args) {
3318
+ return this.getObservabilityStore().getTracesPaginated(args);
3319
+ }
3320
+ async batchCreateSpans(args) {
3321
+ return this.getObservabilityStore().batchCreateSpans(args);
3322
+ }
3323
+ async batchUpdateSpans(args) {
3324
+ return this.getObservabilityStore().batchUpdateSpans(args);
3325
+ }
3326
+ async batchDeleteTraces(args) {
3327
+ return this.getObservabilityStore().batchDeleteTraces(args);
3328
+ }
2254
3329
  /**
2255
3330
  * Scorers
2256
3331
  */
2257
3332
  async getScoreById({ id: _id }) {
2258
3333
  return this.stores.scores.getScoreById({ id: _id });
2259
3334
  }
2260
- async getScoresByScorerId({
3335
+ async listScoresByScorerId({
2261
3336
  scorerId: _scorerId,
2262
- pagination: _pagination
3337
+ pagination: _pagination,
3338
+ entityId: _entityId,
3339
+ entityType: _entityType,
3340
+ source: _source
2263
3341
  }) {
2264
- return this.stores.scores.getScoresByScorerId({ scorerId: _scorerId, pagination: _pagination });
3342
+ return this.stores.scores.listScoresByScorerId({
3343
+ scorerId: _scorerId,
3344
+ pagination: _pagination,
3345
+ entityId: _entityId,
3346
+ entityType: _entityType,
3347
+ source: _source
3348
+ });
2265
3349
  }
2266
- async saveScore(_score) {
2267
- return this.stores.scores.saveScore(_score);
3350
+ async saveScore(score) {
3351
+ return this.stores.scores.saveScore(score);
2268
3352
  }
2269
- async getScoresByRunId({
3353
+ async listScoresByRunId({
2270
3354
  runId: _runId,
2271
3355
  pagination: _pagination
2272
3356
  }) {
2273
- return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
3357
+ return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
2274
3358
  }
2275
- async getScoresByEntityId({
3359
+ async listScoresByEntityId({
2276
3360
  entityId: _entityId,
2277
3361
  entityType: _entityType,
2278
3362
  pagination: _pagination
2279
3363
  }) {
2280
- return this.stores.scores.getScoresByEntityId({
3364
+ return this.stores.scores.listScoresByEntityId({
2281
3365
  entityId: _entityId,
2282
3366
  entityType: _entityType,
2283
3367
  pagination: _pagination
2284
3368
  });
2285
3369
  }
3370
+ async listScoresBySpan({
3371
+ traceId,
3372
+ spanId,
3373
+ pagination: _pagination
3374
+ }) {
3375
+ return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination: _pagination });
3376
+ }
2286
3377
  };
2287
3378
 
2288
3379
  exports.MSSQLStore = MSSQLStore;