@mastra/mssql 0.0.0-iterate-traces-ui-again-20250912091900 → 0.0.0-jail-fs-20260105160110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +1419 -3
  2. package/README.md +324 -37
  3. package/dist/docs/README.md +31 -0
  4. package/dist/docs/SKILL.md +32 -0
  5. package/dist/docs/SOURCE_MAP.json +6 -0
  6. package/dist/docs/storage/01-reference.md +141 -0
  7. package/dist/index.cjs +2500 -1146
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2497 -1147
  12. package/dist/index.js.map +1 -1
  13. package/dist/storage/db/index.d.ts +172 -0
  14. package/dist/storage/db/index.d.ts.map +1 -0
  15. package/dist/storage/db/utils.d.ts +21 -0
  16. package/dist/storage/db/utils.d.ts.map +1 -0
  17. package/dist/storage/domains/memory/index.d.ts +38 -52
  18. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  19. package/dist/storage/domains/observability/index.d.ts +46 -0
  20. package/dist/storage/domains/observability/index.d.ts.map +1 -0
  21. package/dist/storage/domains/scores/index.d.ts +38 -25
  22. package/dist/storage/domains/scores/index.d.ts.map +1 -1
  23. package/dist/storage/domains/utils.d.ts +19 -0
  24. package/dist/storage/domains/utils.d.ts.map +1 -1
  25. package/dist/storage/domains/workflows/index.d.ts +39 -28
  26. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  27. package/dist/storage/index.d.ts +115 -213
  28. package/dist/storage/index.d.ts.map +1 -1
  29. package/package.json +15 -10
  30. package/dist/storage/domains/legacy-evals/index.d.ts +0 -20
  31. package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
  32. package/dist/storage/domains/operations/index.d.ts +0 -51
  33. package/dist/storage/domains/operations/index.d.ts.map +0 -1
  34. package/dist/storage/domains/traces/index.d.ts +0 -37
  35. package/dist/storage/domains/traces/index.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  var error = require('@mastra/core/error');
4
4
  var storage = require('@mastra/core/storage');
5
- var sql2 = require('mssql');
6
- var utils = require('@mastra/core/utils');
5
+ var sql = require('mssql');
7
6
  var agent = require('@mastra/core/agent');
7
+ var base = require('@mastra/core/base');
8
+ var utils = require('@mastra/core/utils');
9
+ var crypto = require('crypto');
10
+ var evals = require('@mastra/core/evals');
8
11
 
9
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
13
 
11
- var sql2__default = /*#__PURE__*/_interopDefault(sql2);
14
+ var sql__default = /*#__PURE__*/_interopDefault(sql);
12
15
 
13
16
  // src/storage/index.ts
