@mastra/mssql 0.0.0-toolOptionTypes-20250917085558 → 0.0.0-top-level-fix-20251211111608

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,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,25 +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
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
471
- const include = selectBy?.include;
472
- if (!include) return null;
428
+ async _getIncludedMessages({ include }) {
429
+ if (!include || include.length === 0) return null;
473
430
  const unionQueries = [];
474
431
  const paramValues = [];
475
432
  let paramIdx = 1;
476
433
  const paramNames = [];
434
+ const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
477
435
  for (const inc of include) {
478
436
  const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
479
- const searchId = inc.threadId || threadId;
480
- const pThreadId = `@p${paramIdx}`;
481
- const pId = `@p${paramIdx + 1}`;
482
- const pPrev = `@p${paramIdx + 2}`;
483
- const pNext = `@p${paramIdx + 3}`;
437
+ const pId = `@p${paramIdx}`;
438
+ const pPrev = `@p${paramIdx + 1}`;
439
+ const pNext = `@p${paramIdx + 2}`;
484
440
  unionQueries.push(
485
441
  `
486
442
  SELECT
@@ -493,30 +449,32 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
493
449
  m.[resourceId],
494
450
  m.seq_id
495
451
  FROM (
496
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
497
- FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
498
- 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})
499
455
  ) AS m
500
456
  WHERE m.id = ${pId}
501
457
  OR EXISTS (
502
458
  SELECT 1
503
459
  FROM (
504
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
505
- FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
506
- 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})
507
463
  ) AS target
508
464
  WHERE target.id = ${pId}
509
465
  AND (
510
- (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})
511
468
  OR
512
- (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})
513
471
  )
514
472
  )
515
473
  `
516
474
  );
517
- paramValues.push(searchId, id, withPreviousMessages, withNextMessages);
518
- paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}`, `p${paramIdx + 3}`);
519
- paramIdx += 4;
475
+ paramValues.push(id, withPreviousMessages, withNextMessages);
476
+ paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}`);
477
+ paramIdx += 3;
520
478
  }
521
479
  const finalQuery = `
522
480
  SELECT * FROM (
@@ -538,34 +496,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
538
496
  });
539
497
  return dedupedRows;
540
498
  }
541
- async getMessages(args) {
542
- const { threadId, resourceId, format, selectBy } = args;
499
+ async listMessagesById({ messageIds }) {
500
+ if (messageIds.length === 0) return { messages: [] };
543
501
  const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
544
502
  const orderByStatement = `ORDER BY [seq_id] DESC`;
545
- const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
546
503
  try {
547
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
548
504
  let rows = [];
549
- const include = selectBy?.include || [];
550
- if (include?.length) {
551
- const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
552
- if (includeMessages) {
553
- rows.push(...includeMessages);
554
- }
555
- }
556
- const excludeIds = rows.map((m) => m.id).filter(Boolean);
557
- 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(", ")})`;
558
506
  const request = this.pool.request();
559
- request.input("threadId", threadId);
560
- if (excludeIds.length > 0) {
561
- const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
562
- query += ` AND id NOT IN (${excludeParams.join(", ")})`;
563
- excludeIds.forEach((id, idx) => {
564
- request.input(`id${idx}`, id);
565
- });
566
- }
567
- query += ` ${orderByStatement} OFFSET 0 ROWS FETCH NEXT @limit ROWS ONLY`;
568
- request.input("limit", limit);
507
+ messageIds.forEach((id, i) => request.input(`id${i}`, id));
508
+ query += ` ${orderByStatement}`;
569
509
  const result = await request.query(query);
570
510
  const remainingRows = result.recordset || [];
571
511
  rows.push(...remainingRows);
@@ -573,157 +513,177 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
573
513
  const timeDiff = a.seq_id - b.seq_id;
574
514
  return timeDiff;
575
515
  });
576
- rows = rows.map(({ seq_id, ...rest }) => rest);
577
- 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() };
578
529
  } catch (error$1) {
579
530
  const mastraError = new error.MastraError(
580
531
  {
581
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_FAILED",
532
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES_BY_ID", "FAILED"),
582
533
  domain: error.ErrorDomain.STORAGE,
583
534
  category: error.ErrorCategory.THIRD_PARTY,
584
535
  details: {
585
- threadId,
586
- resourceId: resourceId ?? ""
536
+ messageIds: JSON.stringify(messageIds)
587
537
  }
588
538
  },
589
539
  error$1
590
540
  );
591
541
  this.logger?.error?.(mastraError.toString());
592
- this.logger?.trackException(mastraError);
593
- return [];
542
+ this.logger?.trackException?.(mastraError);
543
+ return { messages: [] };
594
544
  }
595
545
  }
