@mastra/mssql 0.0.0-remove-unused-import-20250909212718 → 0.0.0-remove-unused-model-providers-api-20251030210744

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3,8 +3,10 @@
3
3
  var error = require('@mastra/core/error');
4
4
  var storage = require('@mastra/core/storage');
5
5
  var sql2 = require('mssql');
6
- var utils = require('@mastra/core/utils');
7
6
  var agent = require('@mastra/core/agent');
7
+ var utils = require('@mastra/core/utils');
8
+ var crypto = require('crypto');
9
+ var scores = require('@mastra/core/scores');
8
10
 
9
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
12
 
@@ -20,154 +22,71 @@ 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
  }
33
+ return filters;
34
+ }
35
+ function prepareWhereClause(filters, _schema) {
36
+ const conditions = [];
37
+ const params = {};
38
+ let paramIndex = 1;
39
+ Object.entries(filters).forEach(([key, value]) => {
40
+ if (value === void 0) return;
41
+ const paramName = `p${paramIndex++}`;
42
+ if (key.endsWith("_gte")) {
43
+ const fieldName = key.slice(0, -4);
44
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
45
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
46
+ } else if (key.endsWith("_lte")) {
47
+ const fieldName = key.slice(0, -4);
48
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
49
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
50
+ } else if (value === null) {
51
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
52
+ } else {
53
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
54
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
55
+ }
56
+ });
39
57
  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
58
+ sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
59
+ params
50
60
  };
51
61
  }
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);
118
- }
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
- };
62
+ function transformFromSqlRow({
63
+ tableName,
64
+ sqlRow
65
+ }) {
66
+ const schema = storage.TABLE_SCHEMAS[tableName];
67
+ const result = {};
68
+ Object.entries(sqlRow).forEach(([key, value]) => {
69
+ const columnSchema = schema?.[key];
70
+ if (columnSchema?.type === "jsonb" && typeof value === "string") {
71
+ try {
72
+ result[key] = JSON.parse(value);
73
+ } catch {
74
+ result[key] = value;
130
75
  }
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);
137
- }
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;
76
+ } else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
77
+ result[key] = new Date(value);
78
+ } else if (columnSchema?.type === "timestamp" && value instanceof Date) {
79
+ result[key] = value;
80
+ } else if (columnSchema?.type === "boolean") {
81
+ result[key] = Boolean(value);
82
+ } else {
83
+ result[key] = value;
168
84
  }
169
- }
170
- };
85
+ });
86
+ return result;
87
+ }
88
+
89
+ // src/storage/domains/memory/index.ts
171
90
  var MemoryMSSQL = class extends storage.MemoryStorage {
172
91
  pool;
173
92
  schema;
@@ -199,7 +118,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
199
118
  }
200
119
  async getThreadById({ threadId }) {
201
120
  try {
202
- const sql7 = `SELECT
121
+ const sql5 = `SELECT
203
122
  id,
204
123
  [resourceId],
205
124
  title,
@@ -210,7 +129,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
210
129
  WHERE id = @threadId`;
211
130
  const request = this.pool.request();
212
131
  request.input("threadId", threadId);
213
- const resultSet = await request.query(sql7);
132
+ const resultSet = await request.query(sql5);
214
133
  const thread = resultSet.recordset[0] || null;
215
134
  if (!thread) {
216
135
  return null;
@@ -256,7 +175,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
256
175
  };
257
176
  }
258
177
  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`;
178
+ const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
179
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
260
180
  const dataRequest = this.pool.request();
261
181
  dataRequest.input("resourceId", resourceId);
262
182
  dataRequest.input("perPage", perPage);
@@ -313,7 +233,12 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
313
233
  req.input("id", thread.id);
314
234
  req.input("resourceId", thread.resourceId);
315
235
  req.input("title", thread.title);
316
- req.input("metadata", thread.metadata ? JSON.stringify(thread.metadata) : null);
236
+ const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
237
+ if (metadata === null) {
238
+ req.input("metadata", sql2__default.default.NVarChar, null);
239
+ } else {
240
+ req.input("metadata", metadata);
241
+ }
317
242
  req.input("createdAt", sql2__default.default.DateTime2, thread.createdAt);
318
243
  req.input("updatedAt", sql2__default.default.DateTime2, thread.updatedAt);
319
244
  await req.query(mergeSql);
@@ -340,7 +265,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
340
265
  try {
341
266
  const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
342
267
  const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
343
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection}`;
268
+ const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
269
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
344
270
  const request = this.pool.request();
345
271
  request.input("resourceId", resourceId);
346
272
  const resultSet = await request.query(dataQuery);
@@ -383,7 +309,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
383
309
  };
384
310
  try {
385
311
  const table = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
386
- const sql7 = `UPDATE ${table}
312
+ const sql5 = `UPDATE ${table}
387
313
  SET title = @title,
388
314
  metadata = @metadata,
389
315
  [updatedAt] = @updatedAt
@@ -394,7 +320,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
394
320
  req.input("title", title);
395
321
  req.input("metadata", JSON.stringify(mergedMetadata));
396
322
  req.input("updatedAt", /* @__PURE__ */ new Date());
397
- const result = await req.query(sql7);
323
+ const result = await req.query(sql5);
398
324
  let thread = result.recordset && result.recordset[0];
399
325
  if (thread && "seq_id" in thread) {
400
326
  const { seq_id, ...rest } = thread;
@@ -464,8 +390,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
464
390
  }
465
391
  async _getIncludedMessages({
466
392
  threadId,
467
- selectBy,
468
- orderByStatement
393
+ selectBy
469
394
  }) {
470
395
  if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
471
396
  const include = selectBy?.include;
@@ -493,7 +418,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
493
418
  m.[resourceId],
494
419
  m.seq_id
495
420
  FROM (
496
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
421
+ SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
497
422
  FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
498
423
  WHERE [thread_id] = ${pThreadId}
499
424
  ) AS m
@@ -501,15 +426,17 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
501
426
  OR EXISTS (
502
427
  SELECT 1
503
428
  FROM (
504
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
429
+ SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
505
430
  FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
506
431
  WHERE [thread_id] = ${pThreadId}
507
432
  ) AS target
508
433
  WHERE target.id = ${pId}
509
434
  AND (
510
- (m.row_num <= target.row_num + ${pPrev} AND m.row_num > target.row_num)
435
+ -- Get previous messages (messages that come BEFORE the target)
436
+ (m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
511
437
  OR
512
- (m.row_num >= target.row_num - ${pNext} AND m.row_num < target.row_num)
438
+ -- Get next messages (messages that come AFTER the target)
439
+ (m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
513
440
  )
514
441
  )
515
442
  `
@@ -548,7 +475,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
548
475
  let rows = [];
549
476
  const include = selectBy?.include || [];
550
477
  if (include?.length) {
551
- const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
478
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
552
479
  if (includeMessages) {
553
480
  rows.push(...includeMessages);
554
481
  }
@@ -589,14 +516,11 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
589
516
  error$1
590
517
  );
591
518
  this.logger?.error?.(mastraError.toString());
592
- this.logger?.trackException(mastraError);
519
+ this.logger?.trackException?.(mastraError);
593
520
  return [];
594
521
  }
595
522
  }
596
- async getMessagesById({
597
- messageIds,
598
- format
599
- }) {
523
+ async listMessagesById({ messageIds }) {
600
524
  if (messageIds.length === 0) return [];
601
525
  const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
602
526
  const orderByStatement = `ORDER BY [seq_id] DESC`;
@@ -614,8 +538,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
614
538
  return timeDiff;
615
539
  });
616
540
  rows = rows.map(({ seq_id, ...rest }) => rest);
617
- if (format === `v1`) return this._parseAndFormatMessages(rows, format);
618
- return this._parseAndFormatMessages(rows, `v2`);
541
+ const messages = this._parseAndFormatMessages(rows, `v2`);
542
+ return messages;
619
543
  } catch (error$1) {
620
544
  const mastraError = new error.MastraError(
621
545
  {
@@ -629,10 +553,139 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
629
553
  error$1
630
554
  );
631
555
  this.logger?.error?.(mastraError.toString());
632
- this.logger?.trackException(mastraError);
556
+ this.logger?.trackException?.(mastraError);
633
557
  return [];
634
558
  }
635
559
  }