14
17
  function getSchemaName(schema) {
@@ -21,157 +24,1119 @@ function getTableName({ indexName, schemaName }) {
21
24
  return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
22
25
  }
23
26
 
24
- // src/storage/domains/legacy-evals/index.ts
25
- function transformEvalRow(row) {
26
- let testInfoValue = null, resultValue = null;
27
- if (row.test_info) {
27
+ // src/storage/db/index.ts
28
+ function resolveMssqlConfig(config) {
29
+ if ("pool" in config && !("server" in config)) {
30
+ return {
31
+ pool: config.pool,
32
+ schemaName: config.schemaName,
33
+ skipDefaultIndexes: config.skipDefaultIndexes,
34
+ indexes: config.indexes,
35
+ needsConnect: false
36
+ };
37
+ }
38
+ const restConfig = config;
39
+ const pool = new sql__default.default.ConnectionPool({
40
+ server: restConfig.server,
41
+ database: restConfig.database,
42
+ user: restConfig.user,
43
+ password: restConfig.password,
44
+ port: restConfig.port,
45
+ options: restConfig.options || { encrypt: true, trustServerCertificate: true }
46
+ });
47
+ return {
48
+ pool,
49
+ schemaName: restConfig.schemaName,
50
+ skipDefaultIndexes: restConfig.skipDefaultIndexes,
51
+ indexes: restConfig.indexes,
52
+ needsConnect: true
53
+ };
54
+ }
55
+ var MssqlDB = class extends base.MastraBase {
56
+ pool;
57
+ schemaName;
58
+ skipDefaultIndexes;
59
+ setupSchemaPromise = null;
60
+ schemaSetupComplete = void 0;
61
+ /**
62
+ * Columns that participate in composite indexes need smaller sizes (NVARCHAR(100)).
63
+ * MSSQL has a 900-byte index key limit, so composite indexes with NVARCHAR(400) columns fail.
64
+ * These are typically ID/type fields that don't need 400 chars.
65
+ */
66
+ COMPOSITE_INDEX_COLUMNS = [
67
+ "traceId",
68
+ // Used in: PRIMARY KEY (traceId, spanId), index (traceId, spanId, seq_id)
69
+ "spanId",
70
+ // Used in: PRIMARY KEY (traceId, spanId), index (traceId, spanId, seq_id)
71
+ "parentSpanId",
72
+ // Used in: index (parentSpanId, startedAt)
73
+ "entityType",
74
+ // Used in: (entityType, entityId), (entityType, entityName)
75
+ "entityId",
76
+ // Used in: (entityType, entityId)
77
+ "entityName",
78
+ // Used in: (entityType, entityName)
79
+ "organizationId",
80
+ // Used in: (organizationId, userId)
81
+ "userId"
82
+ // Used in: (organizationId, userId)
83
+ ];
84
+ /**
85
+ * Columns that store large amounts of data and should use NVARCHAR(MAX).
86
+ * Avoid listing columns that participate in indexes (resourceId, thread_id, agent_name, name, etc.)
87
+ */
88
+ LARGE_DATA_COLUMNS = [
89
+ "workingMemory",
90
+ "snapshot",
91
+ "metadata",
92
+ "content",
93
+ // messages.content - can be very long conversation content
94
+ "input",
95
+ // evals.input - test input data
96
+ "output",
97
+ // evals.output - test output data
98
+ "instructions",
99
+ // evals.instructions - evaluation instructions
100
+ "other"
101
+ // traces.other - additional trace data
102
+ ];
103
+ getSqlType(type, isPrimaryKey = false, useLargeStorage = false, useSmallStorage = false) {
104
+ switch (type) {
105
+ case "text":
106
+ if (useLargeStorage) {
107
+ return "NVARCHAR(MAX)";
108
+ }
109
+ if (useSmallStorage) {
110
+ return "NVARCHAR(100)";
111
+ }
112
+ return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
113
+ case "timestamp":
114
+ return "DATETIME2(7)";
115
+ case "uuid":
116
+ return "UNIQUEIDENTIFIER";
117
+ case "jsonb":
118
+ return "NVARCHAR(MAX)";
119
+ case "integer":
120
+ return "INT";
121
+ case "bigint":
122
+ return "BIGINT";
123
+ case "float":
124
+ return "FLOAT";
125
+ case "boolean":
126
+ return "BIT";
127
+ default:
128
+ throw new error.MastraError({
129
+ id: storage.createStorageErrorId("MSSQL", "TYPE", "NOT_SUPPORTED"),
130
+ domain: error.ErrorDomain.STORAGE,
131
+ category: error.ErrorCategory.THIRD_PARTY
132
+ });
133
+ }
134
+ }
135
+ constructor({
136
+ pool,
137
+ schemaName,
138
+ skipDefaultIndexes
139
+ }) {
140
+ super({ component: "STORAGE", name: "MssqlDB" });
141
+ this.pool = pool;
142
+ this.schemaName = schemaName;
143
+ this.skipDefaultIndexes = skipDefaultIndexes;
144
+ }
145
+ async hasColumn(table, column) {
146
+ const schema = this.schemaName || "dbo";
147
+ const request = this.pool.request();
148
+ request.input("schema", schema);
149
+ request.input("table", table);
150
+ request.input("column", column);
151
+ request.input("columnLower", column.toLowerCase());
152
+ const result = await request.query(
153
+ `SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
154
+ );
155
+ return result.recordset.length > 0;
156
+ }
157
+ async setupSchema() {
158
+ if (!this.schemaName || this.schemaSetupComplete) {
159
+ return;
160
+ }
161
+ if (!this.setupSchemaPromise) {
162
+ this.setupSchemaPromise = (async () => {
163
+ try {
164
+ const checkRequest = this.pool.request();
165
+ checkRequest.input("schemaName", this.schemaName);
166
+ const checkResult = await checkRequest.query(`
167
+ SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
168
+ `);
169
+ const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
170
+ if (!schemaExists) {
171
+ try {
172
+ await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
173
+ this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
174
+ } catch (error) {
175
+ this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
176
+ throw new Error(
177
+ `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.`
178
+ );
179
+ }
180
+ }
181
+ this.schemaSetupComplete = true;
182
+ this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
183
+ } catch (error) {
184
+ this.schemaSetupComplete = void 0;
185
+ this.setupSchemaPromise = null;
186
+ throw error;
187
+ } finally {
188
+ this.setupSchemaPromise = null;
189
+ }
190
+ })();
191
+ }
192
+ await this.setupSchemaPromise;
193
+ }
194
+ async insert({
195
+ tableName,
196
+ record,
197
+ transaction
198
+ }) {
28
199
  try {
29
- testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
30
- } catch {
200
+ const columns = Object.keys(record);
201
+ const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
202
+ const paramNames = columns.map((_, i) => `@param${i}`);
203
+ const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
204
+ const request = transaction ? transaction.request() : this.pool.request();
205
+ columns.forEach((col, i) => {
206
+ const value = record[col];
207
+ const preparedValue = this.prepareValue(value, col, tableName);
208
+ if (preparedValue instanceof Date) {
209
+ request.input(`param${i}`, sql__default.default.DateTime2, preparedValue);
210
+ } else if (preparedValue === null || preparedValue === void 0) {
211
+ request.input(`param${i}`, this.getMssqlType(tableName, col), null);
212
+ } else {
213
+ request.input(`param${i}`, preparedValue);
214
+ }
215
+ });
216
+ await request.query(insertSql);
217
+ } catch (error$1) {
218
+ throw new error.MastraError(
219
+ {
220
+ id: storage.createStorageErrorId("MSSQL", "INSERT", "FAILED"),
221
+ domain: error.ErrorDomain.STORAGE,
222
+ category: error.ErrorCategory.THIRD_PARTY,
223
+ details: {
224
+ tableName
225
+ }
226
+ },
227
+ error$1
228
+ );
229
+ }
230
+ }
231
+ async clearTable({ tableName }) {
232
+ const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
233
+ try {
234
+ try {
235
+ await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
236
+ } catch (truncateError) {
237
+ if (truncateError?.number === 4712) {
238
+ await this.pool.request().query(`DELETE FROM ${fullTableName}`);
239
+ } else {
240
+ throw truncateError;
241
+ }
242
+ }
243
+ } catch (error$1) {
244
+ throw new error.MastraError(
245
+ {
246
+ id: storage.createStorageErrorId("MSSQL", "CLEAR_TABLE", "FAILED"),
247
+ domain: error.ErrorDomain.STORAGE,
248
+ category: error.ErrorCategory.THIRD_PARTY,
249
+ details: {
250
+ tableName
251
+ }
252
+ },
253
+ error$1
254
+ );
255
+ }
256
+ }
257
+ getDefaultValue(type) {
258
+ switch (type) {
259
+ case "timestamp":
260
+ return "DEFAULT SYSUTCDATETIME()";
261
+ case "jsonb":
262
+ return "DEFAULT N'{}'";
263
+ case "boolean":
264
+ return "DEFAULT 0";
265
+ default:
266
+ return storage.getDefaultValue(type);
267
+ }
268
+ }
269
+ async createTable({
270
+ tableName,
271
+ schema
272
+ }) {
273
+ try {
274
+ const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
275
+ const columns = Object.entries(schema).map(([name, def]) => {
276
+ const parsedName = utils.parseSqlIdentifier(name, "column name");
277
+ const constraints = [];
278
+ if (def.primaryKey) constraints.push("PRIMARY KEY");
279
+ if (!def.nullable) constraints.push("NOT NULL");
280
+ const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
281
+ const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(name);
282
+ const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(name);
283
+ return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage, useSmallStorage)} ${constraints.join(" ")}`.trim();
284
+ }).join(",\n");
285
+ if (this.schemaName) {
286
+ await this.setupSchema();
287
+ }
288
+ const checkTableRequest = this.pool.request();
289
+ checkTableRequest.input(
290
+ "tableName",
291
+ getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) }).replace(/[[\]]/g, "").split(".").pop()
292
+ );
293
+ const checkTableSql = `SELECT 1 AS found FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName`;
294
+ checkTableRequest.input("schema", this.schemaName || "dbo");
295
+ const checkTableResult = await checkTableRequest.query(checkTableSql);
296
+ const tableExists = Array.isArray(checkTableResult.recordset) && checkTableResult.recordset.length > 0;
297
+ if (!tableExists) {
298
+ const createSql = `CREATE TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (
299
+ ${columns}
300
+ )`;
301
+ await this.pool.request().query(createSql);
302
+ }
303
+ const columnCheckSql = `
304
+ SELECT 1 AS found
305
+ FROM INFORMATION_SCHEMA.COLUMNS
306
+ WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName AND COLUMN_NAME = 'seq_id'
307
+ `;
308
+ const checkColumnRequest = this.pool.request();
309
+ checkColumnRequest.input("schema", this.schemaName || "dbo");
310
+ checkColumnRequest.input(
311
+ "tableName",
312
+ getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) }).replace(/[[\]]/g, "").split(".").pop()
313
+ );
314
+ const columnResult = await checkColumnRequest.query(columnCheckSql);
315
+ const columnExists = Array.isArray(columnResult.recordset) && columnResult.recordset.length > 0;
316
+ if (!columnExists) {
317
+ const alterSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD seq_id BIGINT IDENTITY(1,1)`;
318
+ await this.pool.request().query(alterSql);
319
+ }
320
+ const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
321
+ if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
322
+ const constraintName = `${schemaPrefix}mastra_workflow_snapshot_workflow_name_run_id_key`;
323
+ const checkConstraintSql = `SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`;
324
+ const checkConstraintRequest = this.pool.request();
325
+ checkConstraintRequest.input("constraintName", constraintName);
326
+ const constraintResult = await checkConstraintRequest.query(checkConstraintSql);
327
+ const constraintExists = Array.isArray(constraintResult.recordset) && constraintResult.recordset.length > 0;
328
+ if (!constraintExists) {
329
+ const addConstraintSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT [${constraintName}] UNIQUE ([workflow_name], [run_id])`;
330
+ await this.pool.request().query(addConstraintSql);
331
+ }
332
+ }
333
+ if (tableName === storage.TABLE_SPANS) {
334
+ await this.migrateSpansTable();
335
+ const pkConstraintName = `${schemaPrefix}mastra_ai_spans_traceid_spanid_pk`;
336
+ const checkPkRequest = this.pool.request();
337
+ checkPkRequest.input("constraintName", pkConstraintName);
338
+ const pkResult = await checkPkRequest.query(
339
+ `SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`
340
+ );
341
+ const pkExists = Array.isArray(pkResult.recordset) && pkResult.recordset.length > 0;
342
+ if (!pkExists) {
343
+ try {
344
+ const addPkSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT [${pkConstraintName}] PRIMARY KEY ([traceId], [spanId])`;
345
+ await this.pool.request().query(addPkSql);
346
+ } catch (pkError) {
347
+ this.logger?.warn?.(`Failed to add composite primary key to spans table:`, pkError);
348
+ }
349
+ }
350
+ }
351
+ } catch (error$1) {
352
+ throw new error.MastraError(
353
+ {
354
+ id: storage.createStorageErrorId("MSSQL", "CREATE_TABLE", "FAILED"),
355
+ domain: error.ErrorDomain.STORAGE,
356
+ category: error.ErrorCategory.THIRD_PARTY,
357
+ details: {
358
+ tableName
359
+ }
360
+ },
361
+ error$1
362
+ );
363
+ }
364
+ }
365
+ /**
366
+ * Migrates the spans table schema from OLD_SPAN_SCHEMA to current SPAN_SCHEMA.
367
+ * This adds new columns that don't exist in old schema.
368
+ */
369
+ async migrateSpansTable() {
370
+ const fullTableName = getTableName({ indexName: storage.TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
371
+ const schema = storage.TABLE_SCHEMAS[storage.TABLE_SPANS];
372
+ try {
373
+ for (const [columnName, columnDef] of Object.entries(schema)) {
374
+ const columnExists = await this.hasColumn(storage.TABLE_SPANS, columnName);
375
+ if (!columnExists) {
376
+ const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
377
+ const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(columnName);
378
+ const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(columnName);
379
+ const isIndexed = !!columnDef.primaryKey;
380
+ const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage, useSmallStorage);
381
+ const nullable = columnDef.nullable ? "" : "NOT NULL";
382
+ const defaultValue = !columnDef.nullable ? this.getDefaultValue(columnDef.type) : "";
383
+ const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
384
+ await this.pool.request().query(alterSql);
385
+ this.logger?.debug?.(`Added column '${columnName}' to ${fullTableName}`);
386
+ }
387
+ }
388
+ this.logger?.info?.(`Migration completed for ${fullTableName}`);
389
+ } catch (error) {
390
+ this.logger?.warn?.(`Failed to migrate spans table ${fullTableName}:`, error);
391
+ }
392
+ }
393
+ /**
394
+ * Alters table schema to add columns if they don't exist
395
+ * @param tableName Name of the table
396
+ * @param schema Schema of the table
397
+ * @param ifNotExists Array of column names to add if they don't exist
398
+ */
399
+ async alterTable({
400
+ tableName,
401
+ schema,
402
+ ifNotExists
403
+ }) {
404
+ const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
405
+ try {
406
+ for (const columnName of ifNotExists) {
407
+ if (schema[columnName]) {
408
+ const columnCheckRequest = this.pool.request();
409
+ columnCheckRequest.input("tableName", fullTableName.replace(/[[\]]/g, "").split(".").pop());
410
+ columnCheckRequest.input("columnName", columnName);
411
+ columnCheckRequest.input("schema", this.schemaName || "dbo");
412
+ const checkSql = `SELECT 1 AS found FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName AND COLUMN_NAME = @columnName`;
413
+ const checkResult = await columnCheckRequest.query(checkSql);
414
+ const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
415
+ if (!columnExists) {
416
+ const columnDef = schema[columnName];
417
+ const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(columnName);
418
+ const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(columnName);
419
+ const isIndexed = !!columnDef.primaryKey;
420
+ const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage, useSmallStorage);
421
+ const nullable = columnDef.nullable ? "" : "NOT NULL";
422
+ const defaultValue = !columnDef.nullable ? this.getDefaultValue(columnDef.type) : "";
423
+ const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
424
+ const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
425
+ await this.pool.request().query(alterSql);
426
+ this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
427
+ }
428
+ }
429
+ }
430
+ } catch (error$1) {
431
+ throw new error.MastraError(
432
+ {
433
+ id: storage.createStorageErrorId("MSSQL", "ALTER_TABLE", "FAILED"),
434
+ domain: error.ErrorDomain.STORAGE,
435
+ category: error.ErrorCategory.THIRD_PARTY,
436
+ details: {
437
+ tableName
438
+ }
439
+ },
440
+ error$1
441
+ );
442
+ }
443
+ }
444
+ async load({ tableName, keys }) {
445
+ try {
446
+ const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
447
+ const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
448
+ const sqlQuery = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
449
+ const request = this.pool.request();
450
+ keyEntries.forEach(([key, value], i) => {
451
+ const preparedValue = this.prepareValue(value, key, tableName);
452
+ if (preparedValue === null || preparedValue === void 0) {
453
+ request.input(`param${i}`, this.getMssqlType(tableName, key), null);
454
+ } else {
455
+ request.input(`param${i}`, preparedValue);
456
+ }
457
+ });
458
+ const resultSet = await request.query(sqlQuery);
459
+ const result = resultSet.recordset[0] || null;
460
+ if (!result) {
461
+ return null;
462
+ }
463
+ if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
464
+ const snapshot = result;
465
+ if (typeof snapshot.snapshot === "string") {
466
+ snapshot.snapshot = JSON.parse(snapshot.snapshot);
467
+ }
468
+ return snapshot;
469
+ }
470
+ return result;
471
+ } catch (error$1) {
472
+ throw new error.MastraError(
473
+ {
474
+ id: storage.createStorageErrorId("MSSQL", "LOAD", "FAILED"),
475
+ domain: error.ErrorDomain.STORAGE,
476
+ category: error.ErrorCategory.THIRD_PARTY,
477
+ details: {
478
+ tableName
479
+ }
480
+ },
481
+ error$1
482
+ );
483
+ }
484
+ }
485
+ async batchInsert({ tableName, records }) {
486
+ const transaction = this.pool.transaction();
487
+ try {
488
+ await transaction.begin();
489
+ for (const record of records) {
490
+ await this.insert({ tableName, record, transaction });
491
+ }
492
+ await transaction.commit();
493
+ } catch (error$1) {
494
+ await transaction.rollback();
495
+ throw new error.MastraError(
496
+ {
497
+ id: storage.createStorageErrorId("MSSQL", "BATCH_INSERT", "FAILED"),
498
+ domain: error.ErrorDomain.STORAGE,
499
+ category: error.ErrorCategory.THIRD_PARTY,
500
+ details: {
501
+ tableName,
502
+ numberOfRecords: records.length
503
+ }
504
+ },
505
+ error$1
506
+ );
507
+ }
508
+ }
509
+ async dropTable({ tableName }) {
510
+ try {
511
+ const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
512
+ await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
513
+ } catch (error$1) {
514
+ throw new error.MastraError(
515
+ {
516
+ id: storage.createStorageErrorId("MSSQL", "DROP_TABLE", "FAILED"),
517
+ domain: error.ErrorDomain.STORAGE,
518
+ category: error.ErrorCategory.THIRD_PARTY,
519
+ details: {
520
+ tableName
521
+ }
522
+ },
523
+ error$1
524
+ );
525
+ }
526
+ }
527
+ /**
528
+ * Prepares a value for database operations, handling Date objects and JSON serialization
529
+ */
530
+ prepareValue(value, columnName, tableName) {
531
+ if (value === null || value === void 0) {
532
+ return value;
533
+ }
534
+ if (value instanceof Date) {
535
+ return value;
536
+ }
537
+ const schema = storage.TABLE_SCHEMAS[tableName];
538
+ const columnSchema = schema?.[columnName];
539
+ if (columnSchema?.type === "boolean") {
540
+ return value ? 1 : 0;
541
+ }
542
+ if (columnSchema?.type === "jsonb") {
543
+ if (typeof value === "string") {
544
+ const trimmed = value.trim();
545
+ if (trimmed.length > 0) {
546
+ try {
547
+ JSON.parse(trimmed);
548
+ return trimmed;
549
+ } catch {
550
+ }
551
+ }
552
+ return JSON.stringify(value);
553
+ }
554
+ if (typeof value === "bigint") {
555
+ return value.toString();
556
+ }
557
+ return JSON.stringify(value);
558
+ }
559
+ if (typeof value === "object") {
560
+ return JSON.stringify(value);
561
+ }
562
+ return value;
563
+ }
564
+ /**
565
+ * Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
566
+ */
567
+ getMssqlType(tableName, columnName) {
568
+ const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
569
+ switch (col?.type) {
570
+ case "text":
571
+ return sql__default.default.NVarChar;
572
+ case "timestamp":
573
+ return sql__default.default.DateTime2;
574
+ case "uuid":
575
+ return sql__default.default.UniqueIdentifier;
576
+ case "jsonb":
577
+ return sql__default.default.NVarChar;
578
+ case "integer":
579
+ return sql__default.default.Int;
580
+ case "bigint":
581
+ return sql__default.default.BigInt;
582
+ case "float":
583
+ return sql__default.default.Float;
584
+ case "boolean":
585
+ return sql__default.default.Bit;
586
+ default:
587
+ return sql__default.default.NVarChar;
588
+ }
589
+ }
590
+ /**
591
+ * Update a single record in the database
592
+ */
593
+ async update({
594
+ tableName,
595
+ keys,
596
+ data,
597
+ transaction
598
+ }) {
599
+ try {
600
+ if (!data || Object.keys(data).length === 0) {
601
+ throw new error.MastraError({
602
+ id: storage.createStorageErrorId("MSSQL", "UPDATE", "EMPTY_DATA"),
603
+ domain: error.ErrorDomain.STORAGE,
604
+ category: error.ErrorCategory.USER,
605
+ text: "Cannot update with empty data payload"
606
+ });
607
+ }
608
+ if (!keys || Object.keys(keys).length === 0) {
609
+ throw new error.MastraError({
610
+ id: storage.createStorageErrorId("MSSQL", "UPDATE", "EMPTY_KEYS"),
611
+ domain: error.ErrorDomain.STORAGE,
612
+ category: error.ErrorCategory.USER,
613
+ text: "Cannot update without keys to identify records"
614
+ });
615
+ }
616
+ const setClauses = [];
617
+ const request = transaction ? transaction.request() : this.pool.request();
618
+ let paramIndex = 0;
619
+ Object.entries(data).forEach(([key, value]) => {
620
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
621
+ const paramName = `set${paramIndex++}`;
622
+ setClauses.push(`[${parsedKey}] = @${paramName}`);
623
+ const preparedValue = this.prepareValue(value, key, tableName);
624
+ if (preparedValue === null || preparedValue === void 0) {
625
+ request.input(paramName, this.getMssqlType(tableName, key), null);
626
+ } else {
627
+ request.input(paramName, preparedValue);
628
+ }
629
+ });
630
+ const whereConditions = [];
631
+ Object.entries(keys).forEach(([key, value]) => {
632
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
633
+ const paramName = `where${paramIndex++}`;
634
+ whereConditions.push(`[${parsedKey}] = @${paramName}`);
635
+ const preparedValue = this.prepareValue(value, key, tableName);
636
+ if (preparedValue === null || preparedValue === void 0) {
637
+ request.input(paramName, this.getMssqlType(tableName, key), null);
638
+ } else {
639
+ request.input(paramName, preparedValue);
640
+ }
641
+ });
642
+ const tableName_ = getTableName({
643
+ indexName: tableName,
644
+ schemaName: getSchemaName(this.schemaName)
645
+ });
646
+ const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
647
+ await request.query(updateSql);
648
+ } catch (error$1) {
649
+ throw new error.MastraError(
650
+ {
651
+ id: storage.createStorageErrorId("MSSQL", "UPDATE", "FAILED"),
652
+ domain: error.ErrorDomain.STORAGE,
653
+ category: error.ErrorCategory.THIRD_PARTY,
654
+ details: {
655
+ tableName
656
+ }
657
+ },
658
+ error$1
659
+ );
660
+ }
661
+ }
662
+ /**
663
+ * Update multiple records in a single batch transaction
664
+ */
665
+ async batchUpdate({
666
+ tableName,
667
+ updates
668
+ }) {
669
+ const transaction = this.pool.transaction();
670
+ try {
671
+ await transaction.begin();
672
+ for (const { keys, data } of updates) {
673
+ await this.update({ tableName, keys, data, transaction });
674
+ }
675
+ await transaction.commit();
676
+ } catch (error$1) {
677
+ await transaction.rollback();
678
+ throw new error.MastraError(
679
+ {
680
+ id: storage.createStorageErrorId("MSSQL", "BATCH_UPDATE", "FAILED"),
681
+ domain: error.ErrorDomain.STORAGE,
682
+ category: error.ErrorCategory.THIRD_PARTY,
683
+ details: {
684
+ tableName,
685
+ numberOfRecords: updates.length
686
+ }
687
+ },
688
+ error$1
689
+ );
690
+ }
691
+ }
692
+ /**
693
+ * Delete multiple records by keys
694
+ */
695
+ async batchDelete({ tableName, keys }) {
696
+ if (keys.length === 0) {
697
+ return;
698
+ }
699
+ const tableName_ = getTableName({
700
+ indexName: tableName,
701
+ schemaName: getSchemaName(this.schemaName)
702
+ });
703
+ const transaction = this.pool.transaction();
704
+ try {
705
+ await transaction.begin();
706
+ for (const keySet of keys) {
707
+ const conditions = [];
708
+ const request = transaction.request();
709
+ let paramIndex = 0;
710
+ Object.entries(keySet).forEach(([key, value]) => {
711
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
712
+ const paramName = `p${paramIndex++}`;
713
+ conditions.push(`[${parsedKey}] = @${paramName}`);
714
+ const preparedValue = this.prepareValue(value, key, tableName);
715
+ if (preparedValue === null || preparedValue === void 0) {
716
+ request.input(paramName, this.getMssqlType(tableName, key), null);
717
+ } else {
718
+ request.input(paramName, preparedValue);
719
+ }
720
+ });
721
+ const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
722
+ await request.query(deleteSql);
723
+ }
724
+ await transaction.commit();
725
+ } catch (error$1) {
726
+ await transaction.rollback();
727
+ throw new error.MastraError(
728
+ {
729
+ id: storage.createStorageErrorId("MSSQL", "BATCH_DELETE", "FAILED"),
730
+ domain: error.ErrorDomain.STORAGE,
731
+ category: error.ErrorCategory.THIRD_PARTY,
732
+ details: {
733
+ tableName,
734
+ numberOfRecords: keys.length
735
+ }
736
+ },
737
+ error$1
738
+ );
739
+ }
740
+ }
741
+ /**
742
+ * Create a new index on a table
743
+ */
744
+ async createIndex(options) {
745
+ try {
746
+ const { name, table, columns, unique = false, where } = options;
747
+ const schemaName = this.schemaName || "dbo";
748
+ const fullTableName = getTableName({
749
+ indexName: table,
750
+ schemaName: getSchemaName(this.schemaName)
751
+ });
752
+ const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
753
+ const checkRequest = this.pool.request();
754
+ checkRequest.input("indexName", indexNameSafe);
755
+ checkRequest.input("schemaName", schemaName);
756
+ checkRequest.input("tableName", table);
757
+ const indexExists = await checkRequest.query(`
758
+ SELECT 1 as found
759
+ FROM sys.indexes i
760
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
761
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
762
+ WHERE i.name = @indexName
763
+ AND s.name = @schemaName
764
+ AND t.name = @tableName
765
+ `);
766
+ if (indexExists.recordset && indexExists.recordset.length > 0) {
767
+ return;
768
+ }
769
+ const uniqueStr = unique ? "UNIQUE " : "";
770
+ const columnsStr = columns.map((col) => {
771
+ if (col.includes(" DESC") || col.includes(" ASC")) {
772
+ const [colName, ...modifiers] = col.split(" ");
773
+ if (!colName) {
774
+ throw new Error(`Invalid column specification: ${col}`);
775
+ }
776
+ return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
777
+ }
778
+ return `[${utils.parseSqlIdentifier(col, "column name")}]`;
779
+ }).join(", ");
780
+ const whereStr = where ? ` WHERE ${where}` : "";
781
+ const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
782
+ await this.pool.request().query(createIndexSql);
783
+ } catch (error$1) {
784
+ throw new error.MastraError(
785
+ {
786
+ id: storage.createStorageErrorId("MSSQL", "INDEX_CREATE", "FAILED"),
787
+ domain: error.ErrorDomain.STORAGE,
788
+ category: error.ErrorCategory.THIRD_PARTY,
789
+ details: {
790
+ indexName: options.name,
791
+ tableName: options.table
792
+ }
793
+ },
794
+ error$1
795
+ );
31
796
  }
32
797
  }
33
- if (row.test_info) {
798
+ /**
799
+ * Drop an existing index
800
+ */
801
+ async dropIndex(indexName) {
34
802
  try {
35
- resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
36
- } catch {
803
+ const schemaName = this.schemaName || "dbo";
804
+ const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
805
+ const checkRequest = this.pool.request();
806
+ checkRequest.input("indexName", indexNameSafe);
807
+ checkRequest.input("schemaName", schemaName);
808
+ const result = await checkRequest.query(`
809
+ SELECT t.name as table_name
810
+ FROM sys.indexes i
811
+ INNER JOIN sys.tables t ON i.object_id = t.object_id
812
+ INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
813
+ WHERE i.name = @indexName
814
+ AND s.name = @schemaName
815
+ `);
816
+ if (!result.recordset || result.recordset.length === 0) {
817
+ return;
818
+ }
819
+ if (result.recordset.length > 1) {
820
+ const tables = result.recordset.map((r) => r.table_name).join(", ");
821
+ throw new error.MastraError({
822
+ id: storage.createStorageErrorId("MSSQL", "INDEX", "AMBIGUOUS"),
823
+ domain: error.ErrorDomain.STORAGE,
824
+ category: error.ErrorCategory.USER,
825
+ text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
826
+ });
827
+ }
828
+ const tableName = result.recordset[0].table_name;
829
+ const fullTableName = getTableName({
830
+ indexName: tableName,
831
+ schemaName: getSchemaName(this.schemaName)
832
+ });
833
+ const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
834
+ await this.pool.request().query(dropSql);
835
+ } catch (error$1) {
836
+ throw new error.MastraError(
837
+ {
838
+ id: storage.createStorageErrorId("MSSQL", "INDEX_DROP", "FAILED"),
839
+ domain: error.ErrorDomain.STORAGE,
840
+ category: error.ErrorCategory.THIRD_PARTY,
841
+ details: {
842
+ indexName
843
+ }
844
+ },
845
+ error$1
846
+ );
37
847
  }
38
848
  }
39
- return {
40
- agentName: row.agent_name,
41
- input: row.input,
42
- output: row.output,
43
- result: resultValue,
44
- metricName: row.metric_name,
45
- instructions: row.instructions,
46
- testInfo: testInfoValue,
47
- globalRunId: row.global_run_id,
48
- runId: row.run_id,
49
- createdAt: row.created_at
50
- };
51
- }
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) {
849
+ /**
850
+ * List indexes for a specific table or all tables
851
+ */
852
+ async listIndexes(tableName) {
62
853
  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";
854
+ const schemaName = this.schemaName || "dbo";
855
+ let query;
70
856
  const request = this.pool.request();
71
- request.input("p1", agentName);
857
+ request.input("schemaName", schemaName);
858
+ if (tableName) {
859
+ query = `
860
+ SELECT
861
+ i.name as name,
862
+ o.name as [table],
863
+ i.is_unique as is_unique,
864
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
865
+ FROM sys.indexes i
866
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
867
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
868
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
869
+ WHERE sch.name = @schemaName
870
+ AND o.name = @tableName
871
+ AND i.name IS NOT NULL
872
+ GROUP BY i.name, o.name, i.is_unique
873
+ `;
874
+ request.input("tableName", tableName);
875
+ } else {
876
+ query = `
877
+ SELECT
878
+ i.name as name,
879
+ o.name as [table],
880
+ i.is_unique as is_unique,
881
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
882
+ FROM sys.indexes i
883
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
884
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
885
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
886
+ WHERE sch.name = @schemaName
887
+ AND i.name IS NOT NULL
888
+ GROUP BY i.name, o.name, i.is_unique
889
+ `;
890
+ }
72
891
  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`;
892
+ const indexes = [];
893
+ for (const row of result.recordset) {
894
+ const colRequest = this.pool.request();
895
+ colRequest.input("indexName", row.name);
896
+ colRequest.input("schemaName", schemaName);
897
+ const colResult = await colRequest.query(`
898
+ SELECT c.name as column_name
899
+ FROM sys.indexes i
900
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
901
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
902
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
903
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
904
+ WHERE i.name = @indexName
905
+ AND s.name = @schemaName
906
+ ORDER BY ic.key_ordinal
907
+ `);
908
+ indexes.push({
909
+ name: row.name,
910
+ table: row.table,
911
+ columns: colResult.recordset.map((c) => c.column_name),
912
+ unique: row.is_unique || false,
913
+ size: row.size || "0 MB",
914
+ definition: ""
915
+ // MSSQL doesn't store definition like PG
916
+ });
917
+ }
918
+ return indexes;
919
+ } catch (error$1) {
920
+ throw new error.MastraError(
921
+ {
922
+ id: storage.createStorageErrorId("MSSQL", "INDEX_LIST", "FAILED"),
923
+ domain: error.ErrorDomain.STORAGE,
924
+ category: error.ErrorCategory.THIRD_PARTY,
925
+ details: tableName ? {
926
+ tableName
927
+ } : {}
928
+ },
929
+ error$1
930
+ );
931
+ }
932
+ }
933
+ /**
934
+ * Get detailed statistics for a specific index
935
+ */
936
+ async describeIndex(indexName) {
111
937
  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
- };
938
+ const schemaName = this.schemaName || "dbo";
939
+ const request = this.pool.request();
940
+ request.input("indexName", indexName);
941
+ request.input("schemaName", schemaName);
942
+ const query = `
943
+ SELECT
944
+ i.name as name,
945
+ o.name as [table],
946
+ i.is_unique as is_unique,
947
+ CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
948
+ i.type_desc as method,
949
+ ISNULL(us.user_scans, 0) as scans,
950
+ ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
951
+ ISNULL(us.user_lookups, 0) as tuples_fetched
952
+ FROM sys.indexes i
953
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
954
+ INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
955
+ LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
956
+ LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
957
+ WHERE i.name = @indexName
958
+ AND sch.name = @schemaName
959
+ GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
960
+ `;
961
+ const result = await request.query(query);
962
+ if (!result.recordset || result.recordset.length === 0) {
963
+ throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
130
964
  }
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;
965
+ const row = result.recordset[0];
966
+ const colRequest = this.pool.request();
967
+ colRequest.input("indexName", indexName);
968
+ colRequest.input("schemaName", schemaName);
969
+ const colResult = await colRequest.query(`
970
+ SELECT c.name as column_name
971
+ FROM sys.indexes i
972
+ INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
973
+ INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
974
+ INNER JOIN sys.objects o ON i.object_id = o.object_id
975
+ INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
976
+ WHERE i.name = @indexName
977
+ AND s.name = @schemaName
978
+ ORDER BY ic.key_ordinal
979
+ `);
143
980
  return {
144
- evals: rows?.map((row) => transformEvalRow(row)) ?? [],
145
- total,
146
- page,
147
- perPage,
148
- hasMore: offset + (rows?.length ?? 0) < total
981
+ name: row.name,
982
+ table: row.table,
983
+ columns: colResult.recordset.map((c) => c.column_name),
984
+ unique: row.is_unique || false,
985
+ size: row.size || "0 MB",
986
+ definition: "",
987
+ method: row.method?.toLowerCase() || "nonclustered",
988
+ scans: Number(row.scans) || 0,
989
+ tuples_read: Number(row.tuples_read) || 0,
990
+ tuples_fetched: Number(row.tuples_fetched) || 0
149
991
  };
150
992
  } catch (error$1) {
151
- const mastraError = new error.MastraError(
993
+ throw new error.MastraError(
152
994
  {
153
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_EVALS_FAILED",
995
+ id: storage.createStorageErrorId("MSSQL", "INDEX_DESCRIBE", "FAILED"),
154
996
  domain: error.ErrorDomain.STORAGE,
155
997
  category: error.ErrorCategory.THIRD_PARTY,
156
998
  details: {
157
- agentName: agentName || "all",
158
- type: type || "all",
159
- page,
160
- perPage
999
+ indexName
161
1000
  }
162
1001
  },
163
1002
  error$1
164
1003
  );
165
- this.logger?.error?.(mastraError.toString());
166
- this.logger?.trackException(mastraError);
167
- throw mastraError;
168
1004
  }
169
1005
  }
170
1006
  };