596
- async getMessagesById({
597
- messageIds,
598
- format
599
- }) {
600
- if (messageIds.length === 0) return [];
601
- const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
602
- const orderByStatement = `ORDER BY [seq_id] DESC`;
603
- try {
604
- let rows = [];
605
- let query = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
606
- const request = this.pool.request();
607
- messageIds.forEach((id, i) => request.input(`id${i}`, id));
608
- query += ` ${orderByStatement}`;
609
- const result = await request.query(query);
610
- const remainingRows = result.recordset || [];
611
- rows.push(...remainingRows);
612
- rows.sort((a, b) => {
613
- const timeDiff = a.seq_id - b.seq_id;
614
- return timeDiff;
615
- });
616
- rows = rows.map(({ seq_id, ...rest }) => rest);
617
- if (format === `v1`) return this._parseAndFormatMessages(rows, format);
618
- return this._parseAndFormatMessages(rows, `v2`);
619
- } catch (error$1) {
620
- const mastraError = new error.MastraError(
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(
621
551
  {
622
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_BY_ID_FAILED",
552
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "INVALID_THREAD_ID"),
623
553
  domain: error.ErrorDomain.STORAGE,
624
554
  category: error.ErrorCategory.THIRD_PARTY,
625
- details: {
626
- messageIds: JSON.stringify(messageIds)
627
- }
555
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
628
556
  },
629
- error$1
557
+ new Error("threadId must be a non-empty string or array of non-empty strings")
630
558
  );
631
- this.logger?.error?.(mastraError.toString());
632
- this.logger?.trackException(mastraError);
633
- return [];
634
559
  }
635
- }
636
- async getMessagesPaginated(args) {
637
- const { threadId, resourceId, format, selectBy } = args;
638
- const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
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
+ });
571
+ }
572
+ const perPage = storage.normalizePerPage(perPageInput, 40);
573
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
639
574
  try {
640
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
641
- const fromDate = dateRange?.start;
642
- const toDate = dateRange?.end;
643
- const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
644
- const orderByStatement = `ORDER BY [seq_id] DESC`;
645
- let messages = [];
646
- if (selectBy?.include?.length) {
647
- const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
648
- if (includeMessages) messages.push(...includeMessages);
649
- }
650
- const perPage = perPageInput !== void 0 ? perPageInput : storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
651
- const currentOffset = page * perPage;
652
- const conditions = ["[thread_id] = @threadId"];
653
- const request = this.pool.request();
654
- request.input("threadId", threadId);
655
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
656
- conditions.push("[createdAt] >= @fromDate");
657
- request.input("fromDate", fromDate.toISOString());
658
- }
659
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
660
- conditions.push("[createdAt] <= @toDate");
661
- request.input("toDate", toDate.toISOString());
662
- }
663
- const whereClause = `WHERE ${conditions.join(" AND ")}`;
664
- const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
665
- 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}`);
666
592
  const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
667
- if (total === 0 && messages.length > 0) {
668
- const parsedIncluded = this._parseAndFormatMessages(messages, 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)) {
669
614
  return {
670
- messages: parsedIncluded,
671
- total: parsedIncluded.length,
615
+ messages: [],
616
+ total: 0,
672
617
  page,
673
- perPage,
618
+ perPage: perPageForResponse,
674
619
  hasMore: false
675
620
  };
676
621
  }
677
- const excludeIds = messages.map((m) => m.id);
678
- if (excludeIds.length > 0) {
679
- const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
680
- conditions.push(`id NOT IN (${excludeParams.join(", ")})`);
681
- excludeIds.forEach((id, idx) => request.input(`id${idx}`, id));
682
- }
683
- const finalWhereClause = `WHERE ${conditions.join(" AND ")}`;
684
- const dataQuery = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${finalWhereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
685
- request.input("offset", currentOffset);
686
- request.input("limit", perPage);
687
- const rowsResult = await request.query(dataQuery);
688
- const rows = rowsResult.recordset || [];
689
- rows.sort((a, b) => a.seq_id - b.seq_id);
690
- messages.push(...rows);
691
- const parsed = this._parseAndFormatMessages(messages, 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;
692
650
  return {
693
- messages: parsed,
694
- total: total + excludeIds.length,
651
+ messages: finalMessages,
652
+ total,
695
653
  page,
696
- perPage,
697
- hasMore: currentOffset + rows.length < total
654
+ perPage: perPageForResponse,
655
+ hasMore
698
656
  };
699
657
  } catch (error$1) {
700
658
  const mastraError = new error.MastraError(
701
659
  {
702
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_PAGINATED_FAILED",
660
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "FAILED"),
703
661
  domain: error.ErrorDomain.STORAGE,
704
662
  category: error.ErrorCategory.THIRD_PARTY,
705
663
  details: {
706
- threadId,
707
- resourceId: resourceId ?? "",
708
- page
664
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
665
+ resourceId: resourceId ?? ""
709
666
  }
710
667
  },
711
668
  error$1
712
669
  );
713
670
  this.logger?.error?.(mastraError.toString());
714
- this.logger?.trackException(mastraError);
715
- 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
+ };
716
679
  }
717
680
  }
718
- async saveMessages({
719
- messages,
720
- format
721
- }) {
722
- if (messages.length === 0) return messages;
681
+ async saveMessages({ messages }) {
682
+ if (messages.length === 0) return { messages: [] };
723
683
  const threadId = messages[0]?.threadId;
724
684
  if (!threadId) {
725
685
  throw new error.MastraError({
726
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
686
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "INVALID_THREAD_ID"),
727
687
  domain: error.ErrorDomain.STORAGE,
728
688
  category: error.ErrorCategory.THIRD_PARTY,
729
689
  text: `Thread ID is required`
@@ -732,7 +692,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
732
692
  const thread = await this.getThreadById({ threadId });
733
693
  if (!thread) {
734
694
  throw new error.MastraError({
735
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
695
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "THREAD_NOT_FOUND"),
736
696
  domain: error.ErrorDomain.STORAGE,
737
697
  category: error.ErrorCategory.THIRD_PARTY,
738
698
  text: `Thread ${threadId} not found`,
@@ -763,7 +723,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
763
723
  "content",
764
724
  typeof message.content === "string" ? message.content : JSON.stringify(message.content)
765
725
  );
766
- request.input("createdAt", sql2__default.default.DateTime2, message.createdAt);
726
+ request.input("createdAt", sql3__default.default.DateTime2, message.createdAt);
767
727
  request.input("role", message.role);
768
728
  request.input("type", message.type || "v2");
769
729
  request.input("resourceId", message.resourceId);
@@ -782,7 +742,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
782
742
  await request.query(mergeSql);
783
743
  }
784
744
  const threadReq = transaction.request();
785
- threadReq.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
745
+ threadReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
786
746
  threadReq.input("id", threadId);
787
747
  await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
788
748
  await transaction.commit();
@@ -801,12 +761,11 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
801
761
  return message;
802
762
  });
803
763
  const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
804
- if (format === "v2") return list.get.all.v2();
805
- return list.get.all.v1();
764
+ return { messages: list.get.all.db() };
806
765
  } catch (error$1) {
807
766
  throw new error.MastraError(
808
767
  {
809
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
768
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "FAILED"),
810
769
  domain: error.ErrorDomain.STORAGE,
811
770
  category: error.ErrorCategory.THIRD_PARTY,
812
771
  details: { threadId }
@@ -897,7 +856,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
897
856
  await transaction.rollback();
898
857
  throw new error.MastraError(
899
858
  {
900
- id: "MASTRA_STORAGE_MSSQL_UPDATE_MESSAGES_FAILED",
859
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_MESSAGES", "FAILED"),
901
860
  domain: error.ErrorDomain.STORAGE,
902
861
  category: error.ErrorCategory.THIRD_PARTY
903
862
  },
@@ -959,7 +918,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
959
918
  } catch (error$1) {
960
919
  throw new error.MastraError(
961
920
  {
962
- id: "MASTRA_STORAGE_MSSQL_STORE_DELETE_MESSAGES_FAILED",
921
+ id: storage.createStorageErrorId("MSSQL", "DELETE_MESSAGES", "FAILED"),
963
922
  domain: error.ErrorDomain.STORAGE,
964
923
  category: error.ErrorCategory.THIRD_PARTY,
965
924
  details: { messageIds: messageIds.join(", ") }
@@ -978,14 +937,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
978
937
  return null;
979
938
  }
980
939
  return {
981
- ...result,
982
- 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,
983
944
  metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
984
945
  };
985
946
  } catch (error$1) {
986
947
  const mastraError = new error.MastraError(
987
948
  {
988
- id: "MASTRA_STORAGE_MSSQL_GET_RESOURCE_BY_ID_FAILED",
949
+ id: storage.createStorageErrorId("MSSQL", "GET_RESOURCE_BY_ID", "FAILED"),
989
950
  domain: error.ErrorDomain.STORAGE,
990
951
  category: error.ErrorCategory.THIRD_PARTY,
991
952
  details: { resourceId }
@@ -993,7 +954,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
993
954
  error$1
994
955
  );
995
956
  this.logger?.error?.(mastraError.toString());
996
- this.logger?.trackException(mastraError);
957
+ this.logger?.trackException?.(mastraError);
997
958
  throw mastraError;
998
959
  }
999
960
  }
@@ -1002,7 +963,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1002
963
  tableName: storage.TABLE_RESOURCES,
1003
964
  record: {
1004
965
  ...resource,
1005
- metadata: JSON.stringify(resource.metadata)
966
+ metadata: resource.metadata
1006
967
  }
1007
968
  });
1008
969
  return resource;
@@ -1052,7 +1013,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1052
1013
  } catch (error$1) {
1053
1014
  const mastraError = new error.MastraError(
1054
1015
  {
1055
- id: "MASTRA_STORAGE_MSSQL_UPDATE_RESOURCE_FAILED",
1016
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_RESOURCE", "FAILED"),
1056
1017
  domain: error.ErrorDomain.STORAGE,
1057
1018
  category: error.ErrorCategory.THIRD_PARTY,
1058
1019
  details: { resourceId }
@@ -1060,62 +1021,381 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1060
1021
  error$1
1061
1022
  );
1062
1023
  this.logger?.error?.(mastraError.toString());
1063
- this.logger?.trackException(mastraError);
1024
+ this.logger?.trackException?.(mastraError);
1064
1025
  throw mastraError;
1065
1026
  }
1066
1027
  }
1067
1028
  };
1068
- var StoreOperationsMSSQL = class extends storage.StoreOperations {
1029
+ var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
1069
1030
  pool;
1070
- schemaName;
1071
- setupSchemaPromise = null;
1072
- schemaSetupComplete = void 0;
1073
- getSqlType(type, isPrimaryKey = false) {
1074
- switch (type) {
1075
- case "text":
1076
- return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(MAX)";
1077
- case "timestamp":
1078
- return "DATETIME2(7)";
1079
- case "uuid":
1080
- return "UNIQUEIDENTIFIER";
1081
- case "jsonb":
1082
- return "NVARCHAR(MAX)";
1083
- case "integer":
1084
- return "INT";
1085
- case "bigint":
1086
- return "BIGINT";
1087
- case "float":
1088
- return "FLOAT";
1089
- default:
1090
- throw new error.MastraError({
1091
- id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
1092
- domain: error.ErrorDomain.STORAGE,
1093
- category: error.ErrorCategory.THIRD_PARTY
1094
- });
1095
- }
1096
- }
1097
- constructor({ pool, schemaName }) {
1031
+ operations;
1032
+ schema;
1033
+ constructor({
1034
+ pool,
1035
+ operations,
1036
+ schema
1037
+ }) {
1098
1038
  super();
1099
1039
  this.pool = pool;
1100
- this.schemaName = schemaName;
1040
+ this.operations = operations;
1041
+ this.schema = schema;
1101
1042
  }
1102
- async hasColumn(table, column) {
1103
- const schema = this.schemaName || "dbo";
1104
- const request = this.pool.request();
1105
- request.input("schema", schema);
1106
- request.input("table", table);
1107
- request.input("column", column);
1108
- request.input("columnLower", column.toLowerCase());
1109
- const result = await request.query(
1110
- `SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
1111
- );
1112
- return result.recordset.length > 0;
1043
+ get tracingStrategy() {
1044
+ return {
1045
+ preferred: "batch-with-updates",
1046
+ supported: ["batch-with-updates", "insert-only"]
1047
+ };
1113
1048
  }