560
+ async listMessages(args) {
561
+ const { threadId, resourceId, include, filter, limit, offset = 0, orderBy } = args;
562
+ if (!threadId.trim()) {
563
+ throw new error.MastraError(
564
+ {
565
+ id: "STORAGE_MSSQL_LIST_MESSAGES_INVALID_THREAD_ID",
566
+ domain: error.ErrorDomain.STORAGE,
567
+ category: error.ErrorCategory.THIRD_PARTY,
568
+ details: { threadId }
569
+ },
570
+ new Error("threadId must be a non-empty string")
571
+ );
572
+ }
573
+ try {
574
+ let perPage = 40;
575
+ if (limit !== void 0) {
576
+ if (limit === false) {
577
+ perPage = Number.MAX_SAFE_INTEGER;
578
+ } else if (limit === 0) {
579
+ perPage = 0;
580
+ } else if (typeof limit === "number" && limit > 0) {
581
+ perPage = limit;
582
+ }
583
+ }
584
+ const page = perPage === 0 ? 0 : Math.floor(offset / perPage);
585
+ const sortField = orderBy?.field || "createdAt";
586
+ const sortDirection = orderBy?.direction || "DESC";
587
+ const orderByStatement = `ORDER BY [${sortField}] ${sortDirection}`;
588
+ const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
589
+ const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
590
+ const conditions = ["[thread_id] = @threadId"];
591
+ const request = this.pool.request();
592
+ request.input("threadId", threadId);
593
+ if (resourceId) {
594
+ conditions.push("[resourceId] = @resourceId");
595
+ request.input("resourceId", resourceId);
596
+ }
597
+ if (filter?.dateRange?.start) {
598
+ conditions.push("[createdAt] >= @fromDate");
599
+ request.input("fromDate", filter.dateRange.start);
600
+ }
601
+ if (filter?.dateRange?.end) {
602
+ conditions.push("[createdAt] <= @toDate");
603
+ request.input("toDate", filter.dateRange.end);
604
+ }
605
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
606
+ const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
607
+ const countResult = await request.query(countQuery);
608
+ const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
609
+ const dataQuery = `${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
610
+ request.input("offset", offset);
611
+ if (perPage > 2147483647) {
612
+ request.input("limit", sql2__default.default.BigInt, perPage);
613
+ } else {
614
+ request.input("limit", perPage);
615
+ }
616
+ const rowsResult = await request.query(dataQuery);
617
+ const rows = rowsResult.recordset || [];
618
+ const messages = [...rows];
619
+ if (total === 0 && messages.length === 0) {
620
+ return {
621
+ messages: [],
622
+ total: 0,
623
+ page,
624
+ perPage,
625
+ hasMore: false
626
+ };
627
+ }
628
+ const messageIds = new Set(messages.map((m) => m.id));
629
+ if (include && include.length > 0) {
630
+ const selectBy = { include };
631
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
632
+ if (includeMessages) {
633
+ for (const includeMsg of includeMessages) {
634
+ if (!messageIds.has(includeMsg.id)) {
635
+ messages.push(includeMsg);
636
+ messageIds.add(includeMsg.id);
637
+ }
638
+ }
639
+ }
640
+ }
641
+ const parsed = this._parseAndFormatMessages(messages, "v2");
642
+ let finalMessages = parsed;
643
+ finalMessages = finalMessages.sort((a, b) => {
644
+ const aValue = sortField === "createdAt" ? new Date(a.createdAt).getTime() : a[sortField];
645
+ const bValue = sortField === "createdAt" ? new Date(b.createdAt).getTime() : b[sortField];
646
+ return sortDirection === "ASC" ? aValue - bValue : bValue - aValue;
647
+ });
648
+ const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
649
+ const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
650
+ const hasMore = limit === false ? false : allThreadMessagesReturned ? false : offset + rows.length < total;
651
+ return {
652
+ messages: finalMessages,
653
+ total,
654
+ page,
655
+ perPage,
656
+ hasMore
657
+ };
658
+ } catch (error$1) {
659
+ const errorPerPage = limit === false ? Number.MAX_SAFE_INTEGER : limit === 0 ? 0 : limit || 40;
660
+ const mastraError = new error.MastraError(
661
+ {
662
+ id: "MASTRA_STORAGE_MSSQL_STORE_LIST_MESSAGES_FAILED",
663
+ domain: error.ErrorDomain.STORAGE,
664
+ category: error.ErrorCategory.THIRD_PARTY,
665
+ details: {
666
+ threadId,
667
+ resourceId: resourceId ?? ""
668
+ }
669
+ },
670
+ error$1
671
+ );
672
+ this.logger?.error?.(mastraError.toString());
673
+ this.logger?.trackException?.(mastraError);
674
+ return {
675
+ messages: [],
676
+ total: 0,
677
+ page: errorPerPage === 0 ? 0 : Math.floor(offset / errorPerPage),
678
+ perPage: errorPerPage,
679
+ hasMore: false
680
+ };
681
+ }
682
+ }
683
+ async listThreadsByResourceId(args) {
684
+ const { resourceId, limit, offset, orderBy, sortDirection } = args;
685
+ const page = Math.floor(offset / limit);
686
+ const perPage = limit;
687
+ return this.getThreadsByResourceIdPaginated({ resourceId, page, perPage, orderBy, sortDirection });
688
+ }
636
689
  async getMessagesPaginated(args) {
637
690
  const { threadId, resourceId, format, selectBy } = args;
638
691
  const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
@@ -644,7 +697,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
644
697
  const orderByStatement = `ORDER BY [seq_id] DESC`;
645
698
  let messages = [];
646
699
  if (selectBy?.include?.length) {
647
- const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
700
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
648
701
  if (includeMessages) messages.push(...includeMessages);
649
702
  }
650
703
  const perPage = perPageInput !== void 0 ? perPageInput : storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
@@ -691,7 +744,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
691
744
  const parsed = this._parseAndFormatMessages(messages, format);
692
745
  return {
693
746
  messages: parsed,
694
- total: total + excludeIds.length,
747
+ total,
695
748
  page,
696
749
  perPage,
697
750
  hasMore: currentOffset + rows.length < total
@@ -711,7 +764,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
711
764
  error$1
712
765
  );
713
766
  this.logger?.error?.(mastraError.toString());
714
- this.logger?.trackException(mastraError);
767
+ this.logger?.trackException?.(mastraError);
715
768
  return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
716
769
  }
717
770
  }
@@ -978,8 +1031,10 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
978
1031
  return null;
979
1032
  }
980
1033
  return {
981
- ...result,
982
- workingMemory: typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
1034
+ id: result.id,
1035
+ createdAt: result.createdAt,
1036
+ updatedAt: result.updatedAt,
1037
+ workingMemory: result.workingMemory,
983
1038
  metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
984
1039
  };
985
1040
  } catch (error$1) {
@@ -993,7 +1048,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
993
1048
  error$1
994
1049
  );
995
1050
  this.logger?.error?.(mastraError.toString());
996
- this.logger?.trackException(mastraError);
1051
+ this.logger?.trackException?.(mastraError);
997
1052
  throw mastraError;
998
1053
  }
999
1054
  }
@@ -1002,7 +1057,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1002
1057
  tableName: storage.TABLE_RESOURCES,
1003
1058
  record: {
1004
1059
  ...resource,
1005
- metadata: JSON.stringify(resource.metadata)
1060
+ metadata: resource.metadata
1006
1061
  }
1007
1062
  });
1008
1063
  return resource;
@@ -1060,132 +1115,457 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1060
1115
  error$1
1061
1116
  );
1062
1117
  this.logger?.error?.(mastraError.toString());
1063
- this.logger?.trackException(mastraError);
1118
+ this.logger?.trackException?.(mastraError);
1064
1119
  throw mastraError;
1065
1120
  }
1066
1121
  }
1067
1122
  };
1068
- var StoreOperationsMSSQL = class extends storage.StoreOperations {
1123
+ var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
1069
1124
  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 }) {
1125
+ operations;
1126
+ schema;
1127
+ constructor({
1128
+ pool,
1129
+ operations,
1130
+ schema
1131
+ }) {
1098
1132
  super();
1099
1133
  this.pool = pool;
1100
- this.schemaName = schemaName;
1134
+ this.operations = operations;
1135
+ this.schema = schema;
1101
1136
  }
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;
1137
+ get aiTracingStrategy() {
1138
+ return {
1139
+ preferred: "batch-with-updates",
1140
+ supported: ["batch-with-updates", "insert-only"]
1141
+ };
1113
1142
  }
1114
- async setupSchema() {
1115
- if (!this.schemaName || this.schemaSetupComplete) {
1116
- return;
1117
- }
1118
- if (!this.setupSchemaPromise) {
1119
- this.setupSchemaPromise = (async () => {
1120
- try {
1121
- const checkRequest = this.pool.request();
1122
- checkRequest.input("schemaName", this.schemaName);
1123
- const checkResult = await checkRequest.query(`
1124
- SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
1125
- `);
1126
- const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1127
- if (!schemaExists) {
1128
- try {
1129
- await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
1130
- this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
1131
- } catch (error) {
1132
- this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
1133
- throw new Error(
1134
- `Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
1135
- );
1136
- }
1143
+ async createAISpan(span) {
1144
+ try {
1145
+ const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
1146
+ const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
1147
+ const record = {
1148
+ ...span,
1149
+ startedAt,
1150
+ endedAt
1151
+ // Note: createdAt/updatedAt will be set by default values
1152
+ };
1153
+ return this.operations.insert({ tableName: storage.TABLE_AI_SPANS, record });
1154
+ } catch (error$1) {
1155
+ throw new error.MastraError(
1156
+ {
1157
+ id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
1158
+ domain: error.ErrorDomain.STORAGE,
1159
+ category: error.ErrorCategory.USER,
1160
+ details: {
1161
+ spanId: span.spanId,
1162
+ traceId: span.traceId,
1163
+ spanType: span.spanType,
1164
+ spanName: span.name
1137
1165
  }
1138
- this.schemaSetupComplete = true;
1139
- this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
1140
- } catch (error) {
1141
- this.schemaSetupComplete = void 0;
1142
- this.setupSchemaPromise = null;
1143
- throw error;
1144
- } finally {
1145
- this.setupSchemaPromise = null;
1146
- }
1147
- })();
1166
+ },
1167
+ error$1
1168
+ );
1148
1169
  }
1149
- await this.setupSchemaPromise;
1150
1170
  }
1151
- async insert({ tableName, record }) {
1171
+ async getAITrace(traceId) {
1152
1172
  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));
1163
- } else {
1164
- request.input(`param${i}`, value);
1165
- }
1173
+ const tableName = getTableName({
1174
+ indexName: storage.TABLE_AI_SPANS,
1175
+ schemaName: getSchemaName(this.schema)
1166
1176
  });
1167
- await request.query(insertSql);
1177
+ const request = this.pool.request();
1178
+ request.input("traceId", traceId);
1179
+ const result = await request.query(
1180
+ `SELECT
1181
+ [traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
1182
+ [attributes], [metadata], [links], [input], [output], [error], [isEvent],
1183
+ [startedAt], [endedAt], [createdAt], [updatedAt]
1184
+ FROM ${tableName}
1185
+ WHERE [traceId] = @traceId
1186
+ ORDER BY [startedAt] DESC`
1187
+ );
1188
+ if (!result.recordset || result.recordset.length === 0) {
1189
+ return null;
1190
+ }
1191
+ return {
1192
+ traceId,
1193
+ spans: result.recordset.map(
1194
+ (span) => transformFromSqlRow({
1195
+ tableName: storage.TABLE_AI_SPANS,
1196
+ sqlRow: span
1197
+ })
1198
+ )
1199
+ };
1168
1200
  } catch (error$1) {
1169
1201
  throw new error.MastraError(
1170
1202
  {
1171
- id: "MASTRA_STORAGE_MSSQL_STORE_INSERT_FAILED",
1203
+ id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
1172
1204
  domain: error.ErrorDomain.STORAGE,
1173
- category: error.ErrorCategory.THIRD_PARTY,
1205
+ category: error.ErrorCategory.USER,
1174
1206
  details: {
1175
- tableName
1207
+ traceId
1176
1208
  }
1177
1209
  },
1178
1210
  error$1
1179
1211
  );
1180
1212
  }