171
- var MemoryMSSQL = class extends storage.MemoryStorage {
1007
+ function getSchemaName2(schema) {
1008
+ return schema ? `[${utils.parseSqlIdentifier(schema, "schema name")}]` : void 0;
1009
+ }
1010
+ function getTableName2({ indexName, schemaName }) {
1011
+ const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
1012
+ const quotedIndexName = `[${parsedIndexName}]`;
1013
+ const quotedSchemaName = schemaName;
1014
+ return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
1015
+ }
1016
+ function buildDateRangeFilter(dateRange, fieldName) {
1017
+ const filters = {};
1018
+ if (dateRange?.start) {
1019
+ const suffix = dateRange.startExclusive ? "_gt" : "_gte";
1020
+ filters[`${fieldName}${suffix}`] = dateRange.start;
1021
+ }
1022
+ if (dateRange?.end) {
1023
+ const suffix = dateRange.endExclusive ? "_lt" : "_lte";
1024
+ filters[`${fieldName}${suffix}`] = dateRange.end;
1025
+ }
1026
+ return filters;
1027
+ }
1028
+ function isInOperator(value) {
1029
+ return typeof value === "object" && value !== null && "$in" in value && Array.isArray(value.$in);
1030
+ }
1031
+ function prepareWhereClause(filters, _schema) {
1032
+ const conditions = [];
1033
+ const params = {};
1034
+ let paramIndex = 1;
1035
+ Object.entries(filters).forEach(([key, value]) => {
1036
+ if (value === void 0) return;
1037
+ if (key.endsWith("_gte")) {
1038
+ const paramName = `p${paramIndex++}`;
1039
+ const fieldName = key.slice(0, -4);
1040
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
1041
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
1042
+ } else if (key.endsWith("_gt")) {
1043
+ const paramName = `p${paramIndex++}`;
1044
+ const fieldName = key.slice(0, -3);
1045
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] > @${paramName}`);
1046
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
1047
+ } else if (key.endsWith("_lte")) {
1048
+ const paramName = `p${paramIndex++}`;
1049
+ const fieldName = key.slice(0, -4);
1050
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
1051
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
1052
+ } else if (key.endsWith("_lt")) {
1053
+ const paramName = `p${paramIndex++}`;
1054
+ const fieldName = key.slice(0, -3);
1055
+ conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] < @${paramName}`);
1056
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
1057
+ } else if (value === null) {
1058
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
1059
+ } else if (isInOperator(value)) {
1060
+ const inValues = value.$in;
1061
+ if (inValues.length === 0) {
1062
+ conditions.push("1 = 0");
1063
+ } else if (inValues.length === 1) {
1064
+ const paramName = `p${paramIndex++}`;
1065
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
1066
+ params[paramName] = inValues[0] instanceof Date ? inValues[0].toISOString() : inValues[0];
1067
+ } else {
1068
+ const inParamNames = [];
1069
+ for (const item of inValues) {
1070
+ const paramName = `p${paramIndex++}`;
1071
+ inParamNames.push(`@${paramName}`);
1072
+ params[paramName] = item instanceof Date ? item.toISOString() : item;
1073
+ }
1074
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IN (${inParamNames.join(", ")})`);
1075
+ }
1076
+ } else if (Array.isArray(value)) {
1077
+ if (value.length === 0) {
1078
+ conditions.push("1 = 0");
1079
+ } else if (value.length === 1) {
1080
+ const paramName = `p${paramIndex++}`;
1081
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
1082
+ params[paramName] = value[0] instanceof Date ? value[0].toISOString() : value[0];
1083
+ } else {
1084
+ const inParamNames = [];
1085
+ for (const item of value) {
1086
+ const paramName = `p${paramIndex++}`;
1087
+ inParamNames.push(`@${paramName}`);
1088
+ params[paramName] = item instanceof Date ? item.toISOString() : item;
1089
+ }
1090
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IN (${inParamNames.join(", ")})`);
1091
+ }
1092
+ } else {
1093
+ const paramName = `p${paramIndex++}`;
1094
+ conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
1095
+ params[paramName] = value instanceof Date ? value.toISOString() : value;
1096
+ }
1097
+ });
1098
+ return {
1099
+ sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
1100
+ params
1101
+ };
1102
+ }
1103
+ function transformFromSqlRow({
1104
+ tableName,
1105
+ sqlRow
1106
+ }) {
1107
+ const schema = storage.TABLE_SCHEMAS[tableName];
1108
+ const result = {};
1109
+ Object.entries(sqlRow).forEach(([key, value]) => {
1110
+ const columnSchema = schema?.[key];
1111
+ if (columnSchema?.type === "jsonb" && typeof value === "string") {
1112
+ try {
1113
+ result[key] = JSON.parse(value);
1114
+ } catch {
1115
+ result[key] = value;
1116
+ }
1117
+ } else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
1118
+ result[key] = new Date(value);
1119
+ } else if (columnSchema?.type === "timestamp" && value instanceof Date) {
1120
+ result[key] = value;
1121
+ } else if (columnSchema?.type === "boolean") {
1122
+ result[key] = Boolean(value);
1123
+ } else {
1124
+ result[key] = value;
1125
+ }
1126
+ });
1127
+ return result;
1128
+ }
1129
+
1130
+ // src/storage/domains/memory/index.ts
1131
+ var MemoryMSSQL = class _MemoryMSSQL extends storage.MemoryStorage {
172
1132
  pool;
173
1133
  schema;
174
- operations;
1134
+ db;
1135
+ needsConnect;
1136
+ skipDefaultIndexes;
1137
+ indexes;
1138
+ /** Tables managed by this domain */
1139
+ static MANAGED_TABLES = [storage.TABLE_THREADS, storage.TABLE_MESSAGES, storage.TABLE_RESOURCES];
175
1140
  _parseAndFormatMessages(messages, format) {
176
1141
  const messagesWithParsedContent = messages.map((message) => {
177
1142
  if (typeof message.content === "string") {
@@ -185,32 +1150,97 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
185
1150
  });
186
1151
  const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
187
1152
  const list = new agent.MessageList().add(cleanMessages, "memory");
188
- return format === "v2" ? list.get.all.v2() : list.get.all.v1();
1153
+ return format === "v2" ? list.get.all.db() : list.get.all.v1();
189
1154
  }
190
- constructor({
191
- pool,
192
- schema,
193
- operations
194
- }) {
1155
+ constructor(config) {
195
1156
  super();
1157
+ const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
196
1158
  this.pool = pool;
197
- this.schema = schema;
198
- this.operations = operations;
1159
+ this.schema = schemaName;
1160
+ this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
1161
+ this.needsConnect = needsConnect;
1162
+ this.skipDefaultIndexes = skipDefaultIndexes;
1163
+ this.indexes = indexes?.filter((idx) => _MemoryMSSQL.MANAGED_TABLES.includes(idx.table));
1164
+ }
1165
+ async init() {
1166
+ if (this.needsConnect) {
1167
+ await this.pool.connect();
1168
+ this.needsConnect = false;
1169
+ }
1170
+ await this.db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
1171
+ await this.db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
1172
+ await this.db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
1173
+ await this.createDefaultIndexes();
1174
+ await this.createCustomIndexes();
1175
+ }
1176
+ /**
1177
+ * Returns default index definitions for the memory domain tables.
1178
+ * IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
1179
+ */
1180
+ getDefaultIndexDefinitions() {
1181
+ const schemaPrefix = this.schema ? `${this.schema}_` : "";
1182
+ return [
1183
+ {
1184
+ name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
1185
+ table: storage.TABLE_THREADS,
1186
+ columns: ["resourceId", "seq_id DESC"]
1187
+ },
1188
+ {
1189
+ name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
1190
+ table: storage.TABLE_MESSAGES,
1191
+ columns: ["thread_id", "seq_id DESC"]
1192
+ }
1193
+ ];
1194
+ }
1195
+ /**
1196
+ * Creates default indexes for optimal query performance.
1197
+ */
1198
+ async createDefaultIndexes() {
1199
+ if (this.skipDefaultIndexes) {
1200
+ return;
1201
+ }
1202
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
1203
+ try {
1204
+ await this.db.createIndex(indexDef);
1205
+ } catch (error) {
1206
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
1207
+ }
1208
+ }
1209
+ }
1210
+ /**
1211
+ * Creates custom user-defined indexes for this domain's tables.
1212
+ */
1213
+ async createCustomIndexes() {
1214
+ if (!this.indexes || this.indexes.length === 0) {
1215
+ return;
1216
+ }
1217
+ for (const indexDef of this.indexes) {
1218
+ try {
1219
+ await this.db.createIndex(indexDef);
1220
+ } catch (error) {
1221
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
1222
+ }
1223
+ }
1224
+ }
1225
+ async dangerouslyClearAll() {
1226
+ await this.db.clearTable({ tableName: storage.TABLE_MESSAGES });
1227
+ await this.db.clearTable({ tableName: storage.TABLE_THREADS });
1228
+ await this.db.clearTable({ tableName: storage.TABLE_RESOURCES });
199
1229
  }
200
1230
  async getThreadById({ threadId }) {
201
1231
  try {
202
- const sql7 = `SELECT
1232
+ const sql5 = `SELECT
203
1233
  id,
204
1234
  [resourceId],
205
1235
  title,
206
1236
  metadata,
207
1237
  [createdAt],
208
1238
  [updatedAt]
209
- FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })}
1239
+ FROM ${getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) })}
210
1240
  WHERE id = @threadId`;
211
1241
  const request = this.pool.request();
212
1242
  request.input("threadId", threadId);
213
- const resultSet = await request.query(sql7);
1243
+ const resultSet = await request.query(sql5);
214
1244
  const thread = resultSet.recordset[0] || null;
215
1245
  if (!thread) {
216
1246
  return null;
@@ -224,7 +1254,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
224
1254
  } catch (error$1) {
225
1255
  throw new error.MastraError(
226
1256
  {
227
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_THREAD_BY_ID_FAILED",
1257
+ id: storage.createStorageErrorId("MSSQL", "GET_THREAD_BY_ID", "FAILED"),
228
1258
  domain: error.ErrorDomain.STORAGE,
229
1259
  category: error.ErrorCategory.THIRD_PARTY,
230
1260
  details: {
@@ -235,12 +1265,25 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
235
1265
  );
236
1266
  }
237
1267
  }
238
- async getThreadsByResourceIdPaginated(args) {
239
- const { resourceId, page = 0, perPage: perPageInput, orderBy = "createdAt", sortDirection = "DESC" } = args;
1268
+ async listThreadsByResourceId(args) {
1269
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
1270
+ if (page < 0) {
1271
+ throw new error.MastraError({
1272
+ id: storage.createStorageErrorId("MSSQL", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
1273
+ domain: error.ErrorDomain.STORAGE,
1274
+ category: error.ErrorCategory.USER,
1275
+ text: "Page number must be non-negative",
1276
+ details: {
1277
+ resourceId,
1278
+ page
1279
+ }
1280
+ });
1281
+ }
1282
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1283
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1284
+ const { field, direction } = this.parseOrderBy(orderBy);
240
1285
  try {
241
- const perPage = perPageInput !== void 0 ? perPageInput : 100;
242
- const currentOffset = page * perPage;
243
- const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
1286
+ const baseQuery = `FROM ${getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) })} WHERE [resourceId] = @resourceId`;
244
1287
  const countQuery = `SELECT COUNT(*) as count ${baseQuery}`;
245
1288
  const countRequest = this.pool.request();
246
1289
  countRequest.input("resourceId", resourceId);
@@ -251,16 +1294,22 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
251
1294
  threads: [],
252
1295
  total: 0,
253
1296
  page,
254
- perPage,
1297
+ perPage: perPageForResponse,
255
1298
  hasMore: false
256
1299
  };
257
1300
  }
258
- const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
259
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
1301
+ const orderByField = field === "createdAt" ? "[createdAt]" : "[updatedAt]";
1302
+ const dir = (direction || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
1303
+ const limitValue = perPageInput === false ? total : perPage;
1304
+ const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
260
1305
  const dataRequest = this.pool.request();
261
1306
  dataRequest.input("resourceId", resourceId);
262
- dataRequest.input("perPage", perPage);
263
- dataRequest.input("offset", currentOffset);
1307
+ dataRequest.input("offset", offset);
1308
+ if (limitValue > 2147483647) {
1309
+ dataRequest.input("perPage", sql__default.default.BigInt, limitValue);
1310
+ } else {
1311
+ dataRequest.input("perPage", limitValue);
1312
+ }
264
1313
  const rowsResult = await dataRequest.query(dataQuery);
265
1314
  const rows = rowsResult.recordset || [];
266
1315
  const threads = rows.map((thread) => ({
@@ -273,13 +1322,13 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
273
1322
  threads,
274
1323
  total,
275
1324
  page,
276
- perPage,
277
- hasMore: currentOffset + threads.length < total
1325
+ perPage: perPageForResponse,
1326
+ hasMore: perPageInput === false ? false : offset + perPage < total
278
1327
  };
279
1328
  } catch (error$1) {
280
1329
  const mastraError = new error.MastraError(
281
1330
  {
282
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1331
+ id: storage.createStorageErrorId("MSSQL", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
283
1332
  domain: error.ErrorDomain.STORAGE,
284
1333
  category: error.ErrorCategory.THIRD_PARTY,
285
1334
  details: {
@@ -291,12 +1340,18 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
291
1340
  );
292
1341
  this.logger?.error?.(mastraError.toString());
293
1342
  this.logger?.trackException?.(mastraError);
294
- return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
1343
+ return {
1344
+ threads: [],
1345
+ total: 0,
1346
+ page,
1347
+ perPage: perPageForResponse,
1348
+ hasMore: false
1349
+ };
295
1350
  }
296
1351
  }
297
1352
  async saveThread({ thread }) {
298
1353
  try {
299
- const table = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1354
+ const table = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
300
1355
  const mergeSql = `MERGE INTO ${table} WITH (HOLDLOCK) AS target
301
1356
  USING (SELECT @id AS id) AS source
302
1357
  ON (target.id = source.id)
@@ -313,15 +1368,20 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
313
1368
  req.input("id", thread.id);
314
1369
  req.input("resourceId", thread.resourceId);
315
1370
  req.input("title", thread.title);
316
- req.input("metadata", thread.metadata ? JSON.stringify(thread.metadata) : null);
317
- req.input("createdAt", sql2__default.default.DateTime2, thread.createdAt);
318
- req.input("updatedAt", sql2__default.default.DateTime2, thread.updatedAt);
1371
+ const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
1372
+ if (metadata === null) {
1373
+ req.input("metadata", sql__default.default.NVarChar, null);
1374
+ } else {
1375
+ req.input("metadata", metadata);
1376
+ }
1377
+ req.input("createdAt", sql__default.default.DateTime2, thread.createdAt);
1378
+ req.input("updatedAt", sql__default.default.DateTime2, thread.updatedAt);
319
1379
  await req.query(mergeSql);
320
1380
  return thread;