1114
- async setupSchema() {
1115
- if (!this.schemaName || this.schemaSetupComplete) {
1116
- return;
1049
+ async createSpan(span) {
1050
+ try {
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
+ );
1117
1075
  }
1118
- if (!this.setupSchemaPromise) {
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) {
1119
1399
  this.setupSchemaPromise = (async () => {
1120
1400
  try {
1121
1401
  const checkRequest = this.pool.request();
@@ -1148,27 +1428,33 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1148
1428
  }
1149
1429
  await this.setupSchemaPromise;
1150
1430
  }
1151
- async insert({ tableName, record }) {
1431
+ async insert({
1432
+ tableName,
1433
+ record,
1434
+ transaction
1435
+ }) {
1152
1436
  try {
1153
- const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
1154
- const values = Object.values(record);
1155
- const paramNames = values.map((_, i) => `@param${i}`);
1156
- const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${columns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
1157
- const request = this.pool.request();
1158
- values.forEach((value, i) => {
1159
- if (value instanceof Date) {
1160
- request.input(`param${i}`, sql2__default.default.DateTime2, value);
1161
- } else if (typeof value === "object" && value !== null) {
1162
- request.input(`param${i}`, JSON.stringify(value));
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);
1163
1449
  } else {
1164
- request.input(`param${i}`, value);
1450
+ request.input(`param${i}`, preparedValue);
1165
1451
  }
1166
1452
  });
1167
1453
  await request.query(insertSql);
1168
1454
  } catch (error$1) {
1169
1455
  throw new error.MastraError(
1170
1456
  {
1171
- id: "MASTRA_STORAGE_MSSQL_STORE_INSERT_FAILED",
1457
+ id: storage.createStorageErrorId("MSSQL", "INSERT", "FAILED"),
1172
1458
  domain: error.ErrorDomain.STORAGE,
1173
1459
  category: error.ErrorCategory.THIRD_PARTY,
1174
1460
  details: {
@@ -1185,7 +1471,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1185
1471
  try {
1186
1472
  await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
1187
1473
  } catch (truncateError) {
1188
- if (truncateError.message && truncateError.message.includes("foreign key")) {
1474
+ if (truncateError?.number === 4712) {
1189
1475
  await this.pool.request().query(`DELETE FROM ${fullTableName}`);
1190
1476
  } else {
1191
1477
  throw truncateError;
@@ -1194,7 +1480,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1194
1480
  } catch (error$1) {
1195
1481
  throw new error.MastraError(
1196
1482
  {
1197
- id: "MASTRA_STORAGE_MSSQL_STORE_CLEAR_TABLE_FAILED",
1483
+ id: storage.createStorageErrorId("MSSQL", "CLEAR_TABLE", "FAILED"),
1198
1484
  domain: error.ErrorDomain.STORAGE,
1199
1485
  category: error.ErrorCategory.THIRD_PARTY,
1200
1486
  details: {
@@ -1208,9 +1494,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1208
1494
  getDefaultValue(type) {
1209
1495
  switch (type) {
1210
1496
  case "timestamp":
1211
- return "DEFAULT SYSDATETIMEOFFSET()";
1497
+ return "DEFAULT SYSUTCDATETIME()";
1212
1498
  case "jsonb":
1213
1499
  return "DEFAULT N'{}'";
1500
+ case "boolean":
1501
+ return "DEFAULT 0";
1214
1502
  default:
1215
1503
  return super.getDefaultValue(type);
1216
1504
  }
@@ -1221,13 +1509,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1221
1509
  }) {
1222
1510
  try {
1223
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
+ ];
1224
1527
  const columns = Object.entries(schema).map(([name, def]) => {
1225
1528
  const parsedName = utils.parseSqlIdentifier(name, "column name");
1226
1529
  const constraints = [];
1227
1530
  if (def.primaryKey) constraints.push("PRIMARY KEY");
1228
1531
  if (!def.nullable) constraints.push("NOT NULL");
1229
1532
  const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
1230
- 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();
1231
1535
  }).join(",\n");
1232
1536
  if (this.schemaName) {
1233
1537
  await this.setupSchema();
@@ -1279,7 +1583,7 @@ ${columns}
1279
1583
  } catch (error$1) {
1280
1584
  throw new error.MastraError(
1281
1585
  {
1282
- id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_TABLE_FAILED",
1586
+ id: storage.createStorageErrorId("MSSQL", "CREATE_TABLE", "FAILED"),
1283
1587
  domain: error.ErrorDomain.STORAGE,
1284
1588
  category: error.ErrorCategory.THIRD_PARTY,
1285
1589
  details: {
@@ -1314,7 +1618,19 @@ ${columns}
1314
1618
  const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1315
1619
  if (!columnExists) {
1316
1620
  const columnDef = schema[columnName];
1317
- 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);
1318
1634
  const nullable = columnDef.nullable === false ? "NOT NULL" : "";
1319
1635
  const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
1320
1636
  const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
@@ -1327,7 +1643,7 @@ ${columns}
1327
1643
  } catch (error$1) {
1328
1644
  throw new error.MastraError(
1329
1645
  {
1330
- id: "MASTRA_STORAGE_MSSQL_STORE_ALTER_TABLE_FAILED",
1646
+ id: storage.createStorageErrorId("MSSQL", "ALTER_TABLE", "FAILED"),
1331
1647
  domain: error.ErrorDomain.STORAGE,
1332
1648
  category: error.ErrorCategory.THIRD_PARTY,
1333
1649
  details: {
@@ -1342,13 +1658,17 @@ ${columns}
1342
1658
  try {
1343
1659
  const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
1344
1660
  const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
1345
- const values = keyEntries.map(([_, value]) => value);
1346
- 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}`;
1347
1662
  const request = this.pool.request();
1348
- values.forEach((value, i) => {
1349
- 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
+ }
1350
1670
  });
1351
- const resultSet = await request.query(sql7);
1671
+ const resultSet = await request.query(sql5);
1352
1672
  const result = resultSet.recordset[0] || null;
1353
1673
  if (!result) {
1354
1674
  return null;
@@ -1364,7 +1684,7 @@ ${columns}
1364
1684
  } catch (error$1) {
1365
1685
  throw new error.MastraError(
1366
1686
  {
1367
- id: "MASTRA_STORAGE_MSSQL_STORE_LOAD_FAILED",
1687
+ id: storage.createStorageErrorId("MSSQL", "LOAD", "FAILED"),
1368
1688
  domain: error.ErrorDomain.STORAGE,
1369
1689
  category: error.ErrorCategory.THIRD_PARTY,
1370
1690
  details: {
@@ -1380,14 +1700,14 @@ ${columns}
1380
1700
  try {
1381
1701
  await transaction.begin();
1382
1702
  for (const record of records) {
1383
- await this.insert({ tableName, record });
1703
+ await this.insert({ tableName, record, transaction });
1384
1704
  }
1385
1705
  await transaction.commit();
1386
1706
  } catch (error$1) {
1387
1707
  await transaction.rollback();
1388
1708
  throw new error.MastraError(
1389
1709
  {
1390
- id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
1710
+ id: storage.createStorageErrorId("MSSQL", "BATCH_INSERT", "FAILED"),
1391
1711
  domain: error.ErrorDomain.STORAGE,
1392
1712
  category: error.ErrorCategory.THIRD_PARTY,
1393
1713
  details: {
@@ -1406,7 +1726,7 @@ ${columns}
1406
1726
  } catch (error$1) {
1407
1727
  throw new error.MastraError(
1408
1728
  {
1409
- id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
1729
+ id: storage.createStorageErrorId("MSSQL", "DROP_TABLE", "FAILED"),
1410
1730
  domain: error.ErrorDomain.STORAGE,
1411
1731
  category: error.ErrorCategory.THIRD_PARTY,
1412
1732
  details: {
@@ -1417,29 +1737,568 @@ ${columns}
1417
1737
  );
1418
1738
  }
1419
1739
  }
1420
- };
1421
- function parseJSON(jsonString) {
1422
- try {
1423
- return JSON.parse(jsonString);
1424
- } catch {
1425
- 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;
1426
1776
  }
1427
- }
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
+ };
1428
2298
  function transformScoreRow(row) {
1429
- return {
1430
- ...row,
1431
- input: parseJSON(row.input),
1432
- scorer: parseJSON(row.scorer),
1433
- preprocessStepResult: parseJSON(row.preprocessStepResult),
1434
- analyzeStepResult: parseJSON(row.analyzeStepResult),
1435
- metadata: parseJSON(row.metadata),
1436
- output: parseJSON(row.output),
1437
- additionalContext: parseJSON(row.additionalContext),
1438
- runtimeContext: parseJSON(row.runtimeContext),
1439
- entity: parseJSON(row.entity),
1440
- createdAt: row.createdAt,
1441
- updatedAt: row.updatedAt
1442
- };
2299
+ return storage.transformScoreRow(row, {
2300
+ convertTimestamps: true
2301
+ });
1443
2302
  }
1444
2303
  var ScoresMSSQL = class extends storage.ScoresStorage {
1445
2304
  pool;
@@ -1469,7 +2328,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1469
2328
  } catch (error$1) {
1470
2329
  throw new error.MastraError(
1471
2330
  {
1472
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORE_BY_ID_FAILED",
2331
+ id: storage.createStorageErrorId("MSSQL", "GET_SCORE_BY_ID", "FAILED"),
1473
2332
  domain: error.ErrorDomain.STORAGE,
1474
2333
  category: error.ErrorCategory.THIRD_PARTY,
1475
2334
  details: { id }
@@ -1477,10 +2336,31 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1477
2336
  error$1
1478
2337
  );
1479
2338
  }
1480
- }
1481
- 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
+ }
1482
2361
  try {
1483
2362
  const scoreId = crypto.randomUUID();
2363
+ const now = /* @__PURE__ */ new Date();
1484
2364
  const {
1485
2365
  scorer,
1486
2366
  preprocessStepResult,
@@ -1489,34 +2369,33 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1489
2369
  input,
1490
2370
  output,
1491
2371
  additionalContext,
1492
- runtimeContext,
2372
+ requestContext,
1493
2373
  entity,
1494
2374
  ...rest
1495
- } = score;
2375
+ } = validatedScore;
1496
2376
  await this.operations.insert({
1497
2377
  tableName: storage.TABLE_SCORERS,
1498
2378
  record: {
1499
2379
  id: scoreId,
1500
2380
  ...rest,
1501
- input: JSON.stringify(input) || "",
1502
- output: JSON.stringify(output) || "",
1503
- preprocessStepResult: preprocessStepResult ? JSON.stringify(preprocessStepResult) : null,
1504
- analyzeStepResult: analyzeStepResult ? JSON.stringify(analyzeStepResult) : null,
1505
- metadata: metadata ? JSON.stringify(metadata) : null,
1506
- additionalContext: additionalContext ? JSON.stringify(additionalContext) : null,
1507
- runtimeContext: runtimeContext ? JSON.stringify(runtimeContext) : null,
1508
- entity: entity ? JSON.stringify(entity) : null,
1509
- scorer: scorer ? JSON.stringify(scorer) : null,
1510
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1511
- 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()
1512
2392
  }
1513
2393
  });
1514
- const scoreFromDb = await this.getScoreById({ id: scoreId });
1515
- return { score: scoreFromDb };
2394
+ return { score: { ...validatedScore, id: scoreId, createdAt: now, updatedAt: now } };
1516
2395
  } catch (error$1) {
1517
2396
  throw new error.MastraError(
1518
2397
  {
1519
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_FAILED",
2398
+ id: storage.createStorageErrorId("MSSQL", "SAVE_SCORE", "FAILED"),
1520
2399
  domain: error.ErrorDomain.STORAGE,
1521
2400
  category: error.ErrorCategory.THIRD_PARTY
1522
2401
  },
@@ -1524,48 +2403,77 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1524
2403
  );
1525
2404
  }
1526
2405
  }
1527
- async getScoresByScorerId({
2406
+ async listScoresByScorerId({
1528
2407
  scorerId,
1529
- pagination
2408
+ pagination,
2409
+ entityId,
2410
+ entityType,
2411
+ source
1530
2412
  }) {
1531
2413
  try {
1532
- const request = this.pool.request();
1533
- request.input("p1", scorerId);
1534
- const totalResult = await request.query(
1535
- `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [scorerId] = @p1`
1536
- );
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}`);
1537
2439
  const total = totalResult.recordset[0]?.count || 0;
2440
+ const { page, perPage: perPageInput } = pagination;
1538
2441
  if (total === 0) {
1539
2442
  return {
1540
2443
  pagination: {
1541
2444
  total: 0,
1542
- page: pagination.page,
1543
- perPage: pagination.perPage,
2445
+ page,
2446
+ perPage: perPageInput,
1544
2447
  hasMore: false
1545
2448
  },
1546
2449
  scores: []
1547
2450
  };
1548
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;
1549
2456
  const dataRequest = this.pool.request();
1550
- dataRequest.input("p1", scorerId);
1551
- dataRequest.input("p2", pagination.perPage);
1552
- dataRequest.input("p3", pagination.page * pagination.perPage);
1553
- const result = await dataRequest.query(
1554
- `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`
1555
- );
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);
1556
2464
  return {
1557
2465
  pagination: {
1558
2466
  total: Number(total),
1559
- page: pagination.page,
1560
- perPage: pagination.perPage,
1561
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
2467
+ page,
2468
+ perPage: perPageForResponse,
2469
+ hasMore: end < total
1562
2470
  },
1563
2471
  scores: result.recordset.map((row) => transformScoreRow(row))
1564
2472
  };
1565
2473
  } catch (error$1) {
1566
2474
  throw new error.MastraError(
1567
2475
  {
1568
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
2476
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
1569
2477
  domain: error.ErrorDomain.STORAGE,
1570
2478
  category: error.ErrorCategory.THIRD_PARTY,
1571
2479
  details: { scorerId }
@@ -1574,7 +2482,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1574
2482
  );
1575
2483
  }
1576
2484
  }
1577
- async getScoresByRunId({
2485
+ async listScoresByRunId({
1578
2486
  runId,
1579
2487
  pagination
1580
2488
  }) {
@@ -1585,37 +2493,42 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1585
2493
  `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1`
1586
2494
  );
1587
2495
  const total = totalResult.recordset[0]?.count || 0;
2496
+ const { page, perPage: perPageInput } = pagination;
1588
2497
  if (total === 0) {
1589
2498
  return {
1590
2499
  pagination: {
1591
2500
  total: 0,
1592
- page: pagination.page,
1593
- perPage: pagination.perPage,
2501
+ page,
2502
+ perPage: perPageInput,
1594
2503
  hasMore: false
1595
2504
  },
1596
2505
  scores: []
1597
2506
  };
1598
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;
1599
2512
  const dataRequest = this.pool.request();
1600
2513
  dataRequest.input("p1", runId);
1601
- dataRequest.input("p2", pagination.perPage);
1602
- dataRequest.input("p3", pagination.page * pagination.perPage);
2514
+ dataRequest.input("p2", limitValue);
2515
+ dataRequest.input("p3", start);
1603
2516
  const result = await dataRequest.query(
1604
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`
1605
2518
  );
1606
2519
  return {
1607
2520
  pagination: {
1608
2521
  total: Number(total),
1609
- page: pagination.page,
1610
- perPage: pagination.perPage,
1611
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
2522
+ page,
2523
+ perPage: perPageForResponse,
2524
+ hasMore: end < total
1612
2525
  },
1613
2526
  scores: result.recordset.map((row) => transformScoreRow(row))
1614
2527
  };
1615
2528
  } catch (error$1) {
1616
2529
  throw new error.MastraError(
1617
2530
  {
1618
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_RUN_ID_FAILED",
2531
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_RUN_ID", "FAILED"),
1619
2532
  domain: error.ErrorDomain.STORAGE,
1620
2533
  category: error.ErrorCategory.THIRD_PARTY,
1621
2534
  details: { runId }
@@ -1624,7 +2537,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1624
2537
  );
1625
2538
  }
1626
2539
  }
1627
- async getScoresByEntityId({
2540
+ async listScoresByEntityId({
1628
2541
  entityId,
1629
2542
  entityType,
1630
2543
  pagination
@@ -1637,38 +2550,43 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1637
2550
  `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2`
1638
2551
  );
1639
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);
1640
2556
  if (total === 0) {
1641
2557
  return {
1642
2558
  pagination: {
1643
2559
  total: 0,
1644
- page: pagination.page,
1645
- perPage: pagination.perPage,
2560
+ page,
2561
+ perPage: perPageForResponse,
1646
2562
  hasMore: false
1647
2563
  },
1648
2564
  scores: []
1649
2565
  };
1650
2566
  }
2567
+ const limitValue = perPageInput === false ? total : perPage;
2568
+ const end = perPageInput === false ? total : start + perPage;
1651
2569
  const dataRequest = this.pool.request();
1652
2570
  dataRequest.input("p1", entityId);
1653
2571
  dataRequest.input("p2", entityType);
1654
- dataRequest.input("p3", pagination.perPage);
1655
- dataRequest.input("p4", pagination.page * pagination.perPage);
2572
+ dataRequest.input("p3", limitValue);
2573
+ dataRequest.input("p4", start);
1656
2574
  const result = await dataRequest.query(
1657
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`
1658
2576
  );
1659
2577
  return {
1660
2578
  pagination: {
1661
2579
  total: Number(total),
1662
- page: pagination.page,
1663
- perPage: pagination.perPage,
1664
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
2580
+ page,
2581
+ perPage: perPageForResponse,
2582
+ hasMore: end < total
1665
2583
  },
1666
2584
  scores: result.recordset.map((row) => transformScoreRow(row))
1667
2585
  };
1668
2586
  } catch (error$1) {
1669
2587
  throw new error.MastraError(
1670
2588
  {
1671
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
2589
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
1672
2590
  domain: error.ErrorDomain.STORAGE,
1673
2591
  category: error.ErrorCategory.THIRD_PARTY,
1674
2592
  details: { entityId, entityType }
@@ -1677,8 +2595,66 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1677
2595
  );
1678
2596
  }
1679
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
+ }
1680
2656
  };
1681
- var TracesMSSQL = class extends storage.TracesStorage {
2657
+ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1682
2658
  pool;
1683
2659
  operations;
1684
2660
  schema;
@@ -1692,207 +2668,166 @@ var TracesMSSQL = class extends storage.TracesStorage {
1692
2668
  this.operations = operations;
1693
2669
  this.schema = schema;
1694
2670
  }
1695
- /** @deprecated use getTracesPaginated instead*/
1696
- async getTraces(args) {
1697
- if (args.fromDate || args.toDate) {
1698
- args.dateRange = {
1699
- start: args.fromDate,
1700
- end: args.toDate
1701
- };
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
+ }
1702
2679
  }
1703
- const result = await this.getTracesPaginated(args);
1704
- 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
+ };
1705
2688
  }
1706
- async getTracesPaginated(args) {
1707
- const { name, scope, page = 0, perPage: perPageInput, attributes, filters, dateRange } = args;
1708
- const fromDate = dateRange?.start;
1709
- const toDate = dateRange?.end;
1710
- const perPage = perPageInput !== void 0 ? perPageInput : 100;
1711
- const currentOffset = page * perPage;
1712
- const paramMap = {};
1713
- const conditions = [];
1714
- let paramIndex = 1;
1715
- if (name) {
1716
- const paramName = `p${paramIndex++}`;
1717
- conditions.push(`[name] LIKE @${paramName}`);
1718
- paramMap[paramName] = `${name}%`;
1719
- }
1720
- if (scope) {
1721
- const paramName = `p${paramIndex++}`;
1722
- conditions.push(`[scope] = @${paramName}`);
1723
- paramMap[paramName] = scope;
1724
- }
1725
- if (attributes) {
1726
- Object.entries(attributes).forEach(([key, value]) => {
1727
- const parsedKey = utils.parseFieldKey(key);
1728
- const paramName = `p${paramIndex++}`;
1729
- conditions.push(`JSON_VALUE([attributes], '$.${parsedKey}') = @${paramName}`);
1730
- paramMap[paramName] = value;
1731
- });
1732
- }
1733
- if (filters) {
1734
- Object.entries(filters).forEach(([key, value]) => {
1735
- const parsedKey = utils.parseFieldKey(key);
1736
- const paramName = `p${paramIndex++}`;
1737
- conditions.push(`[${parsedKey}] = @${paramName}`);
1738
- paramMap[paramName] = value;
1739
- });
1740
- }
1741
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
1742
- const paramName = `p${paramIndex++}`;
1743
- conditions.push(`[createdAt] >= @${paramName}`);
1744
- paramMap[paramName] = fromDate.toISOString();
1745
- }
1746
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
1747
- const paramName = `p${paramIndex++}`;
1748
- conditions.push(`[createdAt] <= @${paramName}`);
1749
- paramMap[paramName] = toDate.toISOString();
1750
- }
1751
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1752
- const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
1753
- 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();
1754
2698
  try {
1755
- const countRequest = this.pool.request();
1756
- Object.entries(paramMap).forEach(([key, value]) => {
1757
- if (value instanceof Date) {
1758
- countRequest.input(key, sql2__default.default.DateTime, value);
1759
- } else {
1760
- countRequest.input(key, value);
1761
- }
1762
- });
1763
- const countResult = await countRequest.query(countQuery);
1764
- 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;
1765
2744
  } catch (error$1) {
2745
+ try {
2746
+ await transaction.rollback();
2747
+ } catch {
2748
+ }
1766
2749
  throw new error.MastraError(
1767
2750
  {
1768
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT",
2751
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
1769
2752
  domain: error.ErrorDomain.STORAGE,
1770
2753
  category: error.ErrorCategory.THIRD_PARTY,
1771
2754
  details: {
1772
- name: args.name ?? "",
1773
- scope: args.scope ?? ""
2755
+ workflowName,
2756
+ runId,
2757
+ stepId
1774
2758
  }
1775
2759
  },
1776
2760
  error$1
1777
2761
  );
1778
2762
  }
1779
- if (total === 0) {
1780
- return {
1781
- traces: [],
1782
- total: 0,
1783
- page,
1784
- perPage,
1785
- hasMore: false
1786
- };
1787
- }
1788
- 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`;
1789
- const dataRequest = this.pool.request();
1790
- Object.entries(paramMap).forEach(([key, value]) => {
1791
- if (value instanceof Date) {
1792
- dataRequest.input(key, sql2__default.default.DateTime, value);
1793
- } else {
1794
- dataRequest.input(key, value);
1795
- }
1796
- });
1797
- dataRequest.input("offset", currentOffset);
1798
- 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();
1799
2771
  try {
1800
- const rowsResult = await dataRequest.query(dataQuery);
1801
- const rows = rowsResult.recordset;
1802
- const traces = rows.map((row) => ({
1803
- id: row.id,
1804
- parentSpanId: row.parentSpanId,
1805
- traceId: row.traceId,
1806
- name: row.name,
1807
- scope: row.scope,
1808
- kind: row.kind,
1809
- status: JSON.parse(row.status),
1810
- events: JSON.parse(row.events),
1811
- links: JSON.parse(row.links),
1812
- attributes: JSON.parse(row.attributes),
1813
- startTime: row.startTime,
1814
- endTime: row.endTime,
1815
- other: row.other,
1816
- createdAt: row.createdAt
1817
- }));
1818
- return {
1819
- traces,
1820
- total,
1821
- page,
1822
- perPage,
1823
- hasMore: currentOffset + traces.length < total
1824
- };
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;
1825
2811
  } catch (error$1) {
2812
+ try {
2813
+ await transaction.rollback();
2814
+ } catch {
2815
+ }
2816
+ if (error$1 instanceof error.MastraError) throw error$1;
1826
2817
  throw new error.MastraError(
1827
2818
  {
1828
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES",
2819
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_STATE", "FAILED"),
1829
2820
  domain: error.ErrorDomain.STORAGE,
1830
2821
  category: error.ErrorCategory.THIRD_PARTY,
1831
2822
  details: {
1832
- name: args.name ?? "",
1833
- scope: args.scope ?? ""
2823
+ workflowName,
2824
+ runId
1834
2825
  }
1835
2826
  },
1836
2827
  error$1
1837
2828
  );
1838
2829
  }
1839
2830
  }
1840
- async batchTraceInsert({ records }) {
1841
- this.logger.debug("Batch inserting traces", { count: records.length });
1842
- await this.operations.batchInsert({
1843
- tableName: storage.TABLE_TRACES,
1844
- records
1845
- });
1846
- }
1847
- };
1848
- function parseWorkflowRun(row) {
1849
- let parsedSnapshot = row.snapshot;
1850
- if (typeof parsedSnapshot === "string") {
1851
- try {
1852
- parsedSnapshot = JSON.parse(row.snapshot);
1853
- } catch (e) {
1854
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1855
- }
1856
- }
1857
- return {
1858
- workflowName: row.workflow_name,
1859
- runId: row.run_id,
1860
- snapshot: parsedSnapshot,
1861
- createdAt: row.createdAt,
1862
- updatedAt: row.updatedAt,
1863
- resourceId: row.resourceId
1864
- };
1865
- }
1866
- var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1867
- pool;
1868
- operations;
1869
- schema;
1870
- constructor({
1871
- pool,
1872
- operations,
1873
- schema
1874
- }) {
1875
- super();
1876
- this.pool = pool;
1877
- this.operations = operations;
1878
- this.schema = schema;
1879
- }
1880
- updateWorkflowResults({
1881
- // workflowName,
1882
- // runId,
1883
- // stepId,
1884
- // result,
1885
- // runtimeContext,
1886
- }) {
1887
- throw new Error("Method not implemented.");
1888
- }
1889
- updateWorkflowState({
1890
- // workflowName,
1891
- // runId,
1892
- // opts,
1893
- }) {
1894
- throw new Error("Method not implemented.");
1895
- }
1896
2831
  async persistWorkflowSnapshot({
1897
2832
  workflowName,
1898
2833
  runId,
@@ -1907,8 +2842,8 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1907
2842
  request.input("run_id", runId);
1908
2843
  request.input("resourceId", resourceId);
1909
2844
  request.input("snapshot", JSON.stringify(snapshot));
1910
- request.input("createdAt", sql2__default.default.DateTime2, new Date(now));
1911
- 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));
1912
2847
  const mergeSql = `MERGE INTO ${table} AS target
1913
2848
  USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
1914
2849
  ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
@@ -1922,7 +2857,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1922
2857
  } catch (error$1) {
1923
2858
  throw new error.MastraError(
1924
2859
  {
1925
- id: "MASTRA_STORAGE_MSSQL_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
2860
+ id: storage.createStorageErrorId("MSSQL", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
1926
2861
  domain: error.ErrorDomain.STORAGE,
1927
2862
  category: error.ErrorCategory.THIRD_PARTY,
1928
2863
  details: {
@@ -1953,7 +2888,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1953
2888
  } catch (error$1) {
1954
2889
  throw new error.MastraError(
1955
2890
  {
1956
- id: "MASTRA_STORAGE_MSSQL_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
2891
+ id: storage.createStorageErrorId("MSSQL", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
1957
2892
  domain: error.ErrorDomain.STORAGE,
1958
2893
  category: error.ErrorCategory.THIRD_PARTY,
1959
2894
  details: {
@@ -1989,11 +2924,11 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1989
2924
  if (!result.recordset || result.recordset.length === 0) {
1990
2925
  return null;
1991
2926
  }
1992
- return parseWorkflowRun(result.recordset[0]);
2927
+ return this.parseWorkflowRun(result.recordset[0]);
1993
2928
  } catch (error$1) {
1994
2929
  throw new error.MastraError(
1995
2930
  {
1996
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
2931
+ id: storage.createStorageErrorId("MSSQL", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1997
2932
  domain: error.ErrorDomain.STORAGE,
1998
2933
  category: error.ErrorCategory.THIRD_PARTY,
1999
2934
  details: {
@@ -2005,13 +2940,43 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2005
2940
  );
2006
2941
  }
2007
2942
  }
2008
- 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({
2009
2973
  workflowName,
2010
2974
  fromDate,
2011
2975
  toDate,
2012
- limit,
2013
- offset,
2014
- resourceId
2976
+ page,
2977
+ perPage,
2978
+ resourceId,
2979
+ status
2015
2980
  } = {}) {
2016
2981
  try {
2017
2982
  const conditions = [];
@@ -2020,13 +2985,17 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2020
2985
  conditions.push(`[workflow_name] = @workflowName`);
2021
2986
  paramMap["workflowName"] = workflowName;
2022
2987
  }
2988
+ if (status) {
2989
+ conditions.push(`JSON_VALUE([snapshot], '$.status') = @status`);
2990
+ paramMap["status"] = status;
2991
+ }
2023
2992
  if (resourceId) {
2024
2993
  const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
2025
2994
  if (hasResourceId) {
2026
2995
  conditions.push(`[resourceId] = @resourceId`);
2027
2996
  paramMap["resourceId"] = resourceId;
2028
2997
  } else {
2029
- 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.`);
2030
2999
  }
2031
3000
  }
2032
3001
  if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
@@ -2043,29 +3012,32 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2043
3012
  const request = this.pool.request();
2044
3013
  Object.entries(paramMap).forEach(([key, value]) => {
2045
3014
  if (value instanceof Date) {
2046
- request.input(key, sql2__default.default.DateTime, value);
3015
+ request.input(key, sql3__default.default.DateTime, value);
2047
3016
  } else {
2048
3017
  request.input(key, value);
2049
3018
  }
2050
3019
  });
2051
- if (limit !== void 0 && offset !== void 0) {
3020
+ const usePagination = typeof perPage === "number" && typeof page === "number";
3021
+ if (usePagination) {
2052
3022
  const countQuery = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
2053
3023
  const countResult = await request.query(countQuery);
2054
3024
  total = Number(countResult.recordset[0]?.count || 0);
2055
3025
  }
2056
3026
  let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY [seq_id] DESC`;
2057
- if (limit !== void 0 && offset !== void 0) {
2058
- query += ` OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
2059
- 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);
2060
3032
  request.input("offset", offset);
2061
3033
  }
2062
3034
  const result = await request.query(query);
2063
- const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
3035
+ const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
2064
3036
  return { runs, total: total || runs.length };
2065
3037
  } catch (error$1) {
2066
3038
  throw new error.MastraError(
2067
3039
  {
2068
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_WORKFLOW_RUNS_FAILED",
3040
+ id: storage.createStorageErrorId("MSSQL", "LIST_WORKFLOW_RUNS", "FAILED"),
2069
3041
  domain: error.ErrorDomain.STORAGE,
2070
3042
  category: error.ErrorCategory.THIRD_PARTY,
2071
3043
  details: {
@@ -2085,7 +3057,10 @@ var MSSQLStore = class extends storage.MastraStorage {
2085
3057
  isConnected = null;
2086
3058
  stores;
2087
3059
  constructor(config) {
2088
- 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 });
2089
3064
  try {
2090
3065
  if ("connectionString" in config) {
2091
3066
  if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
@@ -2100,7 +3075,7 @@ var MSSQLStore = class extends storage.MastraStorage {
2100
3075
  }
2101
3076
  }
2102
3077
  this.schema = config.schemaName || "dbo";
2103
- 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({
2104
3079
  server: config.server,
2105
3080
  database: config.database,
2106
3081
  user: config.user,
@@ -2108,24 +3083,22 @@ var MSSQLStore = class extends storage.MastraStorage {
2108
3083
  port: config.port,
2109
3084
  options: config.options || { encrypt: true, trustServerCertificate: true }
2110
3085
  });
2111
- const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
2112
3086
  const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
2113
3087
  const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
2114
- const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
2115
3088
  const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
2116
3089
  const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
3090
+ const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
2117
3091
  this.stores = {
2118
3092
  operations,
2119
3093
  scores,
2120
- traces,
2121
3094
  workflows,
2122
- legacyEvals,
2123
- memory
3095
+ memory,
3096
+ observability
2124
3097
  };
2125
3098
  } catch (e) {
2126
3099
  throw new error.MastraError(
2127
3100
  {
2128
- id: "MASTRA_STORAGE_MSSQL_STORE_INITIALIZATION_FAILED",
3101
+ id: storage.createStorageErrorId("MSSQL", "INITIALIZATION", "FAILED"),
2129
3102
  domain: error.ErrorDomain.STORAGE,
2130
3103
  category: error.ErrorCategory.USER
2131
3104
  },
@@ -2140,11 +3113,16 @@ var MSSQLStore = class extends storage.MastraStorage {
2140
3113
  try {
2141
3114
  await this.isConnected;
2142
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
+ }
2143
3121
  } catch (error$1) {
2144
3122
  this.isConnected = null;
2145
3123
  throw new error.MastraError(
2146
3124
  {
2147
- id: "MASTRA_STORAGE_MSSQL_STORE_INIT_FAILED",
3125
+ id: storage.createStorageErrorId("MSSQL", "INIT", "FAILED"),
2148
3126
  domain: error.ErrorDomain.STORAGE,
2149
3127
  category: error.ErrorCategory.THIRD_PARTY
2150
3128
  },
@@ -2166,28 +3144,12 @@ var MSSQLStore = class extends storage.MastraStorage {
2166
3144
  resourceWorkingMemory: true,
2167
3145
  hasColumn: true,
2168
3146
  createTable: true,
2169
- deleteMessages: true
3147
+ deleteMessages: true,
3148
+ listScoresBySpan: true,
3149
+ observabilityInstance: true,
3150
+ indexManagement: true
2170
3151
  };
2171
3152
  }
2172
- /** @deprecated use getEvals instead */
2173
- async getEvalsByAgentName(agentName, type) {
2174
- return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2175
- }
2176
- async getEvals(options = {}) {
2177
- return this.stores.legacyEvals.getEvals(options);
2178
- }
2179
- /**
2180
- * @deprecated use getTracesPaginated instead
2181
- */
2182
- async getTraces(args) {
2183
- return this.stores.traces.getTraces(args);
2184
- }
2185
- async getTracesPaginated(args) {
2186
- return this.stores.traces.getTracesPaginated(args);
2187
- }
2188
- async batchTraceInsert({ records }) {
2189
- return this.stores.traces.batchTraceInsert({ records });
2190
- }
2191
3153
  async createTable({
2192
3154
  tableName,
2193
3155
  schema
@@ -2222,15 +3184,6 @@ var MSSQLStore = class extends storage.MastraStorage {
2222
3184
  async getThreadById({ threadId }) {
2223
3185
  return this.stores.memory.getThreadById({ threadId });
2224
3186
  }
2225
- /**
2226
- * @deprecated use getThreadsByResourceIdPaginated instead
2227
- */
2228
- async getThreadsByResourceId(args) {
2229
- return this.stores.memory.getThreadsByResourceId(args);
2230
- }
2231
- async getThreadsByResourceIdPaginated(args) {
2232
- return this.stores.memory.getThreadsByResourceIdPaginated(args);
2233
- }
2234
3187
  async saveThread({ thread }) {
2235
3188
  return this.stores.memory.saveThread({ thread });
2236
3189
  }
@@ -2244,17 +3197,8 @@ var MSSQLStore = class extends storage.MastraStorage {
2244
3197
  async deleteThread({ threadId }) {
2245
3198
  return this.stores.memory.deleteThread({ threadId });
2246
3199
  }
2247
- async getMessages(args) {
2248
- return this.stores.memory.getMessages(args);
2249
- }
2250
- async getMessagesById({
2251
- messageIds,
2252
- format
2253
- }) {
2254
- return this.stores.memory.getMessagesById({ messageIds, format });
2255
- }
2256
- async getMessagesPaginated(args) {
2257
- return this.stores.memory.getMessagesPaginated(args);
3200
+ async listMessagesById({ messageIds }) {
3201
+ return this.stores.memory.listMessagesById({ messageIds });
2258
3202
  }
2259
3203
  async saveMessages(args) {
2260
3204
  return this.stores.memory.saveMessages(args);
@@ -2288,9 +3232,9 @@ var MSSQLStore = class extends storage.MastraStorage {
2288
3232
  runId,
2289
3233
  stepId,
2290
3234
  result,
2291
- runtimeContext
3235
+ requestContext
2292
3236
  }) {
2293
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
3237
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2294
3238
  }
2295
3239
  async updateWorkflowState({
2296
3240
  workflowName,
@@ -2313,15 +3257,8 @@ var MSSQLStore = class extends storage.MastraStorage {
2313
3257
  }) {
2314
3258
  return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2315
3259
  }
2316
- async getWorkflowRuns({
2317
- workflowName,
2318
- fromDate,
2319
- toDate,
2320
- limit,
2321
- offset,
2322
- resourceId
2323
- } = {}) {
2324
- return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
3260
+ async listWorkflowRuns(args = {}) {
3261
+ return this.stores.workflows.listWorkflowRuns(args);
2325
3262
  }
2326
3263
  async getWorkflowRunById({
2327
3264
  runId,
@@ -2329,41 +3266,114 @@ var MSSQLStore = class extends storage.MastraStorage {
2329
3266
  }) {
2330
3267
  return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2331
3268
  }
3269
+ async deleteWorkflowRunById({ runId, workflowName }) {
3270
+ return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
3271
+ }
2332
3272
  async close() {
2333
3273
  await this.pool.close();
2334
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
+ }
2335
3329
  /**
2336
3330
  * Scorers
2337
3331
  */
2338
3332
  async getScoreById({ id: _id }) {
2339
3333
  return this.stores.scores.getScoreById({ id: _id });
2340
3334
  }
2341
- async getScoresByScorerId({
3335
+ async listScoresByScorerId({
2342
3336
  scorerId: _scorerId,
2343
- pagination: _pagination
3337
+ pagination: _pagination,
3338
+ entityId: _entityId,
3339
+ entityType: _entityType,
3340
+ source: _source
2344
3341
  }) {
2345
- 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
+ });
2346
3349
  }
2347
- async saveScore(_score) {
2348
- return this.stores.scores.saveScore(_score);
3350
+ async saveScore(score) {
3351
+ return this.stores.scores.saveScore(score);
2349
3352
  }
2350
- async getScoresByRunId({
3353
+ async listScoresByRunId({
2351
3354
  runId: _runId,
2352
3355
  pagination: _pagination
2353
3356
  }) {
2354
- return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
3357
+ return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
2355
3358
  }
2356
- async getScoresByEntityId({
3359
+ async listScoresByEntityId({
2357
3360
  entityId: _entityId,
2358
3361
  entityType: _entityType,
2359
3362
  pagination: _pagination
2360
3363
  }) {
2361
- return this.stores.scores.getScoresByEntityId({
3364
+ return this.stores.scores.listScoresByEntityId({
2362
3365
  entityId: _entityId,
2363
3366
  entityType: _entityType,
2364
3367
  pagination: _pagination
2365
3368
  });
2366
3369
  }
3370
+ async listScoresBySpan({
3371
+ traceId,
3372
+ spanId,
3373
+ pagination: _pagination
3374
+ }) {
3375
+ return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination: _pagination });
3376
+ }
2367
3377
  };
2368
3378
 
2369
3379
  exports.MSSQLStore = MSSQLStore;