1181
1213
  }
1182
- async clearTable({ tableName }) {
1183
- const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
1214
+ async updateAISpan({
1215
+ spanId,
1216
+ traceId,
1217
+ updates
1218
+ }) {
1219
+ try {
1220
+ const data = { ...updates };
1221
+ if (data.endedAt instanceof Date) {
1222
+ data.endedAt = data.endedAt.toISOString();
1223
+ }
1224
+ if (data.startedAt instanceof Date) {
1225
+ data.startedAt = data.startedAt.toISOString();
1226
+ }
1227
+ await this.operations.update({
1228
+ tableName: storage.TABLE_AI_SPANS,
1229
+ keys: { spanId, traceId },
1230
+ data
1231
+ });
1232
+ } catch (error$1) {
1233
+ throw new error.MastraError(
1234
+ {
1235
+ id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
1236
+ domain: error.ErrorDomain.STORAGE,
1237
+ category: error.ErrorCategory.USER,
1238
+ details: {
1239
+ spanId,
1240
+ traceId
1241
+ }
1242
+ },
1243
+ error$1
1244
+ );
1245
+ }
1246
+ }
1247
+ async getAITracesPaginated({
1248
+ filters,
1249
+ pagination
1250
+ }) {
1251
+ const page = pagination?.page ?? 0;
1252
+ const perPage = pagination?.perPage ?? 10;
1253
+ const { entityId, entityType, ...actualFilters } = filters || {};
1254
+ const filtersWithDateRange = {
1255
+ ...actualFilters,
1256
+ ...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
1257
+ parentSpanId: null
1258
+ // Only get root spans for traces
1259
+ };
1260
+ const whereClause = prepareWhereClause(filtersWithDateRange);
1261
+ let actualWhereClause = whereClause.sql;
1262
+ const params = { ...whereClause.params };
1263
+ let currentParamIndex = Object.keys(params).length + 1;
1264
+ if (entityId && entityType) {
1265
+ let name = "";
1266
+ if (entityType === "workflow") {
1267
+ name = `workflow run: '${entityId}'`;
1268
+ } else if (entityType === "agent") {
1269
+ name = `agent run: '${entityId}'`;
1270
+ } else {
1271
+ const error$1 = new error.MastraError({
1272
+ id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
1273
+ domain: error.ErrorDomain.STORAGE,
1274
+ category: error.ErrorCategory.USER,
1275
+ details: {
1276
+ entityType
1277
+ },
1278
+ text: `Cannot filter by entity type: ${entityType}`
1279
+ });
1280
+ throw error$1;
1281
+ }
1282
+ const entityParam = `p${currentParamIndex++}`;
1283
+ if (actualWhereClause) {
1284
+ actualWhereClause += ` AND [name] = @${entityParam}`;
1285
+ } else {
1286
+ actualWhereClause = ` WHERE [name] = @${entityParam}`;
1287
+ }
1288
+ params[entityParam] = name;
1289
+ }
1290
+ const tableName = getTableName({
1291
+ indexName: storage.TABLE_AI_SPANS,
1292
+ schemaName: getSchemaName(this.schema)
1293
+ });
1294
+ try {
1295
+ const countRequest = this.pool.request();
1296
+ Object.entries(params).forEach(([key, value]) => {
1297
+ countRequest.input(key, value);
1298
+ });
1299
+ const countResult = await countRequest.query(
1300
+ `SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
1301
+ );
1302
+ const total = countResult.recordset[0]?.count ?? 0;
1303
+ if (total === 0) {
1304
+ return {
1305
+ pagination: {
1306
+ total: 0,
1307
+ page,
1308
+ perPage,
1309
+ hasMore: false
1310
+ },
1311
+ spans: []
1312
+ };
1313
+ }
1314
+ const dataRequest = this.pool.request();
1315
+ Object.entries(params).forEach(([key, value]) => {
1316
+ dataRequest.input(key, value);
1317
+ });
1318
+ dataRequest.input("offset", page * perPage);
1319
+ dataRequest.input("limit", perPage);
1320
+ const dataResult = await dataRequest.query(
1321
+ `SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
1322
+ );
1323
+ const spans = dataResult.recordset.map(
1324
+ (row) => transformFromSqlRow({
1325
+ tableName: storage.TABLE_AI_SPANS,
1326
+ sqlRow: row
1327
+ })
1328
+ );
1329
+ return {
1330
+ pagination: {
1331
+ total,
1332
+ page,
1333
+ perPage,
1334
+ hasMore: (page + 1) * perPage < total
1335
+ },
1336
+ spans
1337
+ };
1338
+ } catch (error$1) {
1339
+ throw new error.MastraError(
1340
+ {
1341
+ id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
1342
+ domain: error.ErrorDomain.STORAGE,
1343
+ category: error.ErrorCategory.USER
1344
+ },
1345
+ error$1
1346
+ );
1347
+ }
1348
+ }
1349
+ async batchCreateAISpans(args) {
1350
+ if (!args.records || args.records.length === 0) {
1351
+ return;
1352
+ }
1353
+ try {
1354
+ await this.operations.batchInsert({
1355
+ tableName: storage.TABLE_AI_SPANS,
1356
+ records: args.records.map((span) => ({
1357
+ ...span,
1358
+ startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
1359
+ endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
1360
+ }))
1361
+ });
1362
+ } catch (error$1) {
1363
+ throw new error.MastraError(
1364
+ {
1365
+ id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
1366
+ domain: error.ErrorDomain.STORAGE,
1367
+ category: error.ErrorCategory.USER,
1368
+ details: {
1369
+ count: args.records.length
1370
+ }
1371
+ },
1372
+ error$1
1373
+ );
1374
+ }
1375
+ }
1376
+ async batchUpdateAISpans(args) {
1377
+ if (!args.records || args.records.length === 0) {
1378
+ return;
1379
+ }
1380
+ try {
1381
+ const updates = args.records.map(({ traceId, spanId, updates: data }) => {
1382
+ const processedData = { ...data };
1383
+ if (processedData.endedAt instanceof Date) {
1384
+ processedData.endedAt = processedData.endedAt.toISOString();
1385
+ }
1386
+ if (processedData.startedAt instanceof Date) {
1387
+ processedData.startedAt = processedData.startedAt.toISOString();
1388
+ }
1389
+ return {
1390
+ keys: { spanId, traceId },
1391
+ data: processedData
1392
+ };
1393
+ });
1394
+ await this.operations.batchUpdate({
1395
+ tableName: storage.TABLE_AI_SPANS,
1396
+ updates
1397
+ });
1398
+ } catch (error$1) {
1399
+ throw new error.MastraError(
1400
+ {
1401
+ id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
1402
+ domain: error.ErrorDomain.STORAGE,
1403
+ category: error.ErrorCategory.USER,
1404
+ details: {
1405
+ count: args.records.length
1406
+ }
1407
+ },
1408
+ error$1
1409
+ );
1410
+ }
1411
+ }
1412
+ async batchDeleteAITraces(args) {
1413
+ if (!args.traceIds || args.traceIds.length === 0) {
1414
+ return;
1415
+ }
1416
+ try {
1417
+ const keys = args.traceIds.map((traceId) => ({ traceId }));
1418
+ await this.operations.batchDelete({
1419
+ tableName: storage.TABLE_AI_SPANS,
1420
+ keys
1421
+ });
1422
+ } catch (error$1) {
1423
+ throw new error.MastraError(
1424
+ {
1425
+ id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
1426
+ domain: error.ErrorDomain.STORAGE,
1427
+ category: error.ErrorCategory.USER,
1428
+ details: {
1429
+ count: args.traceIds.length
1430
+ }
1431
+ },
1432
+ error$1
1433
+ );
1434
+ }
1435
+ }
1436
+ };
1437
+ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1438
+ pool;
1439
+ schemaName;
1440
+ setupSchemaPromise = null;
1441
+ schemaSetupComplete = void 0;
1442
+ getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
1443
+ switch (type) {
1444
+ case "text":
1445
+ if (useLargeStorage) {
1446
+ return "NVARCHAR(MAX)";
1447
+ }
1448
+ return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
1449
+ case "timestamp":
1450
+ return "DATETIME2(7)";
1451
+ case "uuid":
1452
+ return "UNIQUEIDENTIFIER";
1453
+ case "jsonb":
1454
+ return "NVARCHAR(MAX)";
1455
+ case "integer":
1456
+ return "INT";
1457
+ case "bigint":
1458
+ return "BIGINT";
1459
+ case "float":
1460
+ return "FLOAT";
1461
+ case "boolean":
1462
+ return "BIT";
1463
+ default:
1464
+ throw new error.MastraError({
1465
+ id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
1466
+ domain: error.ErrorDomain.STORAGE,
1467
+ category: error.ErrorCategory.THIRD_PARTY
1468
+ });
1469
+ }
1470
+ }
1471
+ constructor({ pool, schemaName }) {
1472
+ super();
1473
+ this.pool = pool;
1474
+ this.schemaName = schemaName;
1475
+ }
1476
+ async hasColumn(table, column) {
1477
+ const schema = this.schemaName || "dbo";
1478
+ const request = this.pool.request();
1479
+ request.input("schema", schema);
1480
+ request.input("table", table);
1481
+ request.input("column", column);
1482
+ request.input("columnLower", column.toLowerCase());
1483
+ const result = await request.query(
1484
+ `SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
1485
+ );
1486
+ return result.recordset.length > 0;
1487
+ }
1488
+ async setupSchema() {
1489
+ if (!this.schemaName || this.schemaSetupComplete) {
1490
+ return;
1491
+ }
1492
+ if (!this.setupSchemaPromise) {
1493
+ this.setupSchemaPromise = (async () => {
1494
+ try {
1495
+ const checkRequest = this.pool.request();
1496
+ checkRequest.input("schemaName", this.schemaName);
1497
+ const checkResult = await checkRequest.query(`
1498
+ SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
1499
+ `);
1500
+ const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1501
+ if (!schemaExists) {
1502
+ try {
1503
+ await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
1504
+ this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
1505
+ } catch (error) {
1506
+ this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
1507
+ throw new Error(
1508
+ `Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
1509
+ );
1510
+ }
1511
+ }
1512
+ this.schemaSetupComplete = true;
1513
+ this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
1514
+ } catch (error) {
1515
+ this.schemaSetupComplete = void 0;
1516
+ this.setupSchemaPromise = null;
1517
+ throw error;
1518
+ } finally {
1519
+ this.setupSchemaPromise = null;
1520
+ }
1521
+ })();
1522
+ }
1523
+ await this.setupSchemaPromise;
1524
+ }
1525
+ async insert({
1526
+ tableName,
1527
+ record,
1528
+ transaction
1529
+ }) {
1530
+ try {
1531
+ const columns = Object.keys(record);
1532
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
1533
+ const paramNames = columns.map((_, i) => `@param${i}`);
1534
+ const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
1535
+ const request = transaction ? transaction.request() : this.pool.request();
1536
+ columns.forEach((col, i) => {
1537
+ const value = record[col];
1538
+ const preparedValue = this.prepareValue(value, col, tableName);
1539
+ if (preparedValue instanceof Date) {
1540
+ request.input(`param${i}`, sql2__default.default.DateTime2, preparedValue);
1541
+ } else if (preparedValue === null || preparedValue === void 0) {
1542
+ request.input(`param${i}`, this.getMssqlType(tableName, col), null);
1543
+ } else {
1544
+ request.input(`param${i}`, preparedValue);
1545
+ }
1546
+ });
1547
+ await request.query(insertSql);
1548
+ } catch (error$1) {
1549
+ throw new error.MastraError(
1550
+ {
1551
+ id: "MASTRA_STORAGE_MSSQL_STORE_INSERT_FAILED",
1552
+ domain: error.ErrorDomain.STORAGE,
1553
+ category: error.ErrorCategory.THIRD_PARTY,
1554
+ details: {
1555
+ tableName
1556
+ }
1557
+ },
1558
+ error$1
1559
+ );
1560
+ }
1561
+ }
1562
+ async clearTable({ tableName }) {
1563
+ const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
1184
1564
  try {
1185
1565
  try {
1186
1566
  await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
1187
1567
  } catch (truncateError) {
1188
- if (truncateError.message && truncateError.message.includes("foreign key")) {
1568
+ if (truncateError?.number === 4712) {
1189
1569
  await this.pool.request().query(`DELETE FROM ${fullTableName}`);
1190
1570
  } else {
1191
1571
  throw truncateError;
@@ -1208,9 +1588,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1208
1588
  getDefaultValue(type) {
1209
1589
  switch (type) {
1210
1590
  case "timestamp":
1211
- return "DEFAULT SYSDATETIMEOFFSET()";
1591
+ return "DEFAULT SYSUTCDATETIME()";
1212
1592
  case "jsonb":
1213
1593
  return "DEFAULT N'{}'";
1594
+ case "boolean":
1595
+ return "DEFAULT 0";
1214
1596
  default:
1215
1597
  return super.getDefaultValue(type);
1216
1598
  }
@@ -1221,13 +1603,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
1221
1603
  }) {
1222
1604
  try {
1223
1605
  const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
1606
+ const largeDataColumns = [
1607
+ "workingMemory",
1608
+ "snapshot",
1609
+ "metadata",
1610
+ "content",
1611
+ // messages.content - can be very long conversation content
1612
+ "input",
1613
+ // evals.input - test input data
1614
+ "output",
1615
+ // evals.output - test output data
1616
+ "instructions",
1617
+ // evals.instructions - evaluation instructions
1618
+ "other"
1619
+ // traces.other - additional trace data
1620
+ ];
1224
1621
  const columns = Object.entries(schema).map(([name, def]) => {
1225
1622
  const parsedName = utils.parseSqlIdentifier(name, "column name");
1226
1623
  const constraints = [];
1227
1624
  if (def.primaryKey) constraints.push("PRIMARY KEY");
1228
1625
  if (!def.nullable) constraints.push("NOT NULL");
1229
1626
  const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
1230
- return `[${parsedName}] ${this.getSqlType(def.type, isIndexed)} ${constraints.join(" ")}`.trim();
1627
+ const useLargeStorage = largeDataColumns.includes(name);
1628
+ return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
1231
1629
  }).join(",\n");
1232
1630
  if (this.schemaName) {
1233
1631
  await this.setupSchema();
@@ -1314,7 +1712,19 @@ ${columns}
1314
1712
  const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1315
1713
  if (!columnExists) {
1316
1714
  const columnDef = schema[columnName];
1317
- const sqlType = this.getSqlType(columnDef.type);
1715
+ const largeDataColumns = [
1716
+ "workingMemory",
1717
+ "snapshot",
1718
+ "metadata",
1719
+ "content",
1720
+ "input",
1721
+ "output",
1722
+ "instructions",
1723
+ "other"
1724
+ ];
1725
+ const useLargeStorage = largeDataColumns.includes(columnName);
1726
+ const isIndexed = !!columnDef.primaryKey;
1727
+ const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
1318
1728
  const nullable = columnDef.nullable === false ? "NOT NULL" : "";
1319
1729
  const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
1320
1730
  const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
@@ -1342,13 +1752,17 @@ ${columns}
1342
1752
  try {
1343
1753
  const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
1344
1754
  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}`;
1755
+ const sql5 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
1347
1756
  const request = this.pool.request();
1348
- values.forEach((value, i) => {
1349
- request.input(`param${i}`, value);
1757
+ keyEntries.forEach(([key, value], i) => {
1758
+ const preparedValue = this.prepareValue(value, key, tableName);
1759
+ if (preparedValue === null || preparedValue === void 0) {
1760
+ request.input(`param${i}`, this.getMssqlType(tableName, key), null);
1761
+ } else {
1762
+ request.input(`param${i}`, preparedValue);
1763
+ }
1350
1764
  });
1351
- const resultSet = await request.query(sql7);
1765
+ const resultSet = await request.query(sql5);
1352
1766
  const result = resultSet.recordset[0] || null;
1353
1767
  if (!result) {
1354
1768
  return null;
@@ -1380,63 +1794,599 @@ ${columns}
1380
1794
  try {
1381
1795
  await transaction.begin();
1382
1796
  for (const record of records) {
1383
- await this.insert({ tableName, record });
1797
+ await this.insert({ tableName, record, transaction });
1798
+ }
1799
+ await transaction.commit();
1800
+ } catch (error$1) {
1801
+ await transaction.rollback();
1802
+ throw new error.MastraError(
1803
+ {
1804
+ id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
1805
+ domain: error.ErrorDomain.STORAGE,
1806
+ category: error.ErrorCategory.THIRD_PARTY,
1807
+ details: {
1808
+ tableName,
1809
+ numberOfRecords: records.length
1810
+ }
1811
+ },
1812
+ error$1
1813
+ );
1814
+ }
1815
+ }
1816
+ async dropTable({ tableName }) {
1817
+ try {
1818
+ const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
1819
+ await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
1820
+ } catch (error$1) {
1821
+ throw new error.MastraError(
1822
+ {
1823
+ id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
1824
+ domain: error.ErrorDomain.STORAGE,
1825
+ category: error.ErrorCategory.THIRD_PARTY,
1826
+ details: {
1827
+ tableName
1828
+ }
1829
+ },
1830
+ error$1
1831
+ );
1832
+ }
1833
+ }
1834
+ /**
1835
+ * Prepares a value for database operations, handling Date objects and JSON serialization
1836
+ */
1837
+ prepareValue(value, columnName, tableName) {
1838
+ if (value === null || value === void 0) {
1839
+ return value;
1840
+ }
1841
+ if (value instanceof Date) {
1842
+ return value;
1843
+ }
1844
+ const schema = storage.TABLE_SCHEMAS[tableName];
1845
+ const columnSchema = schema?.[columnName];
1846
+ if (columnSchema?.type === "boolean") {
1847
+ return value ? 1 : 0;
1848
+ }
1849
+ if (columnSchema?.type === "jsonb") {
1850
+ return JSON.stringify(value);
1851
+ }
1852
+ if (typeof value === "object") {
1853
+ return JSON.stringify(value);
1854
+ }
1855
+ return value;
1856
+ }
1857
+ /**
1858
+ * Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
1859
+ */
1860
+ getMssqlType(tableName, columnName) {
1861
+ const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
1862
+ switch (col?.type) {
1863
+ case "text":
1864
+ return sql2__default.default.NVarChar;
1865
+ case "timestamp":
1866
+ return sql2__default.default.DateTime2;
1867
+ case "uuid":
1868
+ return sql2__default.default.UniqueIdentifier;
1869
+ case "jsonb":
1870
+ return sql2__default.default.NVarChar;
1871
+ case "integer":
1872
+ return sql2__default.default.Int;
1873
+ case "bigint":
1874
+ return sql2__default.default.BigInt;
1875
+ case "float":
1876
+ return sql2__default.default.Float;
1877
+ case "boolean":
1878
+ return sql2__default.default.Bit;
1879
+ default:
1880
+ return sql2__default.default.NVarChar;
1881
+ }
1882
+ }
1883
+ /**
1884
+ * Update a single record in the database
1885
+ */
1886
+ async update({
1887
+ tableName,
1888
+ keys,
1889
+ data,
1890
+ transaction
1891
+ }) {
1892
+ try {
1893
+ if (!data || Object.keys(data).length === 0) {
1894
+ throw new error.MastraError({
1895
+ id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
1896
+ domain: error.ErrorDomain.STORAGE,
1897
+ category: error.ErrorCategory.USER,
1898
+ text: "Cannot update with empty data payload"
1899
+ });
1900
+ }
1901
+ if (!keys || Object.keys(keys).length === 0) {
1902
+ throw new error.MastraError({
1903
+ id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
1904
+ domain: error.ErrorDomain.STORAGE,
1905
+ category: error.ErrorCategory.USER,
1906
+ text: "Cannot update without keys to identify records"
1907
+ });
1908
+ }
1909
+ const setClauses = [];
1910
+ const request = transaction ? transaction.request() : this.pool.request();
1911
+ let paramIndex = 0;
1912
+ Object.entries(data).forEach(([key, value]) => {
1913
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1914
+ const paramName = `set${paramIndex++}`;
1915
+ setClauses.push(`[${parsedKey}] = @${paramName}`);
1916
+ const preparedValue = this.prepareValue(value, key, tableName);
1917
+ if (preparedValue === null || preparedValue === void 0) {
1918
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1919
+ } else {
1920
+ request.input(paramName, preparedValue);
1921
+ }
1922
+ });
1923
+ const whereConditions = [];
1924
+ Object.entries(keys).forEach(([key, value]) => {
1925
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1926
+ const paramName = `where${paramIndex++}`;
1927
+ whereConditions.push(`[${parsedKey}] = @${paramName}`);
1928
+ const preparedValue = this.prepareValue(value, key, tableName);
1929
+ if (preparedValue === null || preparedValue === void 0) {
1930
+ request.input(paramName, this.getMssqlType(tableName, key), null);
1931
+ } else {
1932
+ request.input(paramName, preparedValue);
1933
+ }
1934
+ });
1935
+ const tableName_ = getTableName({
1936
+ indexName: tableName,
1937
+ schemaName: getSchemaName(this.schemaName)
1938
+ });
1939
+ const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
1940
+ await request.query(updateSql);
1941
+ } catch (error$1) {
1942
+ throw new error.MastraError(
1943
+ {
1944
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
1945
+ domain: error.ErrorDomain.STORAGE,
1946
+ category: error.ErrorCategory.THIRD_PARTY,
1947
+ details: {
1948
+ tableName
1949
+ }
1950
+ },
1951
+ error$1
1952
+ );
1953
+ }
1954
+ }
1955
+ /**
1956
+ * Update multiple records in a single batch transaction
1957
+ */
1958
+ async batchUpdate({
1959
+ tableName,
1960
+ updates
1961
+ }) {
1962
+ const transaction = this.pool.transaction();
1963
+ try {
1964
+ await transaction.begin();
1965
+ for (const { keys, data } of updates) {
1966
+ await this.update({ tableName, keys, data, transaction });
1967
+ }
1968
+ await transaction.commit();
1969
+ } catch (error$1) {
1970
+ await transaction.rollback();
1971
+ throw new error.MastraError(
1972
+ {
1973
+ id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
1974
+ domain: error.ErrorDomain.STORAGE,
1975
+ category: error.ErrorCategory.THIRD_PARTY,
1976
+ details: {
1977
+ tableName,
1978
+ numberOfRecords: updates.length
1979
+ }
1980
+ },
1981
+ error$1
1982
+ );
1983
+ }
1984
+ }
1985
+ /**
1986
+ * Delete multiple records by keys
1987
+ */
1988
+ async batchDelete({ tableName, keys }) {
1989
+ if (keys.length === 0) {
1990
+ return;
1991
+ }
1992
+ const tableName_ = getTableName({
1993
+ indexName: tableName,
1994
+ schemaName: getSchemaName(this.schemaName)
1995
+ });
1996
+ const transaction = this.pool.transaction();
1997
+ try {
1998
+ await transaction.begin();
1999
+ for (const keySet of keys) {
2000
+ const conditions = [];
2001
+ const request = transaction.request();
2002
+ let paramIndex = 0;
2003
+ Object.entries(keySet).forEach(([key, value]) => {
2004
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
2005
+ const paramName = `p${paramIndex++}`;
2006
+ conditions.push(`[${parsedKey}] = @${paramName}`);
2007
+ const preparedValue = this.prepareValue(value, key, tableName);
2008
+ if (preparedValue === null || preparedValue === void 0) {
2009
+ request.input(paramName, this.getMssqlType(tableName, key), null);
2010
+ } else {
2011
+ request.input(paramName, preparedValue);
2012
+ }
2013
+ });
2014
+ const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
2015
+ await request.query(deleteSql);
2016
+ }
2017
+ await transaction.commit();
2018
+ } catch (error$1) {
2019
+ await transaction.rollback();
2020
+ throw new error.MastraError(
2021
+ {
2022
+ id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
2023
+ domain: error.ErrorDomain.STORAGE,
2024
+ category: error.ErrorCategory.THIRD_PARTY,
2025
+ details: {
2026
+ tableName,
2027
+ numberOfRecords: keys.length
2028
+ }
2029
+ },
2030
+ error$1
2031
+ );
2032
+ }
2033
+ }
2034
+ /**
2035
+ * Create a new index on a table
2036
+ */
2037
+ async createIndex(options) {
2038
+ try {
2039
+ const { name, table, columns, unique = false, where } = options;
2040
+ const schemaName = this.schemaName || "dbo";
2041
+ const fullTableName = getTableName({
2042
+ indexName: table,
2043
+ schemaName: getSchemaName(this.schemaName)
2044
+ });
2045
+ const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
2046
+ const checkRequest = this.pool.request();
2047
+ checkRequest.input("indexName", indexNameSafe);
2048
+ checkRequest.input("schemaName", schemaName);
2049
+ checkRequest.input("tableName", table);
2050
+ const indexExists = await checkRequest.query(`
2051
+ SELECT 1 as found
2052
+ FROM sys.indexes i
2053
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
2054
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
2055
+ WHERE i.name = @indexName
2056
+ AND s.name = @schemaName
2057
+ AND t.name = @tableName
2058
+ `);
2059
+ if (indexExists.recordset && indexExists.recordset.length > 0) {
2060
+ return;
2061
+ }
2062
+ const uniqueStr = unique ? "UNIQUE " : "";
2063
+ const columnsStr = columns.map((col) => {
2064
+ if (col.includes(" DESC") || col.includes(" ASC")) {
2065
+ const [colName, ...modifiers] = col.split(" ");
2066
+ if (!colName) {
2067
+ throw new Error(`Invalid column specification: ${col}`);
2068
+ }
2069
+ return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
2070
+ }
2071
+ return `[${utils.parseSqlIdentifier(col, "column name")}]`;
2072
+ }).join(", ");
2073
+ const whereStr = where ? ` WHERE ${where}` : "";
2074
+ const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
2075
+ await this.pool.request().query(createIndexSql);
2076
+ } catch (error$1) {
2077
+ throw new error.MastraError(
2078
+ {
2079
+ id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
2080
+ domain: error.ErrorDomain.STORAGE,
2081
+ category: error.ErrorCategory.THIRD_PARTY,
2082
+ details: {
2083
+ indexName: options.name,
2084
+ tableName: options.table
2085
+ }
2086
+ },
2087
+ error$1
2088
+ );
2089
+ }
2090
+ }
2091
+ /**
2092
+ * Drop an existing index
2093
+ */
2094
+ async dropIndex(indexName) {
2095
+ try {
2096
+ const schemaName = this.schemaName || "dbo";
2097
+ const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
2098
+ const checkRequest = this.pool.request();
2099
+ checkRequest.input("indexName", indexNameSafe);
2100
+ checkRequest.input("schemaName", schemaName);
2101
+ const result = await checkRequest.query(`
2102
+ SELECT t.name as table_name
2103
+ FROM sys.indexes i
2104
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
2105
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
2106
+ WHERE i.name = @indexName
2107
+ AND s.name = @schemaName
2108
+ `);
2109
+ if (!result.recordset || result.recordset.length === 0) {
2110
+ return;
2111
+ }
2112
+ if (result.recordset.length > 1) {
2113
+ const tables = result.recordset.map((r) => r.table_name).join(", ");
2114
+ throw new error.MastraError({
2115
+ id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
2116
+ domain: error.ErrorDomain.STORAGE,
2117
+ category: error.ErrorCategory.USER,
2118
+ text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
2119
+ });
2120
+ }
2121
+ const tableName = result.recordset[0].table_name;
2122
+ const fullTableName = getTableName({
2123
+ indexName: tableName,
2124
+ schemaName: getSchemaName(this.schemaName)
2125
+ });
2126
+ const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
2127
+ await this.pool.request().query(dropSql);
2128
+ } catch (error$1) {
2129
+ throw new error.MastraError(
2130
+ {
2131
+ id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
2132
+ domain: error.ErrorDomain.STORAGE,
2133
+ category: error.ErrorCategory.THIRD_PARTY,
2134
+ details: {
2135
+ indexName
2136
+ }
2137
+ },
2138
+ error$1
2139
+ );
2140
+ }
2141
+ }
2142
+ /**
2143
+ * List indexes for a specific table or all tables
2144
+ */
2145
+ async listIndexes(tableName) {
2146
+ try {
2147
+ const schemaName = this.schemaName || "dbo";
2148
+ let query;
2149
+ const request = this.pool.request();
2150
+ request.input("schemaName", schemaName);
2151
+ if (tableName) {
2152
+ query = `
2153
+ SELECT
2154
+ i.name as name,
2155
+ o.name as [table],
2156
+ i.is_unique as is_unique,
2157
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2158
+ FROM sys.indexes i
2159
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2160
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2161
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2162
+ WHERE sch.name = @schemaName
2163
+ AND o.name = @tableName
2164
+ AND i.name IS NOT NULL
2165
+ GROUP BY i.name, o.name, i.is_unique
2166
+ `;
2167
+ request.input("tableName", tableName);
2168
+ } else {
2169
+ query = `
2170
+ SELECT
2171
+ i.name as name,
2172
+ o.name as [table],
2173
+ i.is_unique as is_unique,
2174
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
2175
+ FROM sys.indexes i
2176
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2177
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2178
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2179
+ WHERE sch.name = @schemaName
2180
+ AND i.name IS NOT NULL
2181
+ GROUP BY i.name, o.name, i.is_unique
2182
+ `;
2183
+ }
2184
+ const result = await request.query(query);
2185
+ const indexes = [];
2186
+ for (const row of result.recordset) {
2187
+ const colRequest = this.pool.request();
2188
+ colRequest.input("indexName", row.name);
2189
+ colRequest.input("schemaName", schemaName);
2190
+ const colResult = await colRequest.query(`
2191
+ SELECT c.name as column_name
2192
+ FROM sys.indexes i
2193
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2194
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2195
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2196
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2197
+ WHERE i.name = @indexName
2198
+ AND s.name = @schemaName
2199
+ ORDER BY ic.key_ordinal
2200
+ `);
2201
+ indexes.push({
2202
+ name: row.name,
2203
+ table: row.table,
2204
+ columns: colResult.recordset.map((c) => c.column_name),
2205
+ unique: row.is_unique || false,
2206
+ size: row.size || "0 MB",
2207
+ definition: ""
2208
+ // MSSQL doesn't store definition like PG
2209
+ });
2210
+ }
2211
+ return indexes;
2212
+ } catch (error$1) {
2213
+ throw new error.MastraError(
2214
+ {
2215
+ id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
2216
+ domain: error.ErrorDomain.STORAGE,
2217
+ category: error.ErrorCategory.THIRD_PARTY,
2218
+ details: tableName ? {
2219
+ tableName
2220
+ } : {}
2221
+ },
2222
+ error$1
2223
+ );
2224
+ }
2225
+ }
2226
+ /**
2227
+ * Get detailed statistics for a specific index
2228
+ */
2229
+ async describeIndex(indexName) {
2230
+ try {
2231
+ const schemaName = this.schemaName || "dbo";
2232
+ const request = this.pool.request();
2233
+ request.input("indexName", indexName);
2234
+ request.input("schemaName", schemaName);
2235
+ const query = `
2236
+ SELECT
2237
+ i.name as name,
2238
+ o.name as [table],
2239
+ i.is_unique as is_unique,
2240
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
2241
+ i.type_desc as method,
2242
+ ISNULL(us.user_scans, 0) as scans,
2243
+ ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
2244
+ ISNULL(us.user_lookups, 0) as tuples_fetched
2245
+ FROM sys.indexes i
2246
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2247
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
2248
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
2249
+ LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
2250
+ WHERE i.name = @indexName
2251
+ AND sch.name = @schemaName
2252
+ GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
2253
+ `;
2254
+ const result = await request.query(query);
2255
+ if (!result.recordset || result.recordset.length === 0) {
2256
+ throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
1384
2257
  }
1385
- await transaction.commit();
2258
+ const row = result.recordset[0];
2259
+ const colRequest = this.pool.request();
2260
+ colRequest.input("indexName", indexName);
2261
+ colRequest.input("schemaName", schemaName);
2262
+ const colResult = await colRequest.query(`
2263
+ SELECT c.name as column_name
2264
+ FROM sys.indexes i
2265
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
2266
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
2267
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
2268
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
2269
+ WHERE i.name = @indexName
2270
+ AND s.name = @schemaName
2271
+ ORDER BY ic.key_ordinal
2272
+ `);
2273
+ return {
2274
+ name: row.name,
2275
+ table: row.table,
2276
+ columns: colResult.recordset.map((c) => c.column_name),
2277
+ unique: row.is_unique || false,
2278
+ size: row.size || "0 MB",
2279
+ definition: "",
2280
+ method: row.method?.toLowerCase() || "nonclustered",
2281
+ scans: Number(row.scans) || 0,
2282
+ tuples_read: Number(row.tuples_read) || 0,
2283
+ tuples_fetched: Number(row.tuples_fetched) || 0
2284
+ };
1386
2285
  } catch (error$1) {
1387
- await transaction.rollback();
1388
2286
  throw new error.MastraError(
1389
2287
  {
1390
- id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
2288
+ id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
1391
2289
  domain: error.ErrorDomain.STORAGE,
1392
2290
  category: error.ErrorCategory.THIRD_PARTY,
1393
2291
  details: {
1394
- tableName,
1395
- numberOfRecords: records.length
2292
+ indexName
1396
2293
  }
1397
2294
  },
1398
2295
  error$1
1399
2296
  );
1400
2297
  }
1401
2298
  }
1402
- async dropTable({ tableName }) {
2299
+ /**
2300
+ * Returns definitions for automatic performance indexes
2301
+ * IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
2302
+ * NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
2303
+ */
2304
+ getAutomaticIndexDefinitions() {
2305
+ const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
2306
+ return [
2307
+ // Composite indexes for optimal filtering + sorting performance
2308
+ // NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
2309
+ {
2310
+ name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
2311
+ table: storage.TABLE_THREADS,
2312
+ columns: ["resourceId", "seq_id DESC"]
2313
+ },
2314
+ {
2315
+ name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
2316
+ table: storage.TABLE_MESSAGES,
2317
+ columns: ["thread_id", "seq_id DESC"]
2318
+ },
2319
+ {
2320
+ name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
2321
+ table: storage.TABLE_TRACES,
2322
+ columns: ["name", "seq_id DESC"]
2323
+ },
2324
+ {
2325
+ name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
2326
+ table: storage.TABLE_SCORERS,
2327
+ columns: ["traceId", "spanId", "seq_id DESC"]
2328
+ },
2329
+ // AI Spans indexes for optimal trace querying
2330
+ {
2331
+ name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
2332
+ table: storage.TABLE_AI_SPANS,
2333
+ columns: ["traceId", "startedAt DESC"]
2334
+ },
2335
+ {
2336
+ name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
2337
+ table: storage.TABLE_AI_SPANS,
2338
+ columns: ["parentSpanId", "startedAt DESC"]
2339
+ },
2340
+ {
2341
+ name: `${schemaPrefix}mastra_ai_spans_name_idx`,
2342
+ table: storage.TABLE_AI_SPANS,
2343
+ columns: ["name"]
2344
+ },
2345
+ {
2346
+ name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
2347
+ table: storage.TABLE_AI_SPANS,
2348
+ columns: ["spanType", "startedAt DESC"]
2349
+ }
2350
+ ];
2351
+ }
2352
+ /**
2353
+ * Creates automatic indexes for optimal query performance
2354
+ * Uses getAutomaticIndexDefinitions() to determine which indexes to create
2355
+ */
2356
+ async createAutomaticIndexes() {
1403
2357
  try {
1404
- const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
1405
- await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
2358
+ const indexes = this.getAutomaticIndexDefinitions();
2359
+ for (const indexOptions of indexes) {
2360
+ try {
2361
+ await this.createIndex(indexOptions);
2362
+ } catch (error) {
2363
+ this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
2364
+ }
2365
+ }
1406
2366
  } catch (error$1) {
1407
2367
  throw new error.MastraError(
1408
2368
  {
1409
- id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
2369
+ id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
1410
2370
  domain: error.ErrorDomain.STORAGE,
1411
- category: error.ErrorCategory.THIRD_PARTY,
1412
- details: {
1413
- tableName
1414
- }
2371
+ category: error.ErrorCategory.THIRD_PARTY
1415
2372
  },
1416
2373
  error$1
1417
2374
  );
1418
2375
  }
1419
2376
  }
1420
2377
  };
1421
- function parseJSON(jsonString) {
1422
- try {
1423
- return JSON.parse(jsonString);
1424
- } catch {
1425
- return jsonString;
1426
- }
1427
- }
1428
2378
  function transformScoreRow(row) {
1429
2379
  return {
1430
2380
  ...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),
2381
+ input: storage.safelyParseJSON(row.input),
2382
+ scorer: storage.safelyParseJSON(row.scorer),
2383
+ preprocessStepResult: storage.safelyParseJSON(row.preprocessStepResult),
2384
+ analyzeStepResult: storage.safelyParseJSON(row.analyzeStepResult),
2385
+ metadata: storage.safelyParseJSON(row.metadata),
2386
+ output: storage.safelyParseJSON(row.output),
2387
+ additionalContext: storage.safelyParseJSON(row.additionalContext),
2388
+ requestContext: storage.safelyParseJSON(row.requestContext),
2389
+ entity: storage.safelyParseJSON(row.entity),
1440
2390
  createdAt: row.createdAt,
1441
2391
  updatedAt: row.updatedAt
1442
2392
  };
@@ -1479,6 +2429,19 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1479
2429
  }
1480
2430
  }
1481
2431
  async saveScore(score) {
2432
+ let validatedScore;
2433
+ try {
2434
+ validatedScore = scores.saveScorePayloadSchema.parse(score);
2435
+ } catch (error$1) {
2436
+ throw new error.MastraError(
2437
+ {
2438
+ id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_VALIDATION_FAILED",
2439
+ domain: error.ErrorDomain.STORAGE,
2440
+ category: error.ErrorCategory.THIRD_PARTY
2441
+ },
2442
+ error$1
2443
+ );
2444
+ }
1482
2445
  try {
1483
2446
  const scoreId = crypto.randomUUID();
1484
2447
  const {
@@ -1489,24 +2452,24 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1489
2452
  input,
1490
2453
  output,
1491
2454
  additionalContext,
1492
- runtimeContext,
2455
+ requestContext,
1493
2456
  entity,
1494
2457
  ...rest
1495
- } = score;
2458
+ } = validatedScore;
1496
2459
  await this.operations.insert({
1497
2460
  tableName: storage.TABLE_SCORERS,
1498
2461
  record: {
1499
2462
  id: scoreId,
1500
2463
  ...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,
2464
+ input: input || "",
2465
+ output: output || "",
2466
+ preprocessStepResult: preprocessStepResult || null,
2467
+ analyzeStepResult: analyzeStepResult || null,
2468
+ metadata: metadata || null,
2469
+ additionalContext: additionalContext || null,
2470
+ requestContext: requestContext || null,
2471
+ entity: entity || null,
2472
+ scorer: scorer || null,
1510
2473
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1511
2474
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1512
2475
  }
@@ -1526,14 +2489,37 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1526
2489
  }
1527
2490
  async getScoresByScorerId({
1528
2491
  scorerId,
1529
- pagination
2492
+ pagination,
2493
+ entityId,
2494
+ entityType,
2495
+ source
1530
2496
  }) {
1531
2497
  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
- );
2498
+ const conditions = ["[scorerId] = @p1"];
2499
+ const params = { p1: scorerId };
2500
+ let paramIndex = 2;
2501
+ if (entityId) {
2502
+ conditions.push(`[entityId] = @p${paramIndex}`);
2503
+ params[`p${paramIndex}`] = entityId;
2504
+ paramIndex++;
2505
+ }
2506
+ if (entityType) {
2507
+ conditions.push(`[entityType] = @p${paramIndex}`);
2508
+ params[`p${paramIndex}`] = entityType;
2509
+ paramIndex++;
2510
+ }
2511
+ if (source) {
2512
+ conditions.push(`[source] = @p${paramIndex}`);
2513
+ params[`p${paramIndex}`] = source;
2514
+ paramIndex++;
2515
+ }
2516
+ const whereClause = conditions.join(" AND ");
2517
+ const tableName = getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
2518
+ const countRequest = this.pool.request();
2519
+ Object.entries(params).forEach(([key, value]) => {
2520
+ countRequest.input(key, value);
2521
+ });
2522
+ const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
1537
2523
  const total = totalResult.recordset[0]?.count || 0;
1538
2524
  if (total === 0) {
1539
2525
  return {
@@ -1547,12 +2533,13 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1547
2533
  };
1548
2534
  }
1549
2535
  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
- );
2536
+ Object.entries(params).forEach(([key, value]) => {
2537
+ dataRequest.input(key, value);
2538
+ });
2539
+ dataRequest.input("perPage", pagination.perPage);
2540
+ dataRequest.input("offset", pagination.page * pagination.perPage);
2541
+ const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
2542
+ const result = await dataRequest.query(dataQuery);
1556
2543
  return {
1557
2544
  pagination: {
1558
2545
  total: Number(total),
@@ -1677,8 +2664,62 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1677
2664
  );
1678
2665
  }
1679
2666
  }
2667
+ async getScoresBySpan({
2668
+ traceId,
2669
+ spanId,
2670
+ pagination
2671
+ }) {
2672
+ try {
2673
+ const request = this.pool.request();
2674
+ request.input("p1", traceId);
2675
+ request.input("p2", spanId);
2676
+ const totalResult = await request.query(
2677
+ `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
2678
+ );
2679
+ const total = totalResult.recordset[0]?.count || 0;
2680
+ if (total === 0) {
2681
+ return {
2682
+ pagination: {
2683
+ total: 0,
2684
+ page: pagination.page,
2685
+ perPage: pagination.perPage,
2686
+ hasMore: false
2687
+ },
2688
+ scores: []
2689
+ };
2690
+ }
2691
+ const limit = pagination.perPage + 1;
2692
+ const dataRequest = this.pool.request();
2693
+ dataRequest.input("p1", traceId);
2694
+ dataRequest.input("p2", spanId);
2695
+ dataRequest.input("p3", limit);
2696
+ dataRequest.input("p4", pagination.page * pagination.perPage);
2697
+ const result = await dataRequest.query(
2698
+ `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`
2699
+ );
2700
+ return {
2701
+ pagination: {
2702
+ total: Number(total),
2703
+ page: pagination.page,
2704
+ perPage: pagination.perPage,
2705
+ hasMore: result.recordset.length > pagination.perPage
2706
+ },
2707
+ scores: result.recordset.slice(0, pagination.perPage).map((row) => transformScoreRow(row))
2708
+ };
2709
+ } catch (error$1) {
2710
+ throw new error.MastraError(
2711
+ {
2712
+ id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SPAN_FAILED",
2713
+ domain: error.ErrorDomain.STORAGE,
2714
+ category: error.ErrorCategory.THIRD_PARTY,
2715
+ details: { traceId, spanId }
2716
+ },
2717
+ error$1
2718
+ );
2719
+ }
2720
+ }
1680
2721
  };
1681
- var TracesMSSQL = class extends storage.TracesStorage {
2722
+ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1682
2723
  pool;
1683
2724
  operations;
1684
2725
  schema;
@@ -1692,210 +2733,168 @@ var TracesMSSQL = class extends storage.TracesStorage {
1692
2733
  this.operations = operations;
1693
2734
  this.schema = schema;
1694
2735
  }
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
- };
1702
- }
1703
- const result = await this.getTracesPaginated(args);
1704
- return result.traces;
1705
- }
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();
2736
+ parseWorkflowRun(row) {
2737
+ let parsedSnapshot = row.snapshot;
2738
+ if (typeof parsedSnapshot === "string") {
2739
+ try {
2740
+ parsedSnapshot = JSON.parse(row.snapshot);
2741
+ } catch (e) {
2742
+ this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
2743
+ }
1750
2744
  }
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;
2745
+ return {
2746
+ workflowName: row.workflow_name,
2747
+ runId: row.run_id,
2748
+ snapshot: parsedSnapshot,
2749
+ createdAt: row.createdAt,
2750
+ updatedAt: row.updatedAt,
2751
+ resourceId: row.resourceId
2752
+ };
2753
+ }
2754
+ async updateWorkflowResults({
2755
+ workflowName,
2756
+ runId,
2757
+ stepId,
2758
+ result,
2759
+ requestContext
2760
+ }) {
2761
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2762
+ const transaction = this.pool.transaction();
1754
2763
  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);
2764
+ await transaction.begin();
2765
+ const selectRequest = new sql2__default.default.Request(transaction);
2766
+ selectRequest.input("workflow_name", workflowName);
2767
+ selectRequest.input("run_id", runId);
2768
+ const existingSnapshotResult = await selectRequest.query(
2769
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
2770
+ );
2771
+ let snapshot;
2772
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
2773
+ snapshot = {
2774
+ context: {},
2775
+ activePaths: [],
2776
+ timestamp: Date.now(),
2777
+ suspendedPaths: {},
2778
+ resumeLabels: {},
2779
+ serializedStepGraph: [],
2780
+ value: {},
2781
+ waitingPaths: {},
2782
+ status: "pending",
2783
+ runId,
2784
+ requestContext: {}
2785
+ };
2786
+ } else {
2787
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
2788
+ snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2789
+ }
2790
+ snapshot.context[stepId] = result;
2791
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
2792
+ const upsertReq = new sql2__default.default.Request(transaction);
2793
+ upsertReq.input("workflow_name", workflowName);
2794
+ upsertReq.input("run_id", runId);
2795
+ upsertReq.input("snapshot", JSON.stringify(snapshot));
2796
+ upsertReq.input("createdAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
2797
+ upsertReq.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
2798
+ await upsertReq.query(
2799
+ `MERGE ${table} AS target
2800
+ USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
2801
+ ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
2802
+ WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
2803
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
2804
+ VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
2805
+ );
2806
+ await transaction.commit();
2807
+ return snapshot.context;
1765
2808
  } catch (error$1) {
2809
+ try {
2810
+ await transaction.rollback();
2811
+ } catch {
2812
+ }
1766
2813
  throw new error.MastraError(
1767
2814
  {
1768
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT",
2815
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
1769
2816
  domain: error.ErrorDomain.STORAGE,
1770
2817
  category: error.ErrorCategory.THIRD_PARTY,
1771
2818
  details: {
1772
- name: args.name ?? "",
1773
- scope: args.scope ?? ""
2819
+ workflowName,
2820
+ runId,
2821
+ stepId
1774
2822
  }
1775
2823
  },
1776
2824
  error$1
1777
2825
  );
1778
2826
  }
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);
2827
+ }
2828
+ async updateWorkflowState({
2829
+ workflowName,
2830
+ runId,
2831
+ opts
2832
+ }) {
2833
+ const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
2834
+ const transaction = this.pool.transaction();
1799
2835
  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
- };
2836
+ await transaction.begin();
2837
+ const selectRequest = new sql2__default.default.Request(transaction);
2838
+ selectRequest.input("workflow_name", workflowName);
2839
+ selectRequest.input("run_id", runId);
2840
+ const existingSnapshotResult = await selectRequest.query(
2841
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
2842
+ );
2843
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
2844
+ await transaction.rollback();
2845
+ return void 0;
2846
+ }
2847
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
2848
+ const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
2849
+ if (!snapshot || !snapshot?.context) {
2850
+ await transaction.rollback();
2851
+ throw new error.MastraError(
2852
+ {
2853
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
2854
+ domain: error.ErrorDomain.STORAGE,
2855
+ category: error.ErrorCategory.SYSTEM,
2856
+ details: {
2857
+ workflowName,
2858
+ runId
2859
+ }
2860
+ },
2861
+ new Error(`Snapshot not found for runId ${runId}`)
2862
+ );
2863
+ }
2864
+ const updatedSnapshot = { ...snapshot, ...opts };
2865
+ const updateRequest = new sql2__default.default.Request(transaction);
2866
+ updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
2867
+ updateRequest.input("workflow_name", workflowName);
2868
+ updateRequest.input("run_id", runId);
2869
+ updateRequest.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
2870
+ await updateRequest.query(
2871
+ `UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
2872
+ );
2873
+ await transaction.commit();
2874
+ return updatedSnapshot;
1825
2875
  } catch (error$1) {
2876
+ try {
2877
+ await transaction.rollback();
2878
+ } catch {
2879
+ }
1826
2880
  throw new error.MastraError(
1827
2881
  {
1828
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES",
2882
+ id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
1829
2883
  domain: error.ErrorDomain.STORAGE,
1830
2884
  category: error.ErrorCategory.THIRD_PARTY,
1831
2885
  details: {
1832
- name: args.name ?? "",
1833
- scope: args.scope ?? ""
2886
+ workflowName,
2887
+ runId
1834
2888
  }
1835
2889
  },
1836
2890
  error$1
1837
2891
  );
1838
2892
  }
1839
2893
  }
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
2894
  async persistWorkflowSnapshot({
1897
2895
  workflowName,
1898
2896
  runId,
2897
+ resourceId,
1899
2898
  snapshot
1900
2899
  }) {
1901
2900
  const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
@@ -1904,6 +2903,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1904
2903
  const request = this.pool.request();
1905
2904
  request.input("workflow_name", workflowName);
1906
2905
  request.input("run_id", runId);
2906
+ request.input("resourceId", resourceId);
1907
2907
  request.input("snapshot", JSON.stringify(snapshot));
1908
2908
  request.input("createdAt", sql2__default.default.DateTime2, new Date(now));
1909
2909
  request.input("updatedAt", sql2__default.default.DateTime2, new Date(now));
@@ -1911,10 +2911,11 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1911
2911
  USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
1912
2912
  ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
1913
2913
  WHEN MATCHED THEN UPDATE SET
2914
+ resourceId = @resourceId,
1914
2915
  snapshot = @snapshot,
1915
2916
  [updatedAt] = @updatedAt
1916
- WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
1917
- VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
2917
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
2918
+ VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
1918
2919
  await request.query(mergeSql);
1919
2920
  } catch (error$1) {
1920
2921
  throw new error.MastraError(
@@ -1986,7 +2987,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1986
2987
  if (!result.recordset || result.recordset.length === 0) {
1987
2988
  return null;
1988
2989
  }
1989
- return parseWorkflowRun(result.recordset[0]);
2990
+ return this.parseWorkflowRun(result.recordset[0]);
1990
2991
  } catch (error$1) {
1991
2992
  throw new error.MastraError(
1992
2993
  {
@@ -2002,7 +3003,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2002
3003
  );
2003
3004
  }
2004
3005
  }
2005
- async getWorkflowRuns({
3006
+ async listWorkflowRuns({
2006
3007
  workflowName,
2007
3008
  fromDate,
2008
3009
  toDate,
@@ -2023,7 +3024,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2023
3024
  conditions.push(`[resourceId] = @resourceId`);
2024
3025
  paramMap["resourceId"] = resourceId;
2025
3026
  } else {
2026
- console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
3027
+ this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
2027
3028
  }
2028
3029
  }
2029
3030
  if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
@@ -2057,7 +3058,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2057
3058
  request.input("offset", offset);
2058
3059
  }
2059
3060
  const result = await request.query(query);
2060
- const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
3061
+ const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
2061
3062
  return { runs, total: total || runs.length };
2062
3063
  } catch (error$1) {
2063
3064
  throw new error.MastraError(
@@ -2105,19 +3106,17 @@ var MSSQLStore = class extends storage.MastraStorage {
2105
3106
  port: config.port,
2106
3107
  options: config.options || { encrypt: true, trustServerCertificate: true }
2107
3108
  });
2108
- const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
2109
3109
  const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
2110
3110
  const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
2111
- const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
2112
3111
  const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
2113
3112
  const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
3113
+ const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
2114
3114
  this.stores = {
2115
3115
  operations,
2116
3116
  scores,
2117
- traces,
2118
3117
  workflows,
2119
- legacyEvals,
2120
- memory
3118
+ memory,
3119
+ observability
2121
3120
  };
2122
3121
  } catch (e) {
2123
3122
  throw new error.MastraError(
@@ -2137,6 +3136,11 @@ var MSSQLStore = class extends storage.MastraStorage {
2137
3136
  try {
2138
3137
  await this.isConnected;
2139
3138
  await super.init();
3139
+ try {
3140
+ await this.stores.operations.createAutomaticIndexes();
3141
+ } catch (indexError) {
3142
+ this.logger?.warn?.("Failed to create indexes:", indexError);
3143
+ }
2140
3144
  } catch (error$1) {
2141
3145
  this.isConnected = null;
2142
3146
  throw new error.MastraError(
@@ -2163,28 +3167,12 @@ var MSSQLStore = class extends storage.MastraStorage {
2163
3167
  resourceWorkingMemory: true,
2164
3168
  hasColumn: true,
2165
3169
  createTable: true,
2166
- deleteMessages: true
3170
+ deleteMessages: true,
3171
+ getScoresBySpan: true,
3172
+ aiTracing: true,
3173
+ indexManagement: true
2167
3174
  };
2168
3175
  }
2169
- /** @deprecated use getEvals instead */
2170
- async getEvalsByAgentName(agentName, type) {
2171
- return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2172
- }
2173
- async getEvals(options = {}) {
2174
- return this.stores.legacyEvals.getEvals(options);
2175
- }
2176
- /**
2177
- * @deprecated use getTracesPaginated instead
2178
- */
2179
- async getTraces(args) {
2180
- return this.stores.traces.getTraces(args);
2181
- }
2182
- async getTracesPaginated(args) {
2183
- return this.stores.traces.getTracesPaginated(args);
2184
- }
2185
- async batchTraceInsert({ records }) {
2186
- return this.stores.traces.batchTraceInsert({ records });
2187
- }
2188
3176
  async createTable({
2189
3177
  tableName,
2190
3178
  schema
@@ -2244,12 +3232,6 @@ var MSSQLStore = class extends storage.MastraStorage {
2244
3232
  async getMessages(args) {
2245
3233
  return this.stores.memory.getMessages(args);
2246
3234
  }
2247
- async getMessagesById({
2248
- messageIds,
2249
- format
2250
- }) {
2251
- return this.stores.memory.getMessagesById({ messageIds, format });
2252
- }
2253
3235
  async getMessagesPaginated(args) {
2254
3236
  return this.stores.memory.getMessagesPaginated(args);
2255
3237
  }
@@ -2285,9 +3267,9 @@ var MSSQLStore = class extends storage.MastraStorage {
2285
3267
  runId,
2286
3268
  stepId,
2287
3269
  result,
2288
- runtimeContext
3270
+ requestContext
2289
3271
  }) {
2290
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
3272
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2291
3273
  }
2292
3274
  async updateWorkflowState({
2293
3275
  workflowName,
@@ -2299,9 +3281,10 @@ var MSSQLStore = class extends storage.MastraStorage {
2299
3281
  async persistWorkflowSnapshot({
2300
3282
  workflowName,
2301
3283
  runId,
3284
+ resourceId,
2302
3285
  snapshot
2303
3286
  }) {
2304
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
3287
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2305
3288
  }
2306
3289
  async loadWorkflowSnapshot({
2307
3290
  workflowName,
@@ -2309,7 +3292,7 @@ var MSSQLStore = class extends storage.MastraStorage {
2309
3292
  }) {
2310
3293
  return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2311
3294
  }
2312
- async getWorkflowRuns({
3295
+ async listWorkflowRuns({
2313
3296
  workflowName,
2314
3297
  fromDate,
2315
3298
  toDate,
@@ -2317,7 +3300,7 @@ var MSSQLStore = class extends storage.MastraStorage {
2317
3300
  offset,
2318
3301
  resourceId
2319
3302
  } = {}) {
2320
- return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
3303
+ return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
2321
3304
  }
2322
3305
  async getWorkflowRunById({
2323
3306
  runId,
@@ -2328,6 +3311,60 @@ var MSSQLStore = class extends storage.MastraStorage {
2328
3311
  async close() {
2329
3312
  await this.pool.close();
2330
3313
  }
3314
+ /**
3315
+ * Index Management
3316
+ */
3317
+ async createIndex(options) {
3318
+ return this.stores.operations.createIndex(options);
3319
+ }
3320
+ async listIndexes(tableName) {
3321
+ return this.stores.operations.listIndexes(tableName);
3322
+ }
3323
+ async describeIndex(indexName) {
3324
+ return this.stores.operations.describeIndex(indexName);
3325
+ }
3326
+ async dropIndex(indexName) {
3327
+ return this.stores.operations.dropIndex(indexName);
3328
+ }
3329
+ /**
3330
+ * AI Tracing / Observability
3331
+ */
3332
+ getObservabilityStore() {
3333
+ if (!this.stores.observability) {
3334
+ throw new error.MastraError({
3335
+ id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
3336
+ domain: error.ErrorDomain.STORAGE,
3337
+ category: error.ErrorCategory.SYSTEM,
3338
+ text: "Observability storage is not initialized"
3339
+ });
3340
+ }
3341
+ return this.stores.observability;
3342
+ }
3343
+ async createAISpan(span) {
3344
+ return this.getObservabilityStore().createAISpan(span);
3345
+ }
3346
+ async updateAISpan({
3347
+ spanId,
3348
+ traceId,
3349
+ updates
3350
+ }) {
3351
+ return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
3352
+ }
3353
+ async getAITrace(traceId) {
3354
+ return this.getObservabilityStore().getAITrace(traceId);
3355
+ }
3356
+ async getAITracesPaginated(args) {
3357
+ return this.getObservabilityStore().getAITracesPaginated(args);
3358
+ }
3359
+ async batchCreateAISpans(args) {
3360
+ return this.getObservabilityStore().batchCreateAISpans(args);
3361
+ }
3362
+ async batchUpdateAISpans(args) {
3363
+ return this.getObservabilityStore().batchUpdateAISpans(args);
3364
+ }
3365
+ async batchDeleteAITraces(args) {
3366
+ return this.getObservabilityStore().batchDeleteAITraces(args);
3367
+ }
2331
3368
  /**
2332
3369
  * Scorers
2333
3370
  */
@@ -2336,9 +3373,18 @@ var MSSQLStore = class extends storage.MastraStorage {
2336
3373
  }
2337
3374
  async getScoresByScorerId({
2338
3375
  scorerId: _scorerId,
2339
- pagination: _pagination
3376
+ pagination: _pagination,
3377
+ entityId: _entityId,
3378
+ entityType: _entityType,
3379
+ source: _source
2340
3380
  }) {
2341
- return this.stores.scores.getScoresByScorerId({ scorerId: _scorerId, pagination: _pagination });
3381
+ return this.stores.scores.getScoresByScorerId({
3382
+ scorerId: _scorerId,
3383
+ pagination: _pagination,
3384
+ entityId: _entityId,
3385
+ entityType: _entityType,
3386
+ source: _source
3387
+ });
2342
3388
  }
2343
3389
  async saveScore(_score) {
2344
3390
  return this.stores.scores.saveScore(_score);
@@ -2360,6 +3406,13 @@ var MSSQLStore = class extends storage.MastraStorage {
2360
3406
  pagination: _pagination
2361
3407
  });
2362
3408
  }
3409
+ async getScoresBySpan({
3410
+ traceId,
3411
+ spanId,
3412
+ pagination: _pagination
3413
+ }) {
3414
+ return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination: _pagination });
3415
+ }
2363
3416
  };
2364
3417
 
2365
3418
  exports.MSSQLStore = MSSQLStore;