321
1381
  } catch (error$1) {
322
1382
  throw new error.MastraError(
323
1383
  {
324
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_THREAD_FAILED",
1384
+ id: storage.createStorageErrorId("MSSQL", "SAVE_THREAD", "FAILED"),
325
1385
  domain: error.ErrorDomain.STORAGE,
326
1386
  category: error.ErrorCategory.THIRD_PARTY,
327
1387
  details: {
@@ -332,30 +1392,6 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
332
1392
  );
333
1393
  }
334
1394
  }
335
- /**
336
- * @deprecated use getThreadsByResourceIdPaginated instead
337
- */
338
- async getThreadsByResourceId(args) {
339
- const { resourceId, orderBy = "createdAt", sortDirection = "DESC" } = args;
340
- try {
341
- const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
342
- const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
343
- const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${sortDirection}`;
344
- const request = this.pool.request();
345
- request.input("resourceId", resourceId);
346
- const resultSet = await request.query(dataQuery);
347
- const rows = resultSet.recordset || [];
348
- return rows.map((thread) => ({
349
- ...thread,
350
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
351
- createdAt: thread.createdAt,
352
- updatedAt: thread.updatedAt
353
- }));
354
- } catch (error) {
355
- this.logger?.error?.(`Error getting threads for resource ${resourceId}:`, error);
356
- return [];
357
- }
358
- }
359
1395
  /**
360
1396
  * Updates a thread's title and metadata, merging with existing metadata. Returns the updated thread.
361
1397
  */
@@ -367,7 +1403,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
367
1403
  const existingThread = await this.getThreadById({ threadId: id });
368
1404
  if (!existingThread) {
369
1405
  throw new error.MastraError({
370
- id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_THREAD_FAILED",
1406
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "NOT_FOUND"),
371
1407
  domain: error.ErrorDomain.STORAGE,
372
1408
  category: error.ErrorCategory.USER,
373
1409
  text: `Thread ${id} not found`,
@@ -382,8 +1418,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
382
1418
  ...metadata
383
1419
  };
384
1420
  try {
385
- const table = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
386
- const sql7 = `UPDATE ${table}
1421
+ const table = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
1422
+ const sql5 = `UPDATE ${table}
387
1423
  SET title = @title,
388
1424
  metadata = @metadata,
389
1425
  [updatedAt] = @updatedAt
@@ -394,7 +1430,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
394
1430
  req.input("title", title);
395
1431
  req.input("metadata", JSON.stringify(mergedMetadata));
396
1432
  req.input("updatedAt", /* @__PURE__ */ new Date());
397
- const result = await req.query(sql7);
1433
+ const result = await req.query(sql5);
398
1434
  let thread = result.recordset && result.recordset[0];
399
1435
  if (thread && "seq_id" in thread) {
400
1436
  const { seq_id, ...rest } = thread;
@@ -402,7 +1438,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
402
1438
  }
403
1439
  if (!thread) {
404
1440
  throw new error.MastraError({
405
- id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_THREAD_FAILED",
1441
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "NOT_FOUND"),
406
1442
  domain: error.ErrorDomain.STORAGE,
407
1443
  category: error.ErrorCategory.USER,
408
1444
  text: `Thread ${id} not found after update`,
@@ -421,7 +1457,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
421
1457
  } catch (error$1) {
422
1458
  throw new error.MastraError(
423
1459
  {
424
- id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_THREAD_FAILED",
1460
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_THREAD", "FAILED"),
425
1461
  domain: error.ErrorDomain.STORAGE,
426
1462
  category: error.ErrorCategory.THIRD_PARTY,
427
1463
  details: {
@@ -434,8 +1470,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
434
1470
  }
435
1471
  }
436
1472
  async deleteThread({ threadId }) {
437
- const messagesTable = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
438
- const threadsTable = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1473
+ const messagesTable = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
1474
+ const threadsTable = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
439
1475
  const deleteMessagesSql = `DELETE FROM ${messagesTable} WHERE [thread_id] = @threadId`;
440
1476
  const deleteThreadSql = `DELETE FROM ${threadsTable} WHERE id = @threadId`;
441
1477
  const tx = this.pool.transaction();
@@ -451,7 +1487,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
451
1487
  });
452
1488
  throw new error.MastraError(
453
1489
  {
454
- id: "MASTRA_STORAGE_MSSQL_STORE_DELETE_THREAD_FAILED",
1490
+ id: storage.createStorageErrorId("MSSQL", "DELETE_THREAD", "FAILED"),
455
1491
  domain: error.ErrorDomain.STORAGE,
456
1492
  category: error.ErrorCategory.THIRD_PARTY,
457
1493
  details: {
@@ -462,25 +1498,18 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
462
1498
  );
463
1499
  }
464
1500
  }
465
- async _getIncludedMessages({
466
- threadId,
467
- selectBy,
468
- orderByStatement
469
- }) {
470
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
471
- const include = selectBy?.include;
472
- if (!include) return null;
1501
+ async _getIncludedMessages({ include }) {
1502
+ if (!include || include.length === 0) return null;
473
1503
  const unionQueries = [];
474
1504
  const paramValues = [];
475
1505
  let paramIdx = 1;
476
1506
  const paramNames = [];
1507
+ const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
477
1508
  for (const inc of include) {
478
1509
  const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
479
- const searchId = inc.threadId || threadId;
480
- const pThreadId = `@p${paramIdx}`;
481
- const pId = `@p${paramIdx + 1}`;
482
- const pPrev = `@p${paramIdx + 2}`;
483
- const pNext = `@p${paramIdx + 3}`;
1510
+ const pId = `@p${paramIdx}`;
1511
+ const pPrev = `@p${paramIdx + 1}`;
1512
+ const pNext = `@p${paramIdx + 2}`;
484
1513
  unionQueries.push(
485
1514
  `
486
1515
  SELECT
@@ -493,30 +1522,32 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
493
1522
  m.[resourceId],
494
1523
  m.seq_id
495
1524
  FROM (
496
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
497
- FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
498
- WHERE [thread_id] = ${pThreadId}
1525
+ SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
1526
+ FROM ${tableName}
1527
+ WHERE [thread_id] = (SELECT thread_id FROM ${tableName} WHERE id = ${pId})
499
1528
  ) AS m
500
1529
  WHERE m.id = ${pId}
501
1530
  OR EXISTS (
502
1531
  SELECT 1
503
1532
  FROM (
504
- SELECT *, ROW_NUMBER() OVER (${orderByStatement}) as row_num
505
- FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
506
- WHERE [thread_id] = ${pThreadId}
1533
+ SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
1534
+ FROM ${tableName}
1535
+ WHERE [thread_id] = (SELECT thread_id FROM ${tableName} WHERE id = ${pId})
507
1536
  ) AS target
508
1537
  WHERE target.id = ${pId}
509
1538
  AND (
510
- (m.row_num <= target.row_num + ${pPrev} AND m.row_num > target.row_num)
1539
+ -- Get previous messages (messages that come BEFORE the target)
1540
+ (m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
511
1541
  OR
512
- (m.row_num >= target.row_num - ${pNext} AND m.row_num < target.row_num)
1542
+ -- Get next messages (messages that come AFTER the target)
1543
+ (m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
513
1544
  )
514
1545
  )
515
1546
  `
516
1547
  );
517
- paramValues.push(searchId, id, withPreviousMessages, withNextMessages);
518
- paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}`, `p${paramIdx + 3}`);
519
- paramIdx += 4;
1548
+ paramValues.push(id, withPreviousMessages, withNextMessages);
1549
+ paramNames.push(`p${paramIdx}`, `p${paramIdx + 1}`, `p${paramIdx + 2}`);
1550
+ paramIdx += 3;
520
1551
  }
521
1552
  const finalQuery = `
522
1553
  SELECT * FROM (
@@ -538,34 +1569,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
538
1569
  });
539
1570
  return dedupedRows;
540
1571
  }
541
- async getMessages(args) {
542
- const { threadId, resourceId, format, selectBy } = args;
1572
+ async listMessagesById({ messageIds }) {
1573
+ if (messageIds.length === 0) return { messages: [] };
543
1574
  const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
544
1575
  const orderByStatement = `ORDER BY [seq_id] DESC`;
545
- const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
546
1576
  try {
547
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
548
1577
  let rows = [];
549
- const include = selectBy?.include || [];
550
- if (include?.length) {
551
- const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
552
- if (includeMessages) {
553
- rows.push(...includeMessages);
554
- }
555
- }
556
- const excludeIds = rows.map((m) => m.id).filter(Boolean);
557
- let query = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [thread_id] = @threadId`;
1578
+ let query = `${selectStatement} FROM ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
558
1579
  const request = this.pool.request();
559
- request.input("threadId", threadId);
560
- if (excludeIds.length > 0) {
561
- const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
562
- query += ` AND id NOT IN (${excludeParams.join(", ")})`;
563
- excludeIds.forEach((id, idx) => {
564
- request.input(`id${idx}`, id);
565
- });
566
- }
567
- query += ` ${orderByStatement} OFFSET 0 ROWS FETCH NEXT @limit ROWS ONLY`;
568
- request.input("limit", limit);
1580
+ messageIds.forEach((id, i) => request.input(`id${i}`, id));
1581
+ query += ` ${orderByStatement}`;
569
1582
  const result = await request.query(query);
570
1583
  const remainingRows = result.recordset || [];
571
1584
  rows.push(...remainingRows);
@@ -573,157 +1586,177 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
573
1586
  const timeDiff = a.seq_id - b.seq_id;
574
1587
  return timeDiff;
575
1588
  });
576
- rows = rows.map(({ seq_id, ...rest }) => rest);
577
- return this._parseAndFormatMessages(rows, format);
1589
+ const messagesWithParsedContent = rows.map((row) => {
1590
+ if (typeof row.content === "string") {
1591
+ try {
1592
+ return { ...row, content: JSON.parse(row.content) };
1593
+ } catch {
1594
+ return row;
1595
+ }
1596
+ }
1597
+ return row;
1598
+ });
1599
+ const cleanMessages = messagesWithParsedContent.map(({ seq_id, ...rest }) => rest);
1600
+ const list = new agent.MessageList().add(cleanMessages, "memory");
1601
+ return { messages: list.get.all.db() };
578
1602
  } catch (error$1) {
579
1603
  const mastraError = new error.MastraError(
580
1604
  {
581
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_FAILED",
1605
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES_BY_ID", "FAILED"),
582
1606
  domain: error.ErrorDomain.STORAGE,
583
1607
  category: error.ErrorCategory.THIRD_PARTY,
584
1608
  details: {
585
- threadId,
586
- resourceId: resourceId ?? ""
1609
+ messageIds: JSON.stringify(messageIds)
587
1610
  }
588
1611
  },
589
1612
  error$1
590
1613
  );
591
1614
  this.logger?.error?.(mastraError.toString());
592
- this.logger?.trackException(mastraError);
593
- return [];
1615
+ this.logger?.trackException?.(mastraError);
1616
+ return { messages: [] };
594
1617
  }
595
1618
  }
596
- async getMessagesById({
597
- messageIds,
598
- format
599
- }) {
600
- if (messageIds.length === 0) return [];
601
- const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
602
- const orderByStatement = `ORDER BY [seq_id] DESC`;
603
- try {
604
- let rows = [];
605
- let query = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE [id] IN (${messageIds.map((_, i) => `@id${i}`).join(", ")})`;
606
- const request = this.pool.request();
607
- messageIds.forEach((id, i) => request.input(`id${i}`, id));
608
- query += ` ${orderByStatement}`;
609
- const result = await request.query(query);
610
- const remainingRows = result.recordset || [];
611
- rows.push(...remainingRows);
612
- rows.sort((a, b) => {
613
- const timeDiff = a.seq_id - b.seq_id;
614
- return timeDiff;
615
- });
616
- rows = rows.map(({ seq_id, ...rest }) => rest);
617
- if (format === `v1`) return this._parseAndFormatMessages(rows, format);
618
- return this._parseAndFormatMessages(rows, `v2`);
619
- } catch (error$1) {
620
- const mastraError = new error.MastraError(
1619
+ async listMessages(args) {
1620
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
1621
+ const threadIds = Array.isArray(threadId) ? threadId : [threadId];
1622
+ if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
1623
+ throw new error.MastraError(
621
1624
  {
622
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_BY_ID_FAILED",
1625
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "INVALID_THREAD_ID"),
623
1626
  domain: error.ErrorDomain.STORAGE,
624
1627
  category: error.ErrorCategory.THIRD_PARTY,
625
- details: {
626
- messageIds: JSON.stringify(messageIds)
627
- }
1628
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
628
1629
  },
629
- error$1
1630
+ new Error("threadId must be a non-empty string or array of non-empty strings")
630
1631
  );
631
- this.logger?.error?.(mastraError.toString());
632
- this.logger?.trackException(mastraError);
633
- return [];
634
1632
  }
635
- }
636
- async getMessagesPaginated(args) {
637
- const { threadId, resourceId, format, selectBy } = args;
638
- const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
1633
+ if (page < 0) {
1634
+ throw new error.MastraError({
1635
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "INVALID_PAGE"),
1636
+ domain: error.ErrorDomain.STORAGE,
1637
+ category: error.ErrorCategory.USER,
1638
+ text: "Page number must be non-negative",
1639
+ details: {
1640
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
1641
+ page
1642
+ }
1643
+ });
1644
+ }
1645
+ const perPage = storage.normalizePerPage(perPageInput, 40);
1646
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
639
1647
  try {
640
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
641
- const fromDate = dateRange?.start;
642
- const toDate = dateRange?.end;
643
- const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
644
- const orderByStatement = `ORDER BY [seq_id] DESC`;
645
- let messages = [];
646
- if (selectBy?.include?.length) {
647
- const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
648
- if (includeMessages) messages.push(...includeMessages);
649
- }
650
- const perPage = perPageInput !== void 0 ? perPageInput : storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
651
- const currentOffset = page * perPage;
652
- const conditions = ["[thread_id] = @threadId"];
653
- const request = this.pool.request();
654
- request.input("threadId", threadId);
655
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
656
- conditions.push("[createdAt] >= @fromDate");
657
- request.input("fromDate", fromDate.toISOString());
658
- }
659
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
660
- conditions.push("[createdAt] <= @toDate");
661
- request.input("toDate", toDate.toISOString());
662
- }
663
- const whereClause = `WHERE ${conditions.join(" AND ")}`;
664
- const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
665
- const countResult = await request.query(countQuery);
1648
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
1649
+ const orderByStatement = `ORDER BY [${field}] ${direction}, [seq_id] ${direction}`;
1650
+ const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
1651
+ const baseQuery = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId FROM ${tableName}`;
1652
+ const filters = {
1653
+ thread_id: threadIds.length === 1 ? threadIds[0] : { $in: threadIds },
1654
+ ...resourceId ? { resourceId } : {},
1655
+ ...buildDateRangeFilter(filter?.dateRange, "createdAt")
1656
+ };
1657
+ const { sql: actualWhereClause = "", params: whereParams } = prepareWhereClause(
1658
+ filters);
1659
+ const bindWhereParams = (req) => {
1660
+ Object.entries(whereParams).forEach(([paramName, paramValue]) => req.input(paramName, paramValue));
1661
+ };
1662
+ const countRequest = this.pool.request();
1663
+ bindWhereParams(countRequest);
1664
+ const countResult = await countRequest.query(`SELECT COUNT(*) as total FROM ${tableName}${actualWhereClause}`);
666
1665
  const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
667
- if (total === 0 && messages.length > 0) {
668
- const parsedIncluded = this._parseAndFormatMessages(messages, format);
1666
+ const fetchBaseMessages = async () => {
1667
+ const request = this.pool.request();
1668
+ bindWhereParams(request);
1669
+ if (perPageInput === false) {
1670
+ const result2 = await request.query(`${baseQuery}${actualWhereClause} ${orderByStatement}`);
1671
+ return result2.recordset || [];
1672
+ }
1673
+ request.input("offset", offset);
1674
+ request.input("limit", perPage > 2147483647 ? sql__default.default.BigInt : sql__default.default.Int, perPage);
1675
+ const result = await request.query(
1676
+ `${baseQuery}${actualWhereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
1677
+ );
1678
+ return result.recordset || [];
1679
+ };
1680
+ const baseRows = perPage === 0 ? [] : await fetchBaseMessages();
1681
+ const messages = [...baseRows];
1682
+ const seqById = /* @__PURE__ */ new Map();
1683
+ messages.forEach((msg) => {
1684
+ if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
1685
+ });
1686
+ if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
669
1687
  return {
670
- messages: parsedIncluded,
671
- total: parsedIncluded.length,
1688
+ messages: [],
1689
+ total: 0,
672
1690
  page,
673
- perPage,
1691
+ perPage: perPageForResponse,
674
1692
  hasMore: false
675
1693
  };
676
1694
  }
677
- const excludeIds = messages.map((m) => m.id);
678
- if (excludeIds.length > 0) {
679
- const excludeParams = excludeIds.map((_, idx) => `@id${idx}`);
680
- conditions.push(`id NOT IN (${excludeParams.join(", ")})`);
681
- excludeIds.forEach((id, idx) => request.input(`id${idx}`, id));
682
- }
683
- const finalWhereClause = `WHERE ${conditions.join(" AND ")}`;
684
- const dataQuery = `${selectStatement} FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} ${finalWhereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
685
- request.input("offset", currentOffset);
686
- request.input("limit", perPage);
687
- const rowsResult = await request.query(dataQuery);
688
- const rows = rowsResult.recordset || [];
689
- rows.sort((a, b) => a.seq_id - b.seq_id);
690
- messages.push(...rows);
691
- const parsed = this._parseAndFormatMessages(messages, format);
1695
+ if (include?.length) {
1696
+ const messageIds = new Set(messages.map((m) => m.id));
1697
+ const includeMessages = await this._getIncludedMessages({ include });
1698
+ includeMessages?.forEach((msg) => {
1699
+ if (!messageIds.has(msg.id)) {
1700
+ messages.push(msg);
1701
+ messageIds.add(msg.id);
1702
+ if (typeof msg.seq_id === "number") seqById.set(msg.id, msg.seq_id);
1703
+ }
1704
+ });
1705
+ }
1706
+ const parsed = this._parseAndFormatMessages(messages, "v2");
1707
+ const mult = direction === "ASC" ? 1 : -1;
1708
+ const finalMessages = parsed.sort((a, b) => {
1709
+ const aVal = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
1710
+ const bVal = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
1711
+ if (aVal == null || bVal == null) {
1712
+ return aVal == null && bVal == null ? a.id.localeCompare(b.id) : aVal == null ? 1 : -1;
1713
+ }
1714
+ const diff = (typeof aVal === "number" && typeof bVal === "number" ? aVal - bVal : String(aVal).localeCompare(String(bVal))) * mult;
1715
+ if (diff !== 0) return diff;
1716
+ const seqA = seqById.get(a.id);
1717
+ const seqB = seqById.get(b.id);
1718
+ return seqA != null && seqB != null ? (seqA - seqB) * mult : a.id.localeCompare(b.id);
1719
+ });
1720
+ const threadIdSet = new Set(threadIds);
1721
+ const returnedThreadMessageCount = finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).length;
1722
+ const hasMore = perPageInput !== false && returnedThreadMessageCount < total && offset + perPage < total;
692
1723
  return {
693
- messages: parsed,
694
- total: total + excludeIds.length,
1724
+ messages: finalMessages,
1725
+ total,
695
1726
  page,
696
- perPage,
697
- hasMore: currentOffset + rows.length < total
1727
+ perPage: perPageForResponse,
1728
+ hasMore
698
1729
  };
699
1730
  } catch (error$1) {
700
1731
  const mastraError = new error.MastraError(
701
1732
  {
702
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_MESSAGES_PAGINATED_FAILED",
1733
+ id: storage.createStorageErrorId("MSSQL", "LIST_MESSAGES", "FAILED"),
703
1734
  domain: error.ErrorDomain.STORAGE,
704
1735
  category: error.ErrorCategory.THIRD_PARTY,
705
1736
  details: {
706
- threadId,
707
- resourceId: resourceId ?? "",
708
- page
1737
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
1738
+ resourceId: resourceId ?? ""
709
1739
  }
710
1740
  },
711
1741
  error$1
712
1742
  );
713
1743
  this.logger?.error?.(mastraError.toString());
714
- this.logger?.trackException(mastraError);
715
- return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
1744
+ this.logger?.trackException?.(mastraError);
1745
+ return {
1746
+ messages: [],
1747
+ total: 0,
1748
+ page,
1749
+ perPage: perPageForResponse,
1750
+ hasMore: false
1751
+ };
716
1752
  }
717
1753
  }
718
- async saveMessages({
719
- messages,
720
- format
721
- }) {
722
- if (messages.length === 0) return messages;
1754
+ async saveMessages({ messages }) {
1755
+ if (messages.length === 0) return { messages: [] };
723
1756
  const threadId = messages[0]?.threadId;
724
1757
  if (!threadId) {
725
1758
  throw new error.MastraError({
726
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
1759
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "INVALID_THREAD_ID"),
727
1760
  domain: error.ErrorDomain.STORAGE,
728
1761
  category: error.ErrorCategory.THIRD_PARTY,
729
1762
  text: `Thread ID is required`
@@ -732,15 +1765,15 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
732
1765
  const thread = await this.getThreadById({ threadId });
733
1766
  if (!thread) {
734
1767
  throw new error.MastraError({
735
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
1768
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "THREAD_NOT_FOUND"),
736
1769
  domain: error.ErrorDomain.STORAGE,
737
1770
  category: error.ErrorCategory.THIRD_PARTY,
738
1771
  text: `Thread ${threadId} not found`,
739
1772
  details: { threadId }
740
1773
  });
741
1774
  }
742
- const tableMessages = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
743
- const tableThreads = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1775
+ const tableMessages = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
1776
+ const tableThreads = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
744
1777
  try {
745
1778
  const transaction = this.pool.transaction();
746
1779
  await transaction.begin();
@@ -763,7 +1796,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
763
1796
  "content",
764
1797
  typeof message.content === "string" ? message.content : JSON.stringify(message.content)
765
1798
  );
766
- request.input("createdAt", sql2__default.default.DateTime2, message.createdAt);
1799
+ request.input("createdAt", sql__default.default.DateTime2, message.createdAt);
767
1800
  request.input("role", message.role);
768
1801
  request.input("type", message.type || "v2");
769
1802
  request.input("resourceId", message.resourceId);
@@ -782,7 +1815,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
782
1815
  await request.query(mergeSql);
783
1816
  }
784
1817
  const threadReq = transaction.request();
785
- threadReq.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
1818
+ threadReq.input("updatedAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
786
1819
  threadReq.input("id", threadId);
787
1820
  await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
788
1821
  await transaction.commit();
@@ -801,12 +1834,11 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
801
1834
  return message;
802
1835
  });
803
1836
  const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
804
- if (format === "v2") return list.get.all.v2();
805
- return list.get.all.v1();
1837
+ return { messages: list.get.all.db() };
806
1838
  } catch (error$1) {
807
1839
  throw new error.MastraError(
808
1840
  {
809
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_MESSAGES_FAILED",
1841
+ id: storage.createStorageErrorId("MSSQL", "SAVE_MESSAGES", "FAILED"),
810
1842
  domain: error.ErrorDomain.STORAGE,
811
1843
  category: error.ErrorCategory.THIRD_PARTY,
812
1844
  details: { threadId }
@@ -823,7 +1855,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
823
1855
  }
824
1856
  const messageIds = messages.map((m) => m.id);
825
1857
  const idParams = messageIds.map((_, i) => `@id${i}`).join(", ");
826
- let selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}`;
1858
+ let selectQuery = `SELECT id, content, role, type, createdAt, thread_id AS threadId, resourceId FROM ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) })}`;
827
1859
  if (idParams.length > 0) {
828
1860
  selectQuery += ` WHERE id IN (${idParams})`;
829
1861
  } else {
@@ -880,7 +1912,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
880
1912
  }
881
1913
  }
882
1914
  if (setClauses.length > 0) {
883
- const updateSql = `UPDATE ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} SET ${setClauses.join(", ")} WHERE id = @id`;
1915
+ const updateSql = `UPDATE ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) })} SET ${setClauses.join(", ")} WHERE id = @id`;
884
1916
  await req.query(updateSql);
885
1917
  }
886
1918
  }
@@ -889,7 +1921,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
889
1921
  const threadReq = transaction.request();
890
1922
  Array.from(threadIdsToUpdate).forEach((tid, i) => threadReq.input(`tid${i}`, tid));
891
1923
  threadReq.input("updatedAt", (/* @__PURE__ */ new Date()).toISOString());
892
- const threadSql = `UPDATE ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} SET updatedAt = @updatedAt WHERE id IN (${threadIdParams})`;
1924
+ const threadSql = `UPDATE ${getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) })} SET updatedAt = @updatedAt WHERE id IN (${threadIdParams})`;
893
1925
  await threadReq.query(threadSql);
894
1926
  }
895
1927
  await transaction.commit();
@@ -897,7 +1929,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
897
1929
  await transaction.rollback();
898
1930
  throw new error.MastraError(
899
1931
  {
900
- id: "MASTRA_STORAGE_MSSQL_UPDATE_MESSAGES_FAILED",
1932
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_MESSAGES", "FAILED"),
901
1933
  domain: error.ErrorDomain.STORAGE,
902
1934
  category: error.ErrorCategory.THIRD_PARTY
903
1935
  },
@@ -922,8 +1954,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
922
1954
  return;
923
1955
  }
924
1956
  try {
925
- const messageTableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
926
- const threadTableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1957
+ const messageTableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.schema) });
1958
+ const threadTableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.schema) });
927
1959
  const placeholders = messageIds.map((_, idx) => `@p${idx + 1}`).join(",");
928
1960
  const request = this.pool.request();
929
1961
  messageIds.forEach((id, idx) => {
@@ -959,7 +1991,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
959
1991
  } catch (error$1) {
960
1992
  throw new error.MastraError(
961
1993
  {
962
- id: "MASTRA_STORAGE_MSSQL_STORE_DELETE_MESSAGES_FAILED",
1994
+ id: storage.createStorageErrorId("MSSQL", "DELETE_MESSAGES", "FAILED"),
963
1995
  domain: error.ErrorDomain.STORAGE,
964
1996
  category: error.ErrorCategory.THIRD_PARTY,
965
1997
  details: { messageIds: messageIds.join(", ") }
@@ -969,7 +2001,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
969
2001
  }
970
2002
  }
971
2003
  async getResourceById({ resourceId }) {
972
- const tableName = getTableName({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName(this.schema) });
2004
+ const tableName = getTableName2({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName2(this.schema) });
973
2005
  try {
974
2006
  const req = this.pool.request();
975
2007
  req.input("resourceId", resourceId);
@@ -978,14 +2010,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
978
2010
  return null;
979
2011
  }
980
2012
  return {
981
- ...result,
982
- workingMemory: typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
2013
+ id: result.id,
2014
+ createdAt: result.createdAt,
2015
+ updatedAt: result.updatedAt,
2016
+ workingMemory: result.workingMemory,
983
2017
  metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
984
2018
  };
985
2019
  } catch (error$1) {
986
2020
  const mastraError = new error.MastraError(
987
2021
  {
988
- id: "MASTRA_STORAGE_MSSQL_GET_RESOURCE_BY_ID_FAILED",
2022
+ id: storage.createStorageErrorId("MSSQL", "GET_RESOURCE_BY_ID", "FAILED"),
989
2023
  domain: error.ErrorDomain.STORAGE,
990
2024
  category: error.ErrorCategory.THIRD_PARTY,
991
2025
  details: { resourceId }
@@ -993,16 +2027,16 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
993
2027
  error$1
994
2028
  );
995
2029
  this.logger?.error?.(mastraError.toString());
996
- this.logger?.trackException(mastraError);
2030
+ this.logger?.trackException?.(mastraError);
997
2031
  throw mastraError;
998
2032
  }
999
2033
  }
1000
2034
  async saveResource({ resource }) {
1001
- await this.operations.insert({
2035
+ await this.db.insert({
1002
2036
  tableName: storage.TABLE_RESOURCES,
1003
2037
  record: {
1004
2038
  ...resource,
1005
- metadata: JSON.stringify(resource.metadata)
2039
+ metadata: resource.metadata
1006
2040
  }
1007
2041
  });
1008
2042
  return resource;
@@ -1033,7 +2067,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1033
2067
  },
1034
2068
  updatedAt: /* @__PURE__ */ new Date()
1035
2069
  };
1036
- const tableName = getTableName({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName(this.schema) });
2070
+ const tableName = getTableName2({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName2(this.schema) });
1037
2071
  const updates = [];
1038
2072
  const req = this.pool.request();
1039
2073
  if (workingMemory !== void 0) {
@@ -1052,7 +2086,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1052
2086
  } catch (error$1) {
1053
2087
  const mastraError = new error.MastraError(
1054
2088
  {
1055
- id: "MASTRA_STORAGE_MSSQL_UPDATE_RESOURCE_FAILED",
2089
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_RESOURCE", "FAILED"),
1056
2090
  domain: error.ErrorDomain.STORAGE,
1057
2091
  category: error.ErrorCategory.THIRD_PARTY,
1058
2092
  details: { resourceId }
@@ -1060,357 +2094,650 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
1060
2094
  error$1
1061
2095
  );
1062
2096
  this.logger?.error?.(mastraError.toString());
1063
- this.logger?.trackException(mastraError);
2097
+ this.logger?.trackException?.(mastraError);
1064
2098
  throw mastraError;
1065
2099
  }
1066
2100
  }
1067
2101
  };
1068
- var StoreOperationsMSSQL = class extends storage.StoreOperations {
2102
+ var ObservabilityMSSQL = class _ObservabilityMSSQL extends storage.ObservabilityStorage {
1069
2103
  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 }) {
2104
+ db;
2105
+ schema;
2106
+ needsConnect;
2107
+ skipDefaultIndexes;
2108
+ indexes;
2109
+ /** Tables managed by this domain */
2110
+ static MANAGED_TABLES = [storage.TABLE_SPANS];
2111
+ constructor(config) {
1098
2112
  super();
2113
+ const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
1099
2114
  this.pool = pool;
1100
- this.schemaName = schemaName;
2115
+ this.schema = schemaName;
2116
+ this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
2117
+ this.needsConnect = needsConnect;
2118
+ this.skipDefaultIndexes = skipDefaultIndexes;
2119
+ this.indexes = indexes?.filter((idx) => _ObservabilityMSSQL.MANAGED_TABLES.includes(idx.table));
1101
2120
  }
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;
2121
+ async init() {
2122
+ if (this.needsConnect) {
2123
+ await this.pool.connect();
2124
+ this.needsConnect = false;
2125
+ }
2126
+ await this.db.createTable({ tableName: storage.TABLE_SPANS, schema: storage.SPAN_SCHEMA });
2127
+ await this.createDefaultIndexes();
2128
+ await this.createCustomIndexes();
1113
2129
  }
1114
- async setupSchema() {
1115
- if (!this.schemaName || this.schemaSetupComplete) {
2130
+ /**
2131
+ * Returns default index definitions for the observability domain tables.
2132
+ */
2133
+ getDefaultIndexDefinitions() {
2134
+ const schemaPrefix = this.schema ? `${this.schema}_` : "";
2135
+ return [
2136
+ {
2137
+ name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
2138
+ table: storage.TABLE_SPANS,
2139
+ columns: ["traceId", "startedAt DESC"]
2140
+ },
2141
+ {
2142
+ name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
2143
+ table: storage.TABLE_SPANS,
2144
+ columns: ["parentSpanId", "startedAt DESC"]
2145
+ },
2146
+ {
2147
+ name: `${schemaPrefix}mastra_ai_spans_name_idx`,
2148
+ table: storage.TABLE_SPANS,
2149
+ columns: ["name"]
2150
+ },
2151
+ {
2152
+ name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
2153
+ table: storage.TABLE_SPANS,
2154
+ columns: ["spanType", "startedAt DESC"]
2155
+ },
2156
+ // Root spans filtered index - every listTraces query filters parentSpanId IS NULL
2157
+ {
2158
+ name: `${schemaPrefix}mastra_ai_spans_root_spans_idx`,
2159
+ table: storage.TABLE_SPANS,
2160
+ columns: ["startedAt DESC"],
2161
+ where: "[parentSpanId] IS NULL"
2162
+ },
2163
+ // Entity identification indexes - common filtering patterns
2164
+ {
2165
+ name: `${schemaPrefix}mastra_ai_spans_entitytype_entityid_idx`,
2166
+ table: storage.TABLE_SPANS,
2167
+ columns: ["entityType", "entityId"]
2168
+ },
2169
+ {
2170
+ name: `${schemaPrefix}mastra_ai_spans_entitytype_entityname_idx`,
2171
+ table: storage.TABLE_SPANS,
2172
+ columns: ["entityType", "entityName"]
2173
+ },
2174
+ // Multi-tenant filtering - organizationId + userId
2175
+ {
2176
+ name: `${schemaPrefix}mastra_ai_spans_orgid_userid_idx`,
2177
+ table: storage.TABLE_SPANS,
2178
+ columns: ["organizationId", "userId"]
2179
+ }
2180
+ // Note: MSSQL doesn't support GIN indexes for JSONB/array containment queries
2181
+ // Metadata and tags filtering will use full table scans on NVARCHAR(MAX) columns
2182
+ ];
2183
+ }
2184
+ /**
2185
+ * Creates default indexes for optimal query performance.
2186
+ */
2187
+ async createDefaultIndexes() {
2188
+ if (this.skipDefaultIndexes) {
1116
2189
  return;
1117
2190
  }
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
- }
1137
- }
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
- })();
2191
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
2192
+ try {
2193
+ await this.db.createIndex(indexDef);
2194
+ } catch (error) {
2195
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
2196
+ }
1148
2197
  }
1149
- await this.setupSchemaPromise;
1150
2198
  }
1151
- async insert({ tableName, record }) {
2199
+ /**
2200
+ * Creates custom user-defined indexes for this domain's tables.
2201
+ */
2202
+ async createCustomIndexes() {
2203
+ if (!this.indexes || this.indexes.length === 0) {
2204
+ return;
2205
+ }
2206
+ for (const indexDef of this.indexes) {
2207
+ try {
2208
+ await this.db.createIndex(indexDef);
2209
+ } catch (error) {
2210
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
2211
+ }
2212
+ }
2213
+ }
2214
+ async dangerouslyClearAll() {
2215
+ await this.db.clearTable({ tableName: storage.TABLE_SPANS });
2216
+ }
2217
+ get tracingStrategy() {
2218
+ return {
2219
+ preferred: "batch-with-updates",
2220
+ supported: ["batch-with-updates", "insert-only"]
2221
+ };
2222
+ }
2223
+ async createSpan(args) {
2224
+ const { span } = args;
1152
2225
  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
- }
1166
- });
1167
- await request.query(insertSql);
2226
+ const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
2227
+ const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
2228
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2229
+ const record = {
2230
+ ...span,
2231
+ startedAt,
2232
+ endedAt,
2233
+ createdAt: now,
2234
+ updatedAt: now
2235
+ };
2236
+ return this.db.insert({ tableName: storage.TABLE_SPANS, record });
1168
2237
  } catch (error$1) {
1169
2238
  throw new error.MastraError(
1170
2239
  {
1171
- id: "MASTRA_STORAGE_MSSQL_STORE_INSERT_FAILED",
2240
+ id: storage.createStorageErrorId("MSSQL", "CREATE_SPAN", "FAILED"),
1172
2241
  domain: error.ErrorDomain.STORAGE,
1173
- category: error.ErrorCategory.THIRD_PARTY,
2242
+ category: error.ErrorCategory.USER,
1174
2243
  details: {
1175
- tableName
2244
+ spanId: span.spanId,
2245
+ traceId: span.traceId,
2246
+ spanType: span.spanType,
2247
+ name: span.name
1176
2248
  }
1177
2249
  },
1178
2250
  error$1
1179
2251
  );
1180
2252
  }
1181
2253
  }
1182
- async clearTable({ tableName }) {
1183
- const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
2254
+ async getTrace(args) {
2255
+ const { traceId } = args;
1184
2256
  try {
1185
- try {
1186
- await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
1187
- } catch (truncateError) {
1188
- if (truncateError.message && truncateError.message.includes("foreign key")) {
1189
- await this.pool.request().query(`DELETE FROM ${fullTableName}`);
1190
- } else {
1191
- throw truncateError;
1192
- }
2257
+ const tableName = getTableName2({
2258
+ indexName: storage.TABLE_SPANS,
2259
+ schemaName: getSchemaName2(this.schema)
2260
+ });
2261
+ const request = this.pool.request();
2262
+ request.input("traceId", traceId);
2263
+ const result = await request.query(
2264
+ `SELECT
2265
+ [traceId], [spanId], [parentSpanId], [name],
2266
+ [entityType], [entityId], [entityName],
2267
+ [userId], [organizationId], [resourceId],
2268
+ [runId], [sessionId], [threadId], [requestId],
2269
+ [environment], [source], [serviceName], [scope],
2270
+ [spanType], [attributes], [metadata], [tags], [links],
2271
+ [input], [output], [error], [isEvent],
2272
+ [startedAt], [endedAt], [createdAt], [updatedAt]
2273
+ FROM ${tableName}
2274
+ WHERE [traceId] = @traceId
2275
+ ORDER BY [startedAt] ASC`
2276
+ );
2277
+ if (!result.recordset || result.recordset.length === 0) {
2278
+ return null;
1193
2279
  }
2280
+ return {
2281
+ traceId,
2282
+ spans: result.recordset.map(
2283
+ (span) => transformFromSqlRow({
2284
+ tableName: storage.TABLE_SPANS,
2285
+ sqlRow: span
2286
+ })
2287
+ )
2288
+ };
1194
2289
  } catch (error$1) {
1195
2290
  throw new error.MastraError(
1196
2291
  {
1197
- id: "MASTRA_STORAGE_MSSQL_STORE_CLEAR_TABLE_FAILED",
2292
+ id: storage.createStorageErrorId("MSSQL", "GET_TRACE", "FAILED"),
1198
2293
  domain: error.ErrorDomain.STORAGE,
1199
- category: error.ErrorCategory.THIRD_PARTY,
2294
+ category: error.ErrorCategory.USER,
1200
2295
  details: {
1201
- tableName
2296
+ traceId
1202
2297
  }
1203
2298
  },
1204
2299
  error$1
1205
2300
  );
1206
2301
  }
1207
2302
  }
1208
- getDefaultValue(type) {
1209
- switch (type) {
1210
- case "timestamp":
1211
- return "DEFAULT SYSDATETIMEOFFSET()";
1212
- case "jsonb":
1213
- return "DEFAULT N'{}'";
1214
- default:
1215
- return super.getDefaultValue(type);
2303
+ async getSpan(args) {
2304
+ const { traceId, spanId } = args;
2305
+ try {
2306
+ const tableName = getTableName2({
2307
+ indexName: storage.TABLE_SPANS,
2308
+ schemaName: getSchemaName2(this.schema)
2309
+ });
2310
+ const request = this.pool.request();
2311
+ request.input("traceId", traceId);
2312
+ request.input("spanId", spanId);
2313
+ const result = await request.query(
2314
+ `SELECT
2315
+ [traceId], [spanId], [parentSpanId], [name],
2316
+ [entityType], [entityId], [entityName],
2317
+ [userId], [organizationId], [resourceId],
2318
+ [runId], [sessionId], [threadId], [requestId],
2319
+ [environment], [source], [serviceName], [scope],
2320
+ [spanType], [attributes], [metadata], [tags], [links],
2321
+ [input], [output], [error], [isEvent],
2322
+ [startedAt], [endedAt], [createdAt], [updatedAt]
2323
+ FROM ${tableName}
2324
+ WHERE [traceId] = @traceId AND [spanId] = @spanId`
2325
+ );
2326
+ if (!result.recordset || result.recordset.length === 0) {
2327
+ return null;
2328
+ }
2329
+ return {
2330
+ span: transformFromSqlRow({
2331
+ tableName: storage.TABLE_SPANS,
2332
+ sqlRow: result.recordset[0]
2333
+ })
2334
+ };
2335
+ } catch (error$1) {
2336
+ throw new error.MastraError(
2337
+ {
2338
+ id: storage.createStorageErrorId("MSSQL", "GET_SPAN", "FAILED"),
2339
+ domain: error.ErrorDomain.STORAGE,
2340
+ category: error.ErrorCategory.USER,
2341
+ details: { traceId, spanId }
2342
+ },
2343
+ error$1
2344
+ );
1216
2345
  }
1217
2346
  }
1218
- async createTable({
1219
- tableName,
1220
- schema
1221
- }) {
2347
+ async getRootSpan(args) {
2348
+ const { traceId } = args;
1222
2349
  try {
1223
- const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
1224
- const columns = Object.entries(schema).map(([name, def]) => {
1225
- const parsedName = utils.parseSqlIdentifier(name, "column name");
1226
- const constraints = [];
1227
- if (def.primaryKey) constraints.push("PRIMARY KEY");
1228
- if (!def.nullable) constraints.push("NOT NULL");
1229
- const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
1230
- return `[${parsedName}] ${this.getSqlType(def.type, isIndexed)} ${constraints.join(" ")}`.trim();
1231
- }).join(",\n");
1232
- if (this.schemaName) {
1233
- await this.setupSchema();
1234
- }
1235
- const checkTableRequest = this.pool.request();
1236
- checkTableRequest.input(
1237
- "tableName",
1238
- getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) }).replace(/[[\]]/g, "").split(".").pop()
2350
+ const tableName = getTableName2({
2351
+ indexName: storage.TABLE_SPANS,
2352
+ schemaName: getSchemaName2(this.schema)
2353
+ });
2354
+ const request = this.pool.request();
2355
+ request.input("traceId", traceId);
2356
+ const result = await request.query(
2357
+ `SELECT
2358
+ [traceId], [spanId], [parentSpanId], [name],
2359
+ [entityType], [entityId], [entityName],
2360
+ [userId], [organizationId], [resourceId],
2361
+ [runId], [sessionId], [threadId], [requestId],
2362
+ [environment], [source], [serviceName], [scope],
2363
+ [spanType], [attributes], [metadata], [tags], [links],
2364
+ [input], [output], [error], [isEvent],
2365
+ [startedAt], [endedAt], [createdAt], [updatedAt]
2366
+ FROM ${tableName}
2367
+ WHERE [traceId] = @traceId AND [parentSpanId] IS NULL`
1239
2368
  );
1240
- const checkTableSql = `SELECT 1 AS found FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName`;
1241
- checkTableRequest.input("schema", this.schemaName || "dbo");
1242
- const checkTableResult = await checkTableRequest.query(checkTableSql);
1243
- const tableExists = Array.isArray(checkTableResult.recordset) && checkTableResult.recordset.length > 0;
1244
- if (!tableExists) {
1245
- const createSql = `CREATE TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (
1246
- ${columns}
1247
- )`;
1248
- await this.pool.request().query(createSql);
2369
+ if (!result.recordset || result.recordset.length === 0) {
2370
+ return null;
1249
2371
  }
1250
- const columnCheckSql = `
1251
- SELECT 1 AS found
1252
- FROM INFORMATION_SCHEMA.COLUMNS
1253
- WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName AND COLUMN_NAME = 'seq_id'
1254
- `;
1255
- const checkColumnRequest = this.pool.request();
1256
- checkColumnRequest.input("schema", this.schemaName || "dbo");
1257
- checkColumnRequest.input(
1258
- "tableName",
1259
- getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) }).replace(/[[\]]/g, "").split(".").pop()
2372
+ return {
2373
+ span: transformFromSqlRow({
2374
+ tableName: storage.TABLE_SPANS,
2375
+ sqlRow: result.recordset[0]
2376
+ })
2377
+ };
2378
+ } catch (error$1) {
2379
+ throw new error.MastraError(
2380
+ {
2381
+ id: storage.createStorageErrorId("MSSQL", "GET_ROOT_SPAN", "FAILED"),
2382
+ domain: error.ErrorDomain.STORAGE,
2383
+ category: error.ErrorCategory.USER,
2384
+ details: { traceId }
2385
+ },
2386
+ error$1
1260
2387
  );
1261
- const columnResult = await checkColumnRequest.query(columnCheckSql);
1262
- const columnExists = Array.isArray(columnResult.recordset) && columnResult.recordset.length > 0;
1263
- if (!columnExists) {
1264
- const alterSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD seq_id BIGINT IDENTITY(1,1)`;
1265
- await this.pool.request().query(alterSql);
2388
+ }
2389
+ }
2390
+ async updateSpan(args) {
2391
+ const { traceId, spanId, updates } = args;
2392
+ try {
2393
+ const data = { ...updates };
2394
+ if (data.endedAt instanceof Date) {
2395
+ data.endedAt = data.endedAt.toISOString();
1266
2396
  }
1267
- if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
1268
- const constraintName = "mastra_workflow_snapshot_workflow_name_run_id_key";
1269
- const checkConstraintSql = `SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`;
1270
- const checkConstraintRequest = this.pool.request();
1271
- checkConstraintRequest.input("constraintName", constraintName);
1272
- const constraintResult = await checkConstraintRequest.query(checkConstraintSql);
1273
- const constraintExists = Array.isArray(constraintResult.recordset) && constraintResult.recordset.length > 0;
1274
- if (!constraintExists) {
1275
- const addConstraintSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT ${constraintName} UNIQUE ([workflow_name], [run_id])`;
1276
- await this.pool.request().query(addConstraintSql);
2397
+ if (data.startedAt instanceof Date) {
2398
+ data.startedAt = data.startedAt.toISOString();
2399
+ }
2400
+ data.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2401
+ await this.db.update({
2402
+ tableName: storage.TABLE_SPANS,
2403
+ keys: { spanId, traceId },
2404
+ data
2405
+ });
2406
+ } catch (error$1) {
2407
+ throw new error.MastraError(
2408
+ {
2409
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_SPAN", "FAILED"),
2410
+ domain: error.ErrorDomain.STORAGE,
2411
+ category: error.ErrorCategory.USER,
2412
+ details: {
2413
+ spanId,
2414
+ traceId
2415
+ }
2416
+ },
2417
+ error$1
2418
+ );
2419
+ }
2420
+ }
2421
+ async listTraces(args) {
2422
+ const { filters, pagination, orderBy } = storage.listTracesArgsSchema.parse(args);
2423
+ const { page, perPage } = pagination;
2424
+ const tableName = getTableName2({
2425
+ indexName: storage.TABLE_SPANS,
2426
+ schemaName: getSchemaName2(this.schema)
2427
+ });
2428
+ try {
2429
+ const conditions = ["r.[parentSpanId] IS NULL"];
2430
+ const params = {};
2431
+ let paramIndex = 1;
2432
+ if (filters) {
2433
+ if (filters.startedAt?.start) {
2434
+ const param = `p${paramIndex++}`;
2435
+ conditions.push(`r.[startedAt] >= @${param}`);
2436
+ params[param] = filters.startedAt.start.toISOString();
2437
+ }
2438
+ if (filters.startedAt?.end) {
2439
+ const param = `p${paramIndex++}`;
2440
+ conditions.push(`r.[startedAt] <= @${param}`);
2441
+ params[param] = filters.startedAt.end.toISOString();
2442
+ }
2443
+ if (filters.endedAt?.start) {
2444
+ const param = `p${paramIndex++}`;
2445
+ conditions.push(`r.[endedAt] >= @${param}`);
2446
+ params[param] = filters.endedAt.start.toISOString();
2447
+ }
2448
+ if (filters.endedAt?.end) {
2449
+ const param = `p${paramIndex++}`;
2450
+ conditions.push(`r.[endedAt] <= @${param}`);
2451
+ params[param] = filters.endedAt.end.toISOString();
2452
+ }
2453
+ if (filters.spanType !== void 0) {
2454
+ const param = `p${paramIndex++}`;
2455
+ conditions.push(`r.[spanType] = @${param}`);
2456
+ params[param] = filters.spanType;
2457
+ }
2458
+ if (filters.entityType !== void 0) {
2459
+ const param = `p${paramIndex++}`;
2460
+ conditions.push(`r.[entityType] = @${param}`);
2461
+ params[param] = filters.entityType;
2462
+ }
2463
+ if (filters.entityId !== void 0) {
2464
+ const param = `p${paramIndex++}`;
2465
+ conditions.push(`r.[entityId] = @${param}`);
2466
+ params[param] = filters.entityId;
2467
+ }
2468
+ if (filters.entityName !== void 0) {
2469
+ const param = `p${paramIndex++}`;
2470
+ conditions.push(`r.[entityName] = @${param}`);
2471
+ params[param] = filters.entityName;
2472
+ }
2473
+ if (filters.userId !== void 0) {
2474
+ const param = `p${paramIndex++}`;
2475
+ conditions.push(`r.[userId] = @${param}`);
2476
+ params[param] = filters.userId;
2477
+ }
2478
+ if (filters.organizationId !== void 0) {
2479
+ const param = `p${paramIndex++}`;
2480
+ conditions.push(`r.[organizationId] = @${param}`);
2481
+ params[param] = filters.organizationId;
2482
+ }
2483
+ if (filters.resourceId !== void 0) {
2484
+ const param = `p${paramIndex++}`;
2485
+ conditions.push(`r.[resourceId] = @${param}`);
2486
+ params[param] = filters.resourceId;
2487
+ }
2488
+ if (filters.runId !== void 0) {
2489
+ const param = `p${paramIndex++}`;
2490
+ conditions.push(`r.[runId] = @${param}`);
2491
+ params[param] = filters.runId;
2492
+ }
2493
+ if (filters.sessionId !== void 0) {
2494
+ const param = `p${paramIndex++}`;
2495
+ conditions.push(`r.[sessionId] = @${param}`);
2496
+ params[param] = filters.sessionId;
2497
+ }
2498
+ if (filters.threadId !== void 0) {
2499
+ const param = `p${paramIndex++}`;
2500
+ conditions.push(`r.[threadId] = @${param}`);
2501
+ params[param] = filters.threadId;
2502
+ }
2503
+ if (filters.requestId !== void 0) {
2504
+ const param = `p${paramIndex++}`;
2505
+ conditions.push(`r.[requestId] = @${param}`);
2506
+ params[param] = filters.requestId;
2507
+ }
2508
+ if (filters.environment !== void 0) {
2509
+ const param = `p${paramIndex++}`;
2510
+ conditions.push(`r.[environment] = @${param}`);
2511
+ params[param] = filters.environment;
1277
2512
  }
1278
- }
1279
- } catch (error$1) {
1280
- throw new error.MastraError(
1281
- {
1282
- id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_TABLE_FAILED",
1283
- domain: error.ErrorDomain.STORAGE,
1284
- category: error.ErrorCategory.THIRD_PARTY,
1285
- details: {
1286
- tableName
2513
+ if (filters.source !== void 0) {
2514
+ const param = `p${paramIndex++}`;
2515
+ conditions.push(`r.[source] = @${param}`);
2516
+ params[param] = filters.source;
2517
+ }
2518
+ if (filters.serviceName !== void 0) {
2519
+ const param = `p${paramIndex++}`;
2520
+ conditions.push(`r.[serviceName] = @${param}`);
2521
+ params[param] = filters.serviceName;
2522
+ }
2523
+ if (filters.scope != null) {
2524
+ for (const [key, value] of Object.entries(filters.scope)) {
2525
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
2526
+ throw new error.MastraError({
2527
+ id: storage.createStorageErrorId("MSSQL", "LIST_TRACES", "INVALID_FILTER_KEY"),
2528
+ domain: error.ErrorDomain.STORAGE,
2529
+ category: error.ErrorCategory.USER,
2530
+ details: { key }
2531
+ });
2532
+ }
2533
+ const param = `p${paramIndex++}`;
2534
+ conditions.push(`JSON_VALUE(r.[scope], '$.${key}') = @${param}`);
2535
+ params[param] = typeof value === "string" ? value : JSON.stringify(value);
1287
2536
  }
1288
- },
1289
- error$1
1290
- );
1291
- }
1292
- }
1293
- /**
1294
- * Alters table schema to add columns if they don't exist
1295
- * @param tableName Name of the table
1296
- * @param schema Schema of the table
1297
- * @param ifNotExists Array of column names to add if they don't exist
1298
- */
1299
- async alterTable({
1300
- tableName,
1301
- schema,
1302
- ifNotExists
1303
- }) {
1304
- const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
1305
- try {
1306
- for (const columnName of ifNotExists) {
1307
- if (schema[columnName]) {
1308
- const columnCheckRequest = this.pool.request();
1309
- columnCheckRequest.input("tableName", fullTableName.replace(/[[\]]/g, "").split(".").pop());
1310
- columnCheckRequest.input("columnName", columnName);
1311
- columnCheckRequest.input("schema", this.schemaName || "dbo");
1312
- const checkSql = `SELECT 1 AS found FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @tableName AND COLUMN_NAME = @columnName`;
1313
- const checkResult = await columnCheckRequest.query(checkSql);
1314
- const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
1315
- if (!columnExists) {
1316
- const columnDef = schema[columnName];
1317
- const sqlType = this.getSqlType(columnDef.type);
1318
- const nullable = columnDef.nullable === false ? "NOT NULL" : "";
1319
- const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
1320
- const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
1321
- const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
1322
- await this.pool.request().query(alterSql);
1323
- this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
2537
+ }
2538
+ if (filters.metadata != null) {
2539
+ for (const [key, value] of Object.entries(filters.metadata)) {
2540
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
2541
+ throw new error.MastraError({
2542
+ id: storage.createStorageErrorId("MSSQL", "LIST_TRACES", "INVALID_FILTER_KEY"),
2543
+ domain: error.ErrorDomain.STORAGE,
2544
+ category: error.ErrorCategory.USER,
2545
+ details: { key }
2546
+ });
2547
+ }
2548
+ const param = `p${paramIndex++}`;
2549
+ conditions.push(`JSON_VALUE(r.[metadata], '$.${key}') = @${param}`);
2550
+ params[param] = typeof value === "string" ? value : JSON.stringify(value);
2551
+ }
2552
+ }
2553
+ if (filters.tags != null && filters.tags.length > 0) {
2554
+ for (const tag of filters.tags) {
2555
+ const param = `p${paramIndex++}`;
2556
+ conditions.push(`EXISTS (SELECT 1 FROM OPENJSON(r.[tags]) WHERE [value] = @${param})`);
2557
+ params[param] = tag;
1324
2558
  }
1325
2559
  }
2560
+ if (filters.status !== void 0) {
2561
+ switch (filters.status) {
2562
+ case storage.TraceStatus.ERROR:
2563
+ conditions.push(`r.[error] IS NOT NULL`);
2564
+ break;
2565
+ case storage.TraceStatus.RUNNING:
2566
+ conditions.push(`r.[endedAt] IS NULL AND r.[error] IS NULL`);
2567
+ break;
2568
+ case storage.TraceStatus.SUCCESS:
2569
+ conditions.push(`r.[endedAt] IS NOT NULL AND r.[error] IS NULL`);
2570
+ break;
2571
+ }
2572
+ }
2573
+ if (filters.hasChildError !== void 0) {
2574
+ if (filters.hasChildError) {
2575
+ conditions.push(`EXISTS (
2576
+ SELECT 1 FROM ${tableName} c
2577
+ WHERE c.[traceId] = r.[traceId] AND c.[error] IS NOT NULL
2578
+ )`);
2579
+ } else {
2580
+ conditions.push(`NOT EXISTS (
2581
+ SELECT 1 FROM ${tableName} c
2582
+ WHERE c.[traceId] = r.[traceId] AND c.[error] IS NOT NULL
2583
+ )`);
2584
+ }
2585
+ }
2586
+ }
2587
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2588
+ const sortField = orderBy.field;
2589
+ const sortDirection = orderBy.direction;
2590
+ const countRequest = this.pool.request();
2591
+ Object.entries(params).forEach(([key, value]) => {
2592
+ countRequest.input(key, value);
2593
+ });
2594
+ const countResult = await countRequest.query(
2595
+ `SELECT COUNT(*) as count FROM ${tableName} r ${whereClause}`
2596
+ );
2597
+ const count = countResult.recordset[0]?.count ?? 0;
2598
+ if (count === 0) {
2599
+ return {
2600
+ pagination: {
2601
+ total: 0,
2602
+ page,
2603
+ perPage,
2604
+ hasMore: false
2605
+ },
2606
+ spans: []
2607
+ };
1326
2608
  }
2609
+ const dataRequest = this.pool.request();
2610
+ Object.entries(params).forEach(([key, value]) => {
2611
+ dataRequest.input(key, value);
2612
+ });
2613
+ dataRequest.input("offset", page * perPage);
2614
+ dataRequest.input("limit", perPage);
2615
+ const result = await dataRequest.query(
2616
+ `SELECT
2617
+ r.[traceId], r.[spanId], r.[parentSpanId], r.[name],
2618
+ r.[entityType], r.[entityId], r.[entityName],
2619
+ r.[userId], r.[organizationId], r.[resourceId],
2620
+ r.[runId], r.[sessionId], r.[threadId], r.[requestId],
2621
+ r.[environment], r.[source], r.[serviceName], r.[scope],
2622
+ r.[spanType], r.[attributes], r.[metadata], r.[tags], r.[links],
2623
+ r.[input], r.[output], r.[error], r.[isEvent],
2624
+ r.[startedAt], r.[endedAt], r.[createdAt], r.[updatedAt]
2625
+ FROM ${tableName} r
2626
+ ${whereClause}
2627
+ ORDER BY r.[${sortField}] ${sortDirection}
2628
+ OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
2629
+ );
2630
+ return {
2631
+ pagination: {
2632
+ total: count,
2633
+ page,
2634
+ perPage,
2635
+ hasMore: (page + 1) * perPage < count
2636
+ },
2637
+ spans: result.recordset.map(
2638
+ (span) => transformFromSqlRow({
2639
+ tableName: storage.TABLE_SPANS,
2640
+ sqlRow: span
2641
+ })
2642
+ )
2643
+ };
1327
2644
  } catch (error$1) {
1328
2645
  throw new error.MastraError(
1329
2646
  {
1330
- id: "MASTRA_STORAGE_MSSQL_STORE_ALTER_TABLE_FAILED",
2647
+ id: storage.createStorageErrorId("MSSQL", "LIST_TRACES", "FAILED"),
1331
2648
  domain: error.ErrorDomain.STORAGE,
1332
- category: error.ErrorCategory.THIRD_PARTY,
1333
- details: {
1334
- tableName
1335
- }
2649
+ category: error.ErrorCategory.USER
1336
2650
  },
1337
2651
  error$1
1338
2652
  );
1339
2653
  }
1340
2654
  }
1341
- async load({ tableName, keys }) {
2655
+ async batchCreateSpans(args) {
2656
+ if (!args.records || args.records.length === 0) {
2657
+ return;
2658
+ }
1342
2659
  try {
1343
- const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
1344
- 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}`;
1347
- const request = this.pool.request();
1348
- values.forEach((value, i) => {
1349
- request.input(`param${i}`, value);
2660
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2661
+ await this.db.batchInsert({
2662
+ tableName: storage.TABLE_SPANS,
2663
+ records: args.records.map((span) => ({
2664
+ ...span,
2665
+ startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
2666
+ endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt,
2667
+ createdAt: now,
2668
+ updatedAt: now
2669
+ }))
1350
2670
  });
1351
- const resultSet = await request.query(sql7);
1352
- const result = resultSet.recordset[0] || null;
1353
- if (!result) {
1354
- return null;
1355
- }
1356
- if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
1357
- const snapshot = result;
1358
- if (typeof snapshot.snapshot === "string") {
1359
- snapshot.snapshot = JSON.parse(snapshot.snapshot);
1360
- }
1361
- return snapshot;
1362
- }
1363
- return result;
1364
2671
  } catch (error$1) {
1365
2672
  throw new error.MastraError(
1366
2673
  {
1367
- id: "MASTRA_STORAGE_MSSQL_STORE_LOAD_FAILED",
2674
+ id: storage.createStorageErrorId("MSSQL", "BATCH_CREATE_SPANS", "FAILED"),
1368
2675
  domain: error.ErrorDomain.STORAGE,
1369
- category: error.ErrorCategory.THIRD_PARTY,
2676
+ category: error.ErrorCategory.USER,
1370
2677
  details: {
1371
- tableName
2678
+ count: args.records.length
1372
2679
  }
1373
2680
  },
1374
2681
  error$1
1375
2682
  );
1376
2683
  }
1377
2684
  }
1378
- async batchInsert({ tableName, records }) {
1379
- const transaction = this.pool.transaction();
2685
+ async batchUpdateSpans(args) {
2686
+ if (!args.records || args.records.length === 0) {
2687
+ return;
2688
+ }
2689
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1380
2690
  try {
1381
- await transaction.begin();
1382
- for (const record of records) {
1383
- await this.insert({ tableName, record });
1384
- }
1385
- await transaction.commit();
2691
+ const updates = args.records.map(({ traceId, spanId, updates: data }) => {
2692
+ const processedData = { ...data };
2693
+ if (processedData.endedAt instanceof Date) {
2694
+ processedData.endedAt = processedData.endedAt.toISOString();
2695
+ }
2696
+ if (processedData.startedAt instanceof Date) {
2697
+ processedData.startedAt = processedData.startedAt.toISOString();
2698
+ }
2699
+ processedData.updatedAt = now;
2700
+ return {
2701
+ keys: { spanId, traceId },
2702
+ data: processedData
2703
+ };
2704
+ });
2705
+ await this.db.batchUpdate({
2706
+ tableName: storage.TABLE_SPANS,
2707
+ updates
2708
+ });
1386
2709
  } catch (error$1) {
1387
- await transaction.rollback();
1388
2710
  throw new error.MastraError(
1389
2711
  {
1390
- id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
2712
+ id: storage.createStorageErrorId("MSSQL", "BATCH_UPDATE_SPANS", "FAILED"),
1391
2713
  domain: error.ErrorDomain.STORAGE,
1392
- category: error.ErrorCategory.THIRD_PARTY,
2714
+ category: error.ErrorCategory.USER,
1393
2715
  details: {
1394
- tableName,
1395
- numberOfRecords: records.length
2716
+ count: args.records.length
1396
2717
  }
1397
2718
  },
1398
2719
  error$1
1399
2720
  );
1400
2721
  }
1401
2722
  }
1402
- async dropTable({ tableName }) {
2723
+ async batchDeleteTraces(args) {
2724
+ if (!args.traceIds || args.traceIds.length === 0) {
2725
+ return;
2726
+ }
1403
2727
  try {
1404
- const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
1405
- await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
2728
+ const keys = args.traceIds.map((traceId) => ({ traceId }));
2729
+ await this.db.batchDelete({
2730
+ tableName: storage.TABLE_SPANS,
2731
+ keys
2732
+ });
1406
2733
  } catch (error$1) {
1407
2734
  throw new error.MastraError(
1408
2735
  {
1409
- id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
2736
+ id: storage.createStorageErrorId("MSSQL", "BATCH_DELETE_TRACES", "FAILED"),
1410
2737
  domain: error.ErrorDomain.STORAGE,
1411
- category: error.ErrorCategory.THIRD_PARTY,
2738
+ category: error.ErrorCategory.USER,
1412
2739
  details: {
1413
- tableName
2740
+ count: args.traceIds.length
1414
2741
  }
1415
2742
  },
1416
2743
  error$1
@@ -1418,49 +2745,92 @@ ${columns}
1418
2745
  }
1419
2746
  }
1420
2747
  };
1421
- function parseJSON(jsonString) {
1422
- try {
1423
- return JSON.parse(jsonString);
1424
- } catch {
1425
- return jsonString;
1426
- }
1427
- }
1428
2748
  function transformScoreRow(row) {
1429
- return {
1430
- ...row,
1431
- input: parseJSON(row.input),
1432
- scorer: parseJSON(row.scorer),
1433
- preprocessStepResult: parseJSON(row.preprocessStepResult),
1434
- analyzeStepResult: parseJSON(row.analyzeStepResult),
1435
- metadata: parseJSON(row.metadata),
1436
- output: parseJSON(row.output),
1437
- additionalContext: parseJSON(row.additionalContext),
1438
- runtimeContext: parseJSON(row.runtimeContext),
1439
- entity: parseJSON(row.entity),
1440
- createdAt: row.createdAt,
1441
- updatedAt: row.updatedAt
1442
- };
2749
+ return storage.transformScoreRow(row, {
2750
+ convertTimestamps: true
2751
+ });
1443
2752
  }
1444
- var ScoresMSSQL = class extends storage.ScoresStorage {
2753
+ var ScoresMSSQL = class _ScoresMSSQL extends storage.ScoresStorage {
1445
2754
  pool;
1446
- operations;
2755
+ db;
1447
2756
  schema;
1448
- constructor({
1449
- pool,
1450
- operations,
1451
- schema
1452
- }) {
2757
+ needsConnect;
2758
+ skipDefaultIndexes;
2759
+ indexes;
2760
+ /** Tables managed by this domain */
2761
+ static MANAGED_TABLES = [storage.TABLE_SCORERS];
2762
+ constructor(config) {
1453
2763
  super();
2764
+ const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
1454
2765
  this.pool = pool;
1455
- this.operations = operations;
1456
- this.schema = schema;
2766
+ this.schema = schemaName;
2767
+ this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
2768
+ this.needsConnect = needsConnect;
2769
+ this.skipDefaultIndexes = skipDefaultIndexes;
2770
+ this.indexes = indexes?.filter((idx) => _ScoresMSSQL.MANAGED_TABLES.includes(idx.table));
2771
+ }
2772
+ async init() {
2773
+ if (this.needsConnect) {
2774
+ await this.pool.connect();
2775
+ this.needsConnect = false;
2776
+ }
2777
+ await this.db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORERS] });
2778
+ await this.createDefaultIndexes();
2779
+ await this.createCustomIndexes();
2780
+ }
2781
+ /**
2782
+ * Returns default index definitions for the scores domain tables.
2783
+ * IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
2784
+ */
2785
+ getDefaultIndexDefinitions() {
2786
+ const schemaPrefix = this.schema ? `${this.schema}_` : "";
2787
+ return [
2788
+ {
2789
+ name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
2790
+ table: storage.TABLE_SCORERS,
2791
+ columns: ["traceId", "spanId", "seq_id DESC"]
2792
+ }
2793
+ ];
2794
+ }
2795
+ /**
2796
+ * Creates default indexes for optimal query performance.
2797
+ */
2798
+ async createDefaultIndexes() {
2799
+ if (this.skipDefaultIndexes) {
2800
+ return;
2801
+ }
2802
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
2803
+ try {
2804
+ await this.db.createIndex(indexDef);
2805
+ } catch (error) {
2806
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
2807
+ }
2808
+ }
2809
+ }
2810
+ /**
2811
+ * Creates custom user-defined indexes for this domain's tables.
2812
+ */
2813
+ async createCustomIndexes() {
2814
+ if (!this.indexes || this.indexes.length === 0) {
2815
+ return;
2816
+ }
2817
+ for (const indexDef of this.indexes) {
2818
+ try {
2819
+ await this.db.createIndex(indexDef);
2820
+ } catch (error) {
2821
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
2822
+ }
2823
+ }
2824
+ }
2825
+ async dangerouslyClearAll() {
2826
+ await this.db.clearTable({ tableName: storage.TABLE_SCORERS });
1457
2827
  }
1458
2828
  async getScoreById({ id }) {
1459
2829
  try {
1460
2830
  const request = this.pool.request();
1461
2831
  request.input("p1", id);
1462
2832
  const result = await request.query(
1463
- `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE id = @p1`
2833
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE id = @p1`
1464
2834
  );
1465
2835
  if (result.recordset.length === 0) {
1466
2836
  return null;
@@ -1469,7 +2839,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1469
2839
  } catch (error$1) {
1470
2840
  throw new error.MastraError(
1471
2841
  {
1472
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORE_BY_ID_FAILED",
2842
+ id: storage.createStorageErrorId("MSSQL", "GET_SCORE_BY_ID", "FAILED"),
1473
2843
  domain: error.ErrorDomain.STORAGE,
1474
2844
  category: error.ErrorCategory.THIRD_PARTY,
1475
2845
  details: { id }
@@ -1479,8 +2849,29 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1479
2849
  }
1480
2850
  }
1481
2851
  async saveScore(score) {
2852
+ let validatedScore;
2853
+ try {
2854
+ validatedScore = evals.saveScorePayloadSchema.parse(score);
2855
+ } catch (error$1) {
2856
+ throw new error.MastraError(
2857
+ {
2858
+ id: storage.createStorageErrorId("MSSQL", "SAVE_SCORE", "VALIDATION_FAILED"),
2859
+ domain: error.ErrorDomain.STORAGE,
2860
+ category: error.ErrorCategory.USER,
2861
+ details: {
2862
+ scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
2863
+ entityId: score.entityId ?? "unknown",
2864
+ entityType: score.entityType ?? "unknown",
2865
+ traceId: score.traceId ?? "",
2866
+ spanId: score.spanId ?? ""
2867
+ }
2868
+ },
2869
+ error$1
2870
+ );
2871
+ }
1482
2872
  try {
1483
2873
  const scoreId = crypto.randomUUID();
2874
+ const now = /* @__PURE__ */ new Date();
1484
2875
  const {
1485
2876
  scorer,
1486
2877
  preprocessStepResult,
@@ -1489,34 +2880,33 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1489
2880
  input,
1490
2881
  output,
1491
2882
  additionalContext,
1492
- runtimeContext,
2883
+ requestContext,
1493
2884
  entity,
1494
2885
  ...rest
1495
- } = score;
1496
- await this.operations.insert({
2886
+ } = validatedScore;
2887
+ await this.db.insert({
1497
2888
  tableName: storage.TABLE_SCORERS,
1498
2889
  record: {
1499
2890
  id: scoreId,
1500
2891
  ...rest,
1501
- input: JSON.stringify(input) || "",
1502
- output: JSON.stringify(output) || "",
1503
- preprocessStepResult: preprocessStepResult ? JSON.stringify(preprocessStepResult) : null,
1504
- analyzeStepResult: analyzeStepResult ? JSON.stringify(analyzeStepResult) : null,
1505
- metadata: metadata ? JSON.stringify(metadata) : null,
1506
- additionalContext: additionalContext ? JSON.stringify(additionalContext) : null,
1507
- runtimeContext: runtimeContext ? JSON.stringify(runtimeContext) : null,
1508
- entity: entity ? JSON.stringify(entity) : null,
1509
- scorer: scorer ? JSON.stringify(scorer) : null,
1510
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1511
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2892
+ input: input || "",
2893
+ output: output || "",
2894
+ preprocessStepResult: preprocessStepResult || null,
2895
+ analyzeStepResult: analyzeStepResult || null,
2896
+ metadata: metadata || null,
2897
+ additionalContext: additionalContext || null,
2898
+ requestContext: requestContext || null,
2899
+ entity: entity || null,
2900
+ scorer: scorer || null,
2901
+ createdAt: now.toISOString(),
2902
+ updatedAt: now.toISOString()
1512
2903
  }
1513
2904
  });
1514
- const scoreFromDb = await this.getScoreById({ id: scoreId });
1515
- return { score: scoreFromDb };
2905
+ return { score: { ...validatedScore, id: scoreId, createdAt: now, updatedAt: now } };
1516
2906
  } catch (error$1) {
1517
2907
  throw new error.MastraError(
1518
2908
  {
1519
- id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_FAILED",
2909
+ id: storage.createStorageErrorId("MSSQL", "SAVE_SCORE", "FAILED"),
1520
2910
  domain: error.ErrorDomain.STORAGE,
1521
2911
  category: error.ErrorCategory.THIRD_PARTY
1522
2912
  },
@@ -1524,48 +2914,77 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1524
2914
  );
1525
2915
  }
1526
2916
  }
1527
- async getScoresByScorerId({
2917
+ async listScoresByScorerId({
1528
2918
  scorerId,
1529
- pagination
2919
+ pagination,
2920
+ entityId,
2921
+ entityType,
2922
+ source
1530
2923
  }) {
1531
2924
  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
- );
2925
+ const conditions = ["[scorerId] = @p1"];
2926
+ const params = { p1: scorerId };
2927
+ let paramIndex = 2;
2928
+ if (entityId) {
2929
+ conditions.push(`[entityId] = @p${paramIndex}`);
2930
+ params[`p${paramIndex}`] = entityId;
2931
+ paramIndex++;
2932
+ }
2933
+ if (entityType) {
2934
+ conditions.push(`[entityType] = @p${paramIndex}`);
2935
+ params[`p${paramIndex}`] = entityType;
2936
+ paramIndex++;
2937
+ }
2938
+ if (source) {
2939
+ conditions.push(`[source] = @p${paramIndex}`);
2940
+ params[`p${paramIndex}`] = source;
2941
+ paramIndex++;
2942
+ }
2943
+ const whereClause = conditions.join(" AND ");
2944
+ const tableName = getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) });
2945
+ const countRequest = this.pool.request();
2946
+ Object.entries(params).forEach(([key, value]) => {
2947
+ countRequest.input(key, value);
2948
+ });
2949
+ const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
1537
2950
  const total = totalResult.recordset[0]?.count || 0;
2951
+ const { page, perPage: perPageInput } = pagination;
1538
2952
  if (total === 0) {
1539
2953
  return {
1540
2954
  pagination: {
1541
2955
  total: 0,
1542
- page: pagination.page,
1543
- perPage: pagination.perPage,
2956
+ page,
2957
+ perPage: perPageInput,
1544
2958
  hasMore: false
1545
2959
  },
1546
2960
  scores: []
1547
2961
  };
1548
2962
  }
2963
+ const perPage = storage.normalizePerPage(perPageInput, 100);
2964
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2965
+ const limitValue = perPageInput === false ? total : perPage;
2966
+ const end = perPageInput === false ? total : start + perPage;
1549
2967
  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
- );
2968
+ Object.entries(params).forEach(([key, value]) => {
2969
+ dataRequest.input(key, value);
2970
+ });
2971
+ dataRequest.input("perPage", limitValue);
2972
+ dataRequest.input("offset", start);
2973
+ const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
2974
+ const result = await dataRequest.query(dataQuery);
1556
2975
  return {
1557
2976
  pagination: {
1558
2977
  total: Number(total),
1559
- page: pagination.page,
1560
- perPage: pagination.perPage,
1561
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
2978
+ page,
2979
+ perPage: perPageForResponse,
2980
+ hasMore: end < total
1562
2981
  },
1563
2982
  scores: result.recordset.map((row) => transformScoreRow(row))
1564
2983
  };
1565
2984
  } catch (error$1) {
1566
2985
  throw new error.MastraError(
1567
2986
  {
1568
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
2987
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
1569
2988
  domain: error.ErrorDomain.STORAGE,
1570
2989
  category: error.ErrorCategory.THIRD_PARTY,
1571
2990
  details: { scorerId }
@@ -1574,7 +2993,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1574
2993
  );
1575
2994
  }
1576
2995
  }
1577
- async getScoresByRunId({
2996
+ async listScoresByRunId({
1578
2997
  runId,
1579
2998
  pagination
1580
2999
  }) {
@@ -1582,40 +3001,45 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1582
3001
  const request = this.pool.request();
1583
3002
  request.input("p1", runId);
1584
3003
  const totalResult = await request.query(
1585
- `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1`
3004
+ `SELECT COUNT(*) as count FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [runId] = @p1`
1586
3005
  );
1587
3006
  const total = totalResult.recordset[0]?.count || 0;
3007
+ const { page, perPage: perPageInput } = pagination;
1588
3008
  if (total === 0) {
1589
3009
  return {
1590
3010
  pagination: {
1591
3011
  total: 0,
1592
- page: pagination.page,
1593
- perPage: pagination.perPage,
3012
+ page,
3013
+ perPage: perPageInput,
1594
3014
  hasMore: false
1595
3015
  },
1596
3016
  scores: []
1597
3017
  };
1598
3018
  }
3019
+ const perPage = storage.normalizePerPage(perPageInput, 100);
3020
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
3021
+ const limitValue = perPageInput === false ? total : perPage;
3022
+ const end = perPageInput === false ? total : start + perPage;
1599
3023
  const dataRequest = this.pool.request();
1600
3024
  dataRequest.input("p1", runId);
1601
- dataRequest.input("p2", pagination.perPage);
1602
- dataRequest.input("p3", pagination.page * pagination.perPage);
3025
+ dataRequest.input("p2", limitValue);
3026
+ dataRequest.input("p3", start);
1603
3027
  const result = await dataRequest.query(
1604
- `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [runId] = @p1 ORDER BY [createdAt] DESC OFFSET @p3 ROWS FETCH NEXT @p2 ROWS ONLY`
3028
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [runId] = @p1 ORDER BY [createdAt] DESC OFFSET @p3 ROWS FETCH NEXT @p2 ROWS ONLY`
1605
3029
  );
1606
3030
  return {
1607
3031
  pagination: {
1608
3032
  total: Number(total),
1609
- page: pagination.page,
1610
- perPage: pagination.perPage,
1611
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
3033
+ page,
3034
+ perPage: perPageForResponse,
3035
+ hasMore: end < total
1612
3036
  },
1613
3037
  scores: result.recordset.map((row) => transformScoreRow(row))
1614
3038
  };
1615
3039
  } catch (error$1) {
1616
3040
  throw new error.MastraError(
1617
3041
  {
1618
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_RUN_ID_FAILED",
3042
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_RUN_ID", "FAILED"),
1619
3043
  domain: error.ErrorDomain.STORAGE,
1620
3044
  category: error.ErrorCategory.THIRD_PARTY,
1621
3045
  details: { runId }
@@ -1624,7 +3048,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1624
3048
  );
1625
3049
  }
1626
3050
  }
1627
- async getScoresByEntityId({
3051
+ async listScoresByEntityId({
1628
3052
  entityId,
1629
3053
  entityType,
1630
3054
  pagination
@@ -1634,41 +3058,46 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1634
3058
  request.input("p1", entityId);
1635
3059
  request.input("p2", entityType);
1636
3060
  const totalResult = await request.query(
1637
- `SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2`
3061
+ `SELECT COUNT(*) as count FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2`
1638
3062
  );
1639
3063
  const total = totalResult.recordset[0]?.count || 0;
3064
+ const { page, perPage: perPageInput } = pagination;
3065
+ const perPage = storage.normalizePerPage(perPageInput, 100);
3066
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1640
3067
  if (total === 0) {
1641
3068
  return {
1642
3069
  pagination: {
1643
3070
  total: 0,
1644
- page: pagination.page,
1645
- perPage: pagination.perPage,
3071
+ page,
3072
+ perPage: perPageForResponse,
1646
3073
  hasMore: false
1647
3074
  },
1648
3075
  scores: []
1649
3076
  };
1650
3077
  }
3078
+ const limitValue = perPageInput === false ? total : perPage;
3079
+ const end = perPageInput === false ? total : start + perPage;
1651
3080
  const dataRequest = this.pool.request();
1652
3081
  dataRequest.input("p1", entityId);
1653
3082
  dataRequest.input("p2", entityType);
1654
- dataRequest.input("p3", pagination.perPage);
1655
- dataRequest.input("p4", pagination.page * pagination.perPage);
3083
+ dataRequest.input("p3", limitValue);
3084
+ dataRequest.input("p4", start);
1656
3085
  const result = await dataRequest.query(
1657
- `SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
3086
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [entityId] = @p1 AND [entityType] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
1658
3087
  );
1659
3088
  return {
1660
3089
  pagination: {
1661
3090
  total: Number(total),
1662
- page: pagination.page,
1663
- perPage: pagination.perPage,
1664
- hasMore: Number(total) > (pagination.page + 1) * pagination.perPage
3091
+ page,
3092
+ perPage: perPageForResponse,
3093
+ hasMore: end < total
1665
3094
  },
1666
3095
  scores: result.recordset.map((row) => transformScoreRow(row))
1667
3096
  };
1668
3097
  } catch (error$1) {
1669
3098
  throw new error.MastraError(
1670
3099
  {
1671
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
3100
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
1672
3101
  domain: error.ErrorDomain.STORAGE,
1673
3102
  category: error.ErrorCategory.THIRD_PARTY,
1674
3103
  details: { entityId, entityType }
@@ -1677,249 +3106,317 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
1677
3106
  );
1678
3107
  }
1679
3108
  }
3109
+ async listScoresBySpan({
3110
+ traceId,
3111
+ spanId,
3112
+ pagination
3113
+ }) {
3114
+ try {
3115
+ const request = this.pool.request();
3116
+ request.input("p1", traceId);
3117
+ request.input("p2", spanId);
3118
+ const totalResult = await request.query(
3119
+ `SELECT COUNT(*) as count FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
3120
+ );
3121
+ const total = totalResult.recordset[0]?.count || 0;
3122
+ const { page, perPage: perPageInput } = pagination;
3123
+ const perPage = storage.normalizePerPage(perPageInput, 100);
3124
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
3125
+ if (total === 0) {
3126
+ return {
3127
+ pagination: {
3128
+ total: 0,
3129
+ page,
3130
+ perPage: perPageForResponse,
3131
+ hasMore: false
3132
+ },
3133
+ scores: []
3134
+ };
3135
+ }
3136
+ const limitValue = perPageInput === false ? total : perPage;
3137
+ const end = perPageInput === false ? total : start + perPage;
3138
+ const dataRequest = this.pool.request();
3139
+ dataRequest.input("p1", traceId);
3140
+ dataRequest.input("p2", spanId);
3141
+ dataRequest.input("p3", limitValue);
3142
+ dataRequest.input("p4", start);
3143
+ const result = await dataRequest.query(
3144
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
3145
+ );
3146
+ return {
3147
+ pagination: {
3148
+ total: Number(total),
3149
+ page,
3150
+ perPage: perPageForResponse,
3151
+ hasMore: end < total
3152
+ },
3153
+ scores: result.recordset.map((row) => transformScoreRow(row))
3154
+ };
3155
+ } catch (error$1) {
3156
+ throw new error.MastraError(
3157
+ {
3158
+ id: storage.createStorageErrorId("MSSQL", "LIST_SCORES_BY_SPAN", "FAILED"),
3159
+ domain: error.ErrorDomain.STORAGE,
3160
+ category: error.ErrorCategory.THIRD_PARTY,
3161
+ details: { traceId, spanId }
3162
+ },
3163
+ error$1
3164
+ );
3165
+ }
3166
+ }
1680
3167
  };
1681
- var TracesMSSQL = class extends storage.TracesStorage {
3168
+ var WorkflowsMSSQL = class _WorkflowsMSSQL extends storage.WorkflowsStorage {
1682
3169
  pool;
1683
- operations;
3170
+ db;
1684
3171
  schema;
1685
- constructor({
1686
- pool,
1687
- operations,
1688
- schema
1689
- }) {
3172
+ needsConnect;
3173
+ skipDefaultIndexes;
3174
+ indexes;
3175
+ /** Tables managed by this domain */
3176
+ static MANAGED_TABLES = [storage.TABLE_WORKFLOW_SNAPSHOT];
3177
+ constructor(config) {
1690
3178
  super();
3179
+ const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
1691
3180
  this.pool = pool;
1692
- this.operations = operations;
1693
- this.schema = schema;
1694
- }
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;
3181
+ this.schema = schemaName;
3182
+ this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
3183
+ this.needsConnect = needsConnect;
3184
+ this.skipDefaultIndexes = skipDefaultIndexes;
3185
+ this.indexes = indexes?.filter((idx) => _WorkflowsMSSQL.MANAGED_TABLES.includes(idx.table));
3186
+ }
3187
+ /**
3188
+ * Returns default index definitions for the workflows domain tables.
3189
+ * Currently no default indexes are defined for workflows.
3190
+ */
3191
+ getDefaultIndexDefinitions() {
3192
+ return [];
3193
+ }
3194
+ /**
3195
+ * Creates default indexes for optimal query performance.
3196
+ * Currently no default indexes are defined for workflows.
3197
+ */
3198
+ async createDefaultIndexes() {
3199
+ if (this.skipDefaultIndexes) {
3200
+ return;
1724
3201
  }
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
- });
3202
+ }
3203
+ async init() {
3204
+ if (this.needsConnect) {
3205
+ await this.pool.connect();
3206
+ this.needsConnect = false;
1732
3207
  }
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
- });
3208
+ await this.db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema: storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT] });
3209
+ await this.createDefaultIndexes();
3210
+ await this.createCustomIndexes();
3211
+ }
3212
+ /**
3213
+ * Creates custom user-defined indexes for this domain's tables.
3214
+ */
3215
+ async createCustomIndexes() {
3216
+ if (!this.indexes || this.indexes.length === 0) {
3217
+ return;
1740
3218
  }
1741
- if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
1742
- const paramName = `p${paramIndex++}`;
1743
- conditions.push(`[createdAt] >= @${paramName}`);
1744
- paramMap[paramName] = fromDate.toISOString();
3219
+ for (const indexDef of this.indexes) {
3220
+ try {
3221
+ await this.db.createIndex(indexDef);
3222
+ } catch (error) {
3223
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
3224
+ }
1745
3225
  }
1746
- if (toDate instanceof Date && !isNaN(toDate.getTime())) {
1747
- const paramName = `p${paramIndex++}`;
1748
- conditions.push(`[createdAt] <= @${paramName}`);
1749
- paramMap[paramName] = toDate.toISOString();
3226
+ }
3227
+ async dangerouslyClearAll() {
3228
+ await this.db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
3229
+ }
3230
+ parseWorkflowRun(row) {
3231
+ let parsedSnapshot = row.snapshot;
3232
+ if (typeof parsedSnapshot === "string") {
3233
+ try {
3234
+ parsedSnapshot = JSON.parse(row.snapshot);
3235
+ } catch (e) {
3236
+ this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
3237
+ }
1750
3238
  }
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;
3239
+ return {
3240
+ workflowName: row.workflow_name,
3241
+ runId: row.run_id,
3242
+ snapshot: parsedSnapshot,
3243
+ createdAt: row.createdAt,
3244
+ updatedAt: row.updatedAt,
3245
+ resourceId: row.resourceId
3246
+ };
3247
+ }
3248
+ async updateWorkflowResults({
3249
+ workflowName,
3250
+ runId,
3251
+ stepId,
3252
+ result,
3253
+ requestContext
3254
+ }) {
3255
+ const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
3256
+ const transaction = this.pool.transaction();
1754
3257
  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);
3258
+ await transaction.begin();
3259
+ const selectRequest = new sql__default.default.Request(transaction);
3260
+ selectRequest.input("workflow_name", workflowName);
3261
+ selectRequest.input("run_id", runId);
3262
+ const existingSnapshotResult = await selectRequest.query(
3263
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
3264
+ );
3265
+ let snapshot;
3266
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
3267
+ snapshot = {
3268
+ context: {},
3269
+ activePaths: [],
3270
+ activeStepsPath: {},
3271
+ timestamp: Date.now(),
3272
+ suspendedPaths: {},
3273
+ resumeLabels: {},
3274
+ serializedStepGraph: [],
3275
+ status: "pending",
3276
+ value: {},
3277
+ waitingPaths: {},
3278
+ runId,
3279
+ requestContext: {}
3280
+ };
3281
+ } else {
3282
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
3283
+ snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
3284
+ }
3285
+ snapshot.context[stepId] = result;
3286
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
3287
+ const upsertReq = new sql__default.default.Request(transaction);
3288
+ upsertReq.input("workflow_name", workflowName);
3289
+ upsertReq.input("run_id", runId);
3290
+ upsertReq.input("snapshot", JSON.stringify(snapshot));
3291
+ upsertReq.input("createdAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
3292
+ upsertReq.input("updatedAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
3293
+ await upsertReq.query(
3294
+ `MERGE ${table} AS target
3295
+ USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
3296
+ ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
3297
+ WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
3298
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
3299
+ VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
3300
+ );
3301
+ await transaction.commit();
3302
+ return snapshot.context;
1765
3303
  } catch (error$1) {
3304
+ try {
3305
+ await transaction.rollback();
3306
+ } catch {
3307
+ }
1766
3308
  throw new error.MastraError(
1767
3309
  {
1768
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT",
3310
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
1769
3311
  domain: error.ErrorDomain.STORAGE,
1770
3312
  category: error.ErrorCategory.THIRD_PARTY,
1771
3313
  details: {
1772
- name: args.name ?? "",
1773
- scope: args.scope ?? ""
3314
+ workflowName,
3315
+ runId,
3316
+ stepId
1774
3317
  }
1775
3318
  },
1776
3319
  error$1
1777
3320
  );
1778
3321
  }
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);
3322
+ }
3323
+ async updateWorkflowState({
3324
+ workflowName,
3325
+ runId,
3326
+ opts
3327
+ }) {
3328
+ const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
3329
+ const transaction = this.pool.transaction();
1799
3330
  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
- };
3331
+ await transaction.begin();
3332
+ const selectRequest = new sql__default.default.Request(transaction);
3333
+ selectRequest.input("workflow_name", workflowName);
3334
+ selectRequest.input("run_id", runId);
3335
+ const existingSnapshotResult = await selectRequest.query(
3336
+ `SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
3337
+ );
3338
+ if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
3339
+ await transaction.rollback();
3340
+ return void 0;
3341
+ }
3342
+ const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
3343
+ const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
3344
+ if (!snapshot || !snapshot?.context) {
3345
+ await transaction.rollback();
3346
+ throw new error.MastraError(
3347
+ {
3348
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_STATE", "SNAPSHOT_NOT_FOUND"),
3349
+ domain: error.ErrorDomain.STORAGE,
3350
+ category: error.ErrorCategory.SYSTEM,
3351
+ details: {
3352
+ workflowName,
3353
+ runId
3354
+ }
3355
+ },
3356
+ new Error(`Snapshot not found for runId ${runId}`)
3357
+ );
3358
+ }
3359
+ const updatedSnapshot = { ...snapshot, ...opts };
3360
+ const updateRequest = new sql__default.default.Request(transaction);
3361
+ updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
3362
+ updateRequest.input("workflow_name", workflowName);
3363
+ updateRequest.input("run_id", runId);
3364
+ updateRequest.input("updatedAt", sql__default.default.DateTime2, /* @__PURE__ */ new Date());
3365
+ await updateRequest.query(
3366
+ `UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
3367
+ );
3368
+ await transaction.commit();
3369
+ return updatedSnapshot;
1825
3370
  } catch (error$1) {
3371
+ try {
3372
+ await transaction.rollback();
3373
+ } catch {
3374
+ }
3375
+ if (error$1 instanceof error.MastraError) throw error$1;
1826
3376
  throw new error.MastraError(
1827
3377
  {
1828
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES",
3378
+ id: storage.createStorageErrorId("MSSQL", "UPDATE_WORKFLOW_STATE", "FAILED"),
1829
3379
  domain: error.ErrorDomain.STORAGE,
1830
3380
  category: error.ErrorCategory.THIRD_PARTY,
1831
3381
  details: {
1832
- name: args.name ?? "",
1833
- scope: args.scope ?? ""
3382
+ workflowName,
3383
+ runId
1834
3384
  }
1835
3385
  },
1836
3386
  error$1
1837
3387
  );
1838
3388
  }
1839
3389
  }
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
3390
  async persistWorkflowSnapshot({
1897
3391
  workflowName,
1898
3392
  runId,
3393
+ resourceId,
1899
3394
  snapshot
1900
3395
  }) {
1901
- const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
3396
+ const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
1902
3397
  const now = (/* @__PURE__ */ new Date()).toISOString();
1903
3398
  try {
1904
3399
  const request = this.pool.request();
1905
3400
  request.input("workflow_name", workflowName);
1906
3401
  request.input("run_id", runId);
3402
+ request.input("resourceId", resourceId);
1907
3403
  request.input("snapshot", JSON.stringify(snapshot));
1908
- request.input("createdAt", sql2__default.default.DateTime2, new Date(now));
1909
- request.input("updatedAt", sql2__default.default.DateTime2, new Date(now));
3404
+ request.input("createdAt", sql__default.default.DateTime2, new Date(now));
3405
+ request.input("updatedAt", sql__default.default.DateTime2, new Date(now));
1910
3406
  const mergeSql = `MERGE INTO ${table} AS target
1911
3407
  USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
1912
3408
  ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
1913
3409
  WHEN MATCHED THEN UPDATE SET
3410
+ resourceId = @resourceId,
1914
3411
  snapshot = @snapshot,
1915
3412
  [updatedAt] = @updatedAt
1916
- WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
1917
- VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
3413
+ WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
3414
+ VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
1918
3415
  await request.query(mergeSql);
1919
3416
  } catch (error$1) {
1920
3417
  throw new error.MastraError(
1921
3418
  {
1922
- id: "MASTRA_STORAGE_MSSQL_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
3419
+ id: storage.createStorageErrorId("MSSQL", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
1923
3420
  domain: error.ErrorDomain.STORAGE,
1924
3421
  category: error.ErrorCategory.THIRD_PARTY,
1925
3422
  details: {
@@ -1936,7 +3433,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1936
3433
  runId
1937
3434
  }) {
1938
3435
  try {
1939
- const result = await this.operations.load({
3436
+ const result = await this.db.load({
1940
3437
  tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
1941
3438
  keys: {
1942
3439
  workflow_name: workflowName,
@@ -1950,7 +3447,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1950
3447
  } catch (error$1) {
1951
3448
  throw new error.MastraError(
1952
3449
  {
1953
- id: "MASTRA_STORAGE_MSSQL_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
3450
+ id: storage.createStorageErrorId("MSSQL", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
1954
3451
  domain: error.ErrorDomain.STORAGE,
1955
3452
  category: error.ErrorCategory.THIRD_PARTY,
1956
3453
  details: {
@@ -1978,7 +3475,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1978
3475
  paramMap["workflowName"] = workflowName;
1979
3476
  }
1980
3477
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1981
- const tableName = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
3478
+ const tableName = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
1982
3479
  const query = `SELECT * FROM ${tableName} ${whereClause}`;
1983
3480
  const request = this.pool.request();
1984
3481
  Object.entries(paramMap).forEach(([key, value]) => request.input(key, value));
@@ -1986,11 +3483,11 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
1986
3483
  if (!result.recordset || result.recordset.length === 0) {
1987
3484
  return null;
1988
3485
  }
1989
- return parseWorkflowRun(result.recordset[0]);
3486
+ return this.parseWorkflowRun(result.recordset[0]);
1990
3487
  } catch (error$1) {
1991
3488
  throw new error.MastraError(
1992
3489
  {
1993
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
3490
+ id: storage.createStorageErrorId("MSSQL", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1994
3491
  domain: error.ErrorDomain.STORAGE,
1995
3492
  category: error.ErrorCategory.THIRD_PARTY,
1996
3493
  details: {
@@ -2002,13 +3499,43 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2002
3499
  );
2003
3500
  }
2004
3501
  }
2005
- async getWorkflowRuns({
3502
+ async deleteWorkflowRunById({ runId, workflowName }) {
3503
+ const table = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
3504
+ const transaction = this.pool.transaction();
3505
+ try {
3506
+ await transaction.begin();
3507
+ const deleteRequest = new sql__default.default.Request(transaction);
3508
+ deleteRequest.input("workflow_name", workflowName);
3509
+ deleteRequest.input("run_id", runId);
3510
+ await deleteRequest.query(`DELETE FROM ${table} WHERE workflow_name = @workflow_name AND run_id = @run_id`);
3511
+ await transaction.commit();
3512
+ } catch (error$1) {
3513
+ try {
3514
+ await transaction.rollback();
3515
+ } catch {
3516
+ }
3517
+ throw new error.MastraError(
3518
+ {
3519
+ id: storage.createStorageErrorId("MSSQL", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
3520
+ domain: error.ErrorDomain.STORAGE,
3521
+ category: error.ErrorCategory.THIRD_PARTY,
3522
+ details: {
3523
+ runId,
3524
+ workflowName
3525
+ }
3526
+ },
3527
+ error$1
3528
+ );
3529
+ }
3530
+ }
3531
+ async listWorkflowRuns({
2006
3532
  workflowName,
2007
3533
  fromDate,
2008
3534
  toDate,
2009
- limit,
2010
- offset,
2011
- resourceId
3535
+ page,
3536
+ perPage,
3537
+ resourceId,
3538
+ status
2012
3539
  } = {}) {
2013
3540
  try {
2014
3541
  const conditions = [];
@@ -2017,13 +3544,17 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2017
3544
  conditions.push(`[workflow_name] = @workflowName`);
2018
3545
  paramMap["workflowName"] = workflowName;
2019
3546
  }
3547
+ if (status) {
3548
+ conditions.push(`JSON_VALUE([snapshot], '$.status') = @status`);
3549
+ paramMap["status"] = status;
3550
+ }
2020
3551
  if (resourceId) {
2021
- const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
3552
+ const hasResourceId = await this.db.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
2022
3553
  if (hasResourceId) {
2023
3554
  conditions.push(`[resourceId] = @resourceId`);
2024
3555
  paramMap["resourceId"] = resourceId;
2025
3556
  } else {
2026
- console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
3557
+ this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
2027
3558
  }
2028
3559
  }
2029
3560
  if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
@@ -2036,33 +3567,36 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2036
3567
  }
2037
3568
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2038
3569
  let total = 0;
2039
- const tableName = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
3570
+ const tableName = getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.schema) });
2040
3571
  const request = this.pool.request();
2041
3572
  Object.entries(paramMap).forEach(([key, value]) => {
2042
3573
  if (value instanceof Date) {
2043
- request.input(key, sql2__default.default.DateTime, value);
3574
+ request.input(key, sql__default.default.DateTime, value);
2044
3575
  } else {
2045
3576
  request.input(key, value);
2046
3577
  }
2047
3578
  });
2048
- if (limit !== void 0 && offset !== void 0) {
3579
+ const usePagination = typeof perPage === "number" && typeof page === "number";
3580
+ if (usePagination) {
2049
3581
  const countQuery = `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`;
2050
3582
  const countResult = await request.query(countQuery);
2051
3583
  total = Number(countResult.recordset[0]?.count || 0);
2052
3584
  }
2053
3585
  let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY [seq_id] DESC`;
2054
- if (limit !== void 0 && offset !== void 0) {
2055
- query += ` OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
2056
- request.input("limit", limit);
3586
+ if (usePagination) {
3587
+ const normalizedPerPage = storage.normalizePerPage(perPage, Number.MAX_SAFE_INTEGER);
3588
+ const offset = page * normalizedPerPage;
3589
+ query += ` OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
3590
+ request.input("perPage", normalizedPerPage);
2057
3591
  request.input("offset", offset);
2058
3592
  }
2059
3593
  const result = await request.query(query);
2060
- const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
3594
+ const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
2061
3595
  return { runs, total: total || runs.length };
2062
3596
  } catch (error$1) {
2063
3597
  throw new error.MastraError(
2064
3598
  {
2065
- id: "MASTRA_STORAGE_MSSQL_STORE_GET_WORKFLOW_RUNS_FAILED",
3599
+ id: storage.createStorageErrorId("MSSQL", "LIST_WORKFLOW_RUNS", "FAILED"),
2066
3600
  domain: error.ErrorDomain.STORAGE,
2067
3601
  category: error.ErrorCategory.THIRD_PARTY,
2068
3602
  details: {
@@ -2076,18 +3610,28 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
2076
3610
  };
2077
3611
 
2078
3612
  // src/storage/index.ts
3613
+ var isPoolConfig = (config) => {
3614
+ return "pool" in config;
3615
+ };
2079
3616
  var MSSQLStore = class extends storage.MastraStorage {
2080
3617
  pool;
2081
3618
  schema;
2082
3619
  isConnected = null;
2083
3620
  stores;
2084
3621
  constructor(config) {
2085
- super({ name: "MSSQLStore" });
3622
+ if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
3623
+ throw new Error("MSSQLStore: id must be provided and cannot be empty.");
3624
+ }
3625
+ super({ id: config.id, name: "MSSQLStore", disableInit: config.disableInit });
2086
3626
  try {
2087
- if ("connectionString" in config) {
3627
+ this.schema = config.schemaName || "dbo";
3628
+ if (isPoolConfig(config)) {
3629
+ this.pool = config.pool;
3630
+ } else if ("connectionString" in config) {
2088
3631
  if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
2089
3632
  throw new Error("MSSQLStore: connectionString must be provided and cannot be empty.");
2090
3633
  }
3634
+ this.pool = new sql__default.default.ConnectionPool(config.connectionString);
2091
3635
  } else {
2092
3636
  const required = ["server", "database", "user", "password"];
2093
3637
  for (const key of required) {
@@ -2095,34 +3639,35 @@ var MSSQLStore = class extends storage.MastraStorage {
2095
3639
  throw new Error(`MSSQLStore: ${key} must be provided and cannot be empty.`);
2096
3640
  }
2097
3641
  }
3642
+ this.pool = new sql__default.default.ConnectionPool({
3643
+ server: config.server,
3644
+ database: config.database,
3645
+ user: config.user,
3646
+ password: config.password,
3647
+ port: config.port,
3648
+ options: config.options || { encrypt: true, trustServerCertificate: true }
3649
+ });
2098
3650
  }
2099
- this.schema = config.schemaName || "dbo";
2100
- this.pool = "connectionString" in config ? new sql2__default.default.ConnectionPool(config.connectionString) : new sql2__default.default.ConnectionPool({
2101
- server: config.server,
2102
- database: config.database,
2103
- user: config.user,
2104
- password: config.password,
2105
- port: config.port,
2106
- options: config.options || { encrypt: true, trustServerCertificate: true }
2107
- });
2108
- const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
2109
- const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
2110
- const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
2111
- const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
2112
- const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
2113
- const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
3651
+ const domainConfig = {
3652
+ pool: this.pool,
3653
+ schemaName: this.schema,
3654
+ skipDefaultIndexes: config.skipDefaultIndexes,
3655
+ indexes: config.indexes
3656
+ };
3657
+ const scores = new ScoresMSSQL(domainConfig);
3658
+ const workflows = new WorkflowsMSSQL(domainConfig);
3659
+ const memory = new MemoryMSSQL(domainConfig);
3660
+ const observability = new ObservabilityMSSQL(domainConfig);
2114
3661
  this.stores = {
2115
- operations,
2116
3662
  scores,
2117
- traces,
2118
3663
  workflows,
2119
- legacyEvals,
2120
- memory
3664
+ memory,
3665
+ observability
2121
3666
  };
2122
3667
  } catch (e) {
2123
3668
  throw new error.MastraError(
2124
3669
  {
2125
- id: "MASTRA_STORAGE_MSSQL_STORE_INITIALIZATION_FAILED",
3670
+ id: storage.createStorageErrorId("MSSQL", "INITIALIZATION", "FAILED"),
2126
3671
  domain: error.ErrorDomain.STORAGE,
2127
3672
  category: error.ErrorCategory.USER
2128
3673
  },
@@ -2141,7 +3686,7 @@ var MSSQLStore = class extends storage.MastraStorage {
2141
3686
  this.isConnected = null;
2142
3687
  throw new error.MastraError(
2143
3688
  {
2144
- id: "MASTRA_STORAGE_MSSQL_STORE_INIT_FAILED",
3689
+ id: storage.createStorageErrorId("MSSQL", "INIT", "FAILED"),
2145
3690
  domain: error.ErrorDomain.STORAGE,
2146
3691
  category: error.ErrorCategory.THIRD_PARTY
2147
3692
  },
@@ -2157,211 +3702,20 @@ var MSSQLStore = class extends storage.MastraStorage {
2157
3702
  throw err;
2158
3703
  }
2159
3704
  }
2160
- get supports() {
2161
- return {
2162
- selectByIncludeResourceScope: true,
2163
- resourceWorkingMemory: true,
2164
- hasColumn: true,
2165
- createTable: true,
2166
- deleteMessages: true
2167
- };
2168
- }
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
- async createTable({
2189
- tableName,
2190
- schema
2191
- }) {
2192
- return this.stores.operations.createTable({ tableName, schema });
2193
- }
2194
- async alterTable({
2195
- tableName,
2196
- schema,
2197
- ifNotExists
2198
- }) {
2199
- return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
2200
- }
2201
- async clearTable({ tableName }) {
2202
- return this.stores.operations.clearTable({ tableName });
2203
- }
2204
- async dropTable({ tableName }) {
2205
- return this.stores.operations.dropTable({ tableName });
2206
- }
2207
- async insert({ tableName, record }) {
2208
- return this.stores.operations.insert({ tableName, record });
2209
- }
2210
- async batchInsert({ tableName, records }) {
2211
- return this.stores.operations.batchInsert({ tableName, records });
2212
- }
2213
- async load({ tableName, keys }) {
2214
- return this.stores.operations.load({ tableName, keys });
2215
- }
2216
- /**
2217
- * Memory
2218
- */
2219
- async getThreadById({ threadId }) {
2220
- return this.stores.memory.getThreadById({ threadId });
2221
- }
2222
- /**
2223
- * @deprecated use getThreadsByResourceIdPaginated instead
2224
- */
2225
- async getThreadsByResourceId(args) {
2226
- return this.stores.memory.getThreadsByResourceId(args);
2227
- }
2228
- async getThreadsByResourceIdPaginated(args) {
2229
- return this.stores.memory.getThreadsByResourceIdPaginated(args);
2230
- }
2231
- async saveThread({ thread }) {
2232
- return this.stores.memory.saveThread({ thread });
2233
- }
2234
- async updateThread({
2235
- id,
2236
- title,
2237
- metadata
2238
- }) {
2239
- return this.stores.memory.updateThread({ id, title, metadata });
2240
- }
2241
- async deleteThread({ threadId }) {
2242
- return this.stores.memory.deleteThread({ threadId });
2243
- }
2244
- async getMessages(args) {
2245
- return this.stores.memory.getMessages(args);
2246
- }
2247
- async getMessagesById({
2248
- messageIds,
2249
- format
2250
- }) {
2251
- return this.stores.memory.getMessagesById({ messageIds, format });
2252
- }
2253
- async getMessagesPaginated(args) {
2254
- return this.stores.memory.getMessagesPaginated(args);
2255
- }
2256
- async saveMessages(args) {
2257
- return this.stores.memory.saveMessages(args);
2258
- }
2259
- async updateMessages({
2260
- messages
2261
- }) {
2262
- return this.stores.memory.updateMessages({ messages });
2263
- }
2264
- async deleteMessages(messageIds) {
2265
- return this.stores.memory.deleteMessages(messageIds);
2266
- }
2267
- async getResourceById({ resourceId }) {
2268
- return this.stores.memory.getResourceById({ resourceId });
2269
- }
2270
- async saveResource({ resource }) {
2271
- return this.stores.memory.saveResource({ resource });
2272
- }
2273
- async updateResource({
2274
- resourceId,
2275
- workingMemory,
2276
- metadata
2277
- }) {
2278
- return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2279
- }
2280
3705
  /**
2281
- * Workflows
3706
+ * Closes the MSSQL connection pool.
3707
+ *
3708
+ * This will close the connection pool, including pre-configured pools.
2282
3709
  */
2283
- async updateWorkflowResults({
2284
- workflowName,
2285
- runId,
2286
- stepId,
2287
- result,
2288
- runtimeContext
2289
- }) {
2290
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
2291
- }
2292
- async updateWorkflowState({
2293
- workflowName,
2294
- runId,
2295
- opts
2296
- }) {
2297
- return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2298
- }
2299
- async persistWorkflowSnapshot({
2300
- workflowName,
2301
- runId,
2302
- snapshot
2303
- }) {
2304
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2305
- }
2306
- async loadWorkflowSnapshot({
2307
- workflowName,
2308
- runId
2309
- }) {
2310
- return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2311
- }
2312
- async getWorkflowRuns({
2313
- workflowName,
2314
- fromDate,
2315
- toDate,
2316
- limit,
2317
- offset,
2318
- resourceId
2319
- } = {}) {
2320
- return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
2321
- }
2322
- async getWorkflowRunById({
2323
- runId,
2324
- workflowName
2325
- }) {
2326
- return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2327
- }
2328
3710
  async close() {
2329
3711
  await this.pool.close();
2330
3712
  }
2331
- /**
2332
- * Scorers
2333
- */
2334
- async getScoreById({ id: _id }) {
2335
- return this.stores.scores.getScoreById({ id: _id });
2336
- }
2337
- async getScoresByScorerId({
2338
- scorerId: _scorerId,
2339
- pagination: _pagination
2340
- }) {
2341
- return this.stores.scores.getScoresByScorerId({ scorerId: _scorerId, pagination: _pagination });
2342
- }
2343
- async saveScore(_score) {
2344
- return this.stores.scores.saveScore(_score);
2345
- }
2346
- async getScoresByRunId({
2347
- runId: _runId,
2348
- pagination: _pagination
2349
- }) {
2350
- return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
2351
- }
2352
- async getScoresByEntityId({
2353
- entityId: _entityId,
2354
- entityType: _entityType,
2355
- pagination: _pagination
2356
- }) {
2357
- return this.stores.scores.getScoresByEntityId({
2358
- entityId: _entityId,
2359
- entityType: _entityType,
2360
- pagination: _pagination
2361
- });
2362
- }
2363
3713
  };
2364
3714
 
2365
3715
  exports.MSSQLStore = MSSQLStore;
3716
+ exports.MemoryMSSQL = MemoryMSSQL;
3717
+ exports.ObservabilityMSSQL = ObservabilityMSSQL;
3718
+ exports.ScoresMSSQL = ScoresMSSQL;
3719
+ exports.WorkflowsMSSQL = WorkflowsMSSQL;
2366
3720
  //# sourceMappingURL=index.cjs.map
2367
3721
  //# sourceMappingURL=index.cjs.map