@mastra/mssql 0.0.0-fix-11329-windows-path-20251222155941 → 0.0.0-fix-local-pkg-cwd-20251224015404
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +348 -3
- package/dist/index.cjs +705 -414
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +706 -415
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +36 -23
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/db/utils.d.ts +1 -5
- package/dist/storage/db/utils.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +18 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +26 -23
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +23 -18
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/utils.d.ts +2 -2
- package/dist/storage/domains/utils.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +19 -1
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +55 -176
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
2
|
-
import { MastraStorage, createStorageErrorId,
|
|
2
|
+
import { MastraStorage, createStorageErrorId, ScoresStorage, TABLE_SCORERS, TABLE_SCHEMAS, normalizePerPage, calculatePagination, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ObservabilityStorage, TABLE_SPANS, SPAN_SCHEMA, listTracesArgsSchema, getDefaultValue, transformScoreRow as transformScoreRow$1, TraceStatus } from '@mastra/core/storage';
|
|
3
3
|
import sql from 'mssql';
|
|
4
|
+
import { MessageList } from '@mastra/core/agent';
|
|
4
5
|
import { MastraBase } from '@mastra/core/base';
|
|
5
6
|
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
6
|
-
import { MessageList } from '@mastra/core/agent';
|
|
7
7
|
import { randomUUID } from 'crypto';
|
|
8
8
|
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
9
9
|
|
|
@@ -20,31 +20,89 @@ function getTableName({ indexName, schemaName }) {
|
|
|
20
20
|
|
|
21
21
|
// src/storage/db/index.ts
|
|
22
22
|
function resolveMssqlConfig(config) {
|
|
23
|
-
if ("pool" in config && "
|
|
24
|
-
return {
|
|
23
|
+
if ("pool" in config && !("server" in config)) {
|
|
24
|
+
return {
|
|
25
|
+
pool: config.pool,
|
|
26
|
+
schemaName: config.schemaName,
|
|
27
|
+
skipDefaultIndexes: config.skipDefaultIndexes,
|
|
28
|
+
indexes: config.indexes,
|
|
29
|
+
needsConnect: false
|
|
30
|
+
};
|
|
25
31
|
}
|
|
32
|
+
const restConfig = config;
|
|
26
33
|
const pool = new sql.ConnectionPool({
|
|
27
|
-
server:
|
|
28
|
-
database:
|
|
29
|
-
user:
|
|
30
|
-
password:
|
|
31
|
-
port:
|
|
32
|
-
options:
|
|
34
|
+
server: restConfig.server,
|
|
35
|
+
database: restConfig.database,
|
|
36
|
+
user: restConfig.user,
|
|
37
|
+
password: restConfig.password,
|
|
38
|
+
port: restConfig.port,
|
|
39
|
+
options: restConfig.options || { encrypt: true, trustServerCertificate: true }
|
|
33
40
|
});
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
return {
|
|
42
|
+
pool,
|
|
43
|
+
schemaName: restConfig.schemaName,
|
|
44
|
+
skipDefaultIndexes: restConfig.skipDefaultIndexes,
|
|
45
|
+
indexes: restConfig.indexes,
|
|
46
|
+
needsConnect: true
|
|
47
|
+
};
|
|
36
48
|
}
|
|
37
49
|
var MssqlDB = class extends MastraBase {
|
|
38
50
|
pool;
|
|
39
51
|
schemaName;
|
|
52
|
+
skipDefaultIndexes;
|
|
40
53
|
setupSchemaPromise = null;
|
|
41
54
|
schemaSetupComplete = void 0;
|
|
42
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Columns that participate in composite indexes need smaller sizes (NVARCHAR(100)).
|
|
57
|
+
* MSSQL has a 900-byte index key limit, so composite indexes with NVARCHAR(400) columns fail.
|
|
58
|
+
* These are typically ID/type fields that don't need 400 chars.
|
|
59
|
+
*/
|
|
60
|
+
COMPOSITE_INDEX_COLUMNS = [
|
|
61
|
+
"traceId",
|
|
62
|
+
// Used in: PRIMARY KEY (traceId, spanId), index (traceId, spanId, seq_id)
|
|
63
|
+
"spanId",
|
|
64
|
+
// Used in: PRIMARY KEY (traceId, spanId), index (traceId, spanId, seq_id)
|
|
65
|
+
"parentSpanId",
|
|
66
|
+
// Used in: index (parentSpanId, startedAt)
|
|
67
|
+
"entityType",
|
|
68
|
+
// Used in: (entityType, entityId), (entityType, entityName)
|
|
69
|
+
"entityId",
|
|
70
|
+
// Used in: (entityType, entityId)
|
|
71
|
+
"entityName",
|
|
72
|
+
// Used in: (entityType, entityName)
|
|
73
|
+
"organizationId",
|
|
74
|
+
// Used in: (organizationId, userId)
|
|
75
|
+
"userId"
|
|
76
|
+
// Used in: (organizationId, userId)
|
|
77
|
+
];
|
|
78
|
+
/**
|
|
79
|
+
* Columns that store large amounts of data and should use NVARCHAR(MAX).
|
|
80
|
+
* Avoid listing columns that participate in indexes (resourceId, thread_id, agent_name, name, etc.)
|
|
81
|
+
*/
|
|
82
|
+
LARGE_DATA_COLUMNS = [
|
|
83
|
+
"workingMemory",
|
|
84
|
+
"snapshot",
|
|
85
|
+
"metadata",
|
|
86
|
+
"content",
|
|
87
|
+
// messages.content - can be very long conversation content
|
|
88
|
+
"input",
|
|
89
|
+
// evals.input - test input data
|
|
90
|
+
"output",
|
|
91
|
+
// evals.output - test output data
|
|
92
|
+
"instructions",
|
|
93
|
+
// evals.instructions - evaluation instructions
|
|
94
|
+
"other"
|
|
95
|
+
// traces.other - additional trace data
|
|
96
|
+
];
|
|
97
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false, useSmallStorage = false) {
|
|
43
98
|
switch (type) {
|
|
44
99
|
case "text":
|
|
45
100
|
if (useLargeStorage) {
|
|
46
101
|
return "NVARCHAR(MAX)";
|
|
47
102
|
}
|
|
103
|
+
if (useSmallStorage) {
|
|
104
|
+
return "NVARCHAR(100)";
|
|
105
|
+
}
|
|
48
106
|
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
49
107
|
case "timestamp":
|
|
50
108
|
return "DATETIME2(7)";
|
|
@@ -68,10 +126,15 @@ var MssqlDB = class extends MastraBase {
|
|
|
68
126
|
});
|
|
69
127
|
}
|
|
70
128
|
}
|
|
71
|
-
constructor({
|
|
129
|
+
constructor({
|
|
130
|
+
pool,
|
|
131
|
+
schemaName,
|
|
132
|
+
skipDefaultIndexes
|
|
133
|
+
}) {
|
|
72
134
|
super({ component: "STORAGE", name: "MssqlDB" });
|
|
73
135
|
this.pool = pool;
|
|
74
136
|
this.schemaName = schemaName;
|
|
137
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
75
138
|
}
|
|
76
139
|
async hasColumn(table, column) {
|
|
77
140
|
const schema = this.schemaName || "dbo";
|
|
@@ -203,29 +266,15 @@ var MssqlDB = class extends MastraBase {
|
|
|
203
266
|
}) {
|
|
204
267
|
try {
|
|
205
268
|
const uniqueConstraintColumns = tableName === TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
206
|
-
const largeDataColumns = [
|
|
207
|
-
"workingMemory",
|
|
208
|
-
"snapshot",
|
|
209
|
-
"metadata",
|
|
210
|
-
"content",
|
|
211
|
-
// messages.content - can be very long conversation content
|
|
212
|
-
"input",
|
|
213
|
-
// evals.input - test input data
|
|
214
|
-
"output",
|
|
215
|
-
// evals.output - test output data
|
|
216
|
-
"instructions",
|
|
217
|
-
// evals.instructions - evaluation instructions
|
|
218
|
-
"other"
|
|
219
|
-
// traces.other - additional trace data
|
|
220
|
-
];
|
|
221
269
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
222
270
|
const parsedName = parseSqlIdentifier(name, "column name");
|
|
223
271
|
const constraints = [];
|
|
224
272
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
225
273
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
226
274
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
227
|
-
const useLargeStorage =
|
|
228
|
-
|
|
275
|
+
const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(name);
|
|
276
|
+
const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(name);
|
|
277
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage, useSmallStorage)} ${constraints.join(" ")}`.trim();
|
|
229
278
|
}).join(",\n");
|
|
230
279
|
if (this.schemaName) {
|
|
231
280
|
await this.setupSchema();
|
|
@@ -262,18 +311,37 @@ ${columns}
|
|
|
262
311
|
const alterSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD seq_id BIGINT IDENTITY(1,1)`;
|
|
263
312
|
await this.pool.request().query(alterSql);
|
|
264
313
|
}
|
|
314
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
265
315
|
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
266
|
-
const constraintName =
|
|
316
|
+
const constraintName = `${schemaPrefix}mastra_workflow_snapshot_workflow_name_run_id_key`;
|
|
267
317
|
const checkConstraintSql = `SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`;
|
|
268
318
|
const checkConstraintRequest = this.pool.request();
|
|
269
319
|
checkConstraintRequest.input("constraintName", constraintName);
|
|
270
320
|
const constraintResult = await checkConstraintRequest.query(checkConstraintSql);
|
|
271
321
|
const constraintExists = Array.isArray(constraintResult.recordset) && constraintResult.recordset.length > 0;
|
|
272
322
|
if (!constraintExists) {
|
|
273
|
-
const addConstraintSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT ${constraintName} UNIQUE ([workflow_name], [run_id])`;
|
|
323
|
+
const addConstraintSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT [${constraintName}] UNIQUE ([workflow_name], [run_id])`;
|
|
274
324
|
await this.pool.request().query(addConstraintSql);
|
|
275
325
|
}
|
|
276
326
|
}
|
|
327
|
+
if (tableName === TABLE_SPANS) {
|
|
328
|
+
await this.migrateSpansTable();
|
|
329
|
+
const pkConstraintName = `${schemaPrefix}mastra_ai_spans_traceid_spanid_pk`;
|
|
330
|
+
const checkPkRequest = this.pool.request();
|
|
331
|
+
checkPkRequest.input("constraintName", pkConstraintName);
|
|
332
|
+
const pkResult = await checkPkRequest.query(
|
|
333
|
+
`SELECT 1 AS found FROM sys.key_constraints WHERE name = @constraintName`
|
|
334
|
+
);
|
|
335
|
+
const pkExists = Array.isArray(pkResult.recordset) && pkResult.recordset.length > 0;
|
|
336
|
+
if (!pkExists) {
|
|
337
|
+
try {
|
|
338
|
+
const addPkSql = `ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} ADD CONSTRAINT [${pkConstraintName}] PRIMARY KEY ([traceId], [spanId])`;
|
|
339
|
+
await this.pool.request().query(addPkSql);
|
|
340
|
+
} catch (pkError) {
|
|
341
|
+
this.logger?.warn?.(`Failed to add composite primary key to spans table:`, pkError);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
277
345
|
} catch (error) {
|
|
278
346
|
throw new MastraError(
|
|
279
347
|
{
|
|
@@ -288,6 +356,34 @@ ${columns}
|
|
|
288
356
|
);
|
|
289
357
|
}
|
|
290
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* Migrates the spans table schema from OLD_SPAN_SCHEMA to current SPAN_SCHEMA.
|
|
361
|
+
* This adds new columns that don't exist in old schema.
|
|
362
|
+
*/
|
|
363
|
+
async migrateSpansTable() {
|
|
364
|
+
const fullTableName = getTableName({ indexName: TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
|
|
365
|
+
const schema = TABLE_SCHEMAS[TABLE_SPANS];
|
|
366
|
+
try {
|
|
367
|
+
for (const [columnName, columnDef] of Object.entries(schema)) {
|
|
368
|
+
const columnExists = await this.hasColumn(TABLE_SPANS, columnName);
|
|
369
|
+
if (!columnExists) {
|
|
370
|
+
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
371
|
+
const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(columnName);
|
|
372
|
+
const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(columnName);
|
|
373
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
374
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage, useSmallStorage);
|
|
375
|
+
const nullable = columnDef.nullable ? "" : "NOT NULL";
|
|
376
|
+
const defaultValue = !columnDef.nullable ? this.getDefaultValue(columnDef.type) : "";
|
|
377
|
+
const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
378
|
+
await this.pool.request().query(alterSql);
|
|
379
|
+
this.logger?.debug?.(`Added column '${columnName}' to ${fullTableName}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
this.logger?.info?.(`Migration completed for ${fullTableName}`);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
this.logger?.warn?.(`Failed to migrate spans table ${fullTableName}:`, error);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
291
387
|
/**
|
|
292
388
|
* Alters table schema to add columns if they don't exist
|
|
293
389
|
* @param tableName Name of the table
|
|
@@ -312,21 +408,12 @@ ${columns}
|
|
|
312
408
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
313
409
|
if (!columnExists) {
|
|
314
410
|
const columnDef = schema[columnName];
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
"snapshot",
|
|
318
|
-
"metadata",
|
|
319
|
-
"content",
|
|
320
|
-
"input",
|
|
321
|
-
"output",
|
|
322
|
-
"instructions",
|
|
323
|
-
"other"
|
|
324
|
-
];
|
|
325
|
-
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
411
|
+
const useLargeStorage = this.LARGE_DATA_COLUMNS.includes(columnName);
|
|
412
|
+
const useSmallStorage = this.COMPOSITE_INDEX_COLUMNS.includes(columnName);
|
|
326
413
|
const isIndexed = !!columnDef.primaryKey;
|
|
327
|
-
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
328
|
-
const nullable = columnDef.nullable
|
|
329
|
-
const defaultValue = columnDef.nullable
|
|
414
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage, useSmallStorage);
|
|
415
|
+
const nullable = columnDef.nullable ? "" : "NOT NULL";
|
|
416
|
+
const defaultValue = !columnDef.nullable ? this.getDefaultValue(columnDef.type) : "";
|
|
330
417
|
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
331
418
|
const alterSql = `ALTER TABLE ${fullTableName} ADD [${parsedColumnName}] ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
332
419
|
await this.pool.request().query(alterSql);
|
|
@@ -910,84 +997,6 @@ ${columns}
|
|
|
910
997
|
);
|
|
911
998
|
}
|
|
912
999
|
}
|
|
913
|
-
/**
|
|
914
|
-
* Returns definitions for automatic performance indexes
|
|
915
|
-
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
916
|
-
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
917
|
-
*/
|
|
918
|
-
getAutomaticIndexDefinitions() {
|
|
919
|
-
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
920
|
-
return [
|
|
921
|
-
// Composite indexes for optimal filtering + sorting performance
|
|
922
|
-
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
923
|
-
{
|
|
924
|
-
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
925
|
-
table: TABLE_THREADS,
|
|
926
|
-
columns: ["resourceId", "seq_id DESC"]
|
|
927
|
-
},
|
|
928
|
-
{
|
|
929
|
-
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
930
|
-
table: TABLE_MESSAGES,
|
|
931
|
-
columns: ["thread_id", "seq_id DESC"]
|
|
932
|
-
},
|
|
933
|
-
{
|
|
934
|
-
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
935
|
-
table: TABLE_TRACES,
|
|
936
|
-
columns: ["name", "seq_id DESC"]
|
|
937
|
-
},
|
|
938
|
-
{
|
|
939
|
-
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
940
|
-
table: TABLE_SCORERS,
|
|
941
|
-
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
942
|
-
},
|
|
943
|
-
// Spans indexes for optimal trace querying
|
|
944
|
-
{
|
|
945
|
-
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
946
|
-
table: TABLE_SPANS,
|
|
947
|
-
columns: ["traceId", "startedAt DESC"]
|
|
948
|
-
},
|
|
949
|
-
{
|
|
950
|
-
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
951
|
-
table: TABLE_SPANS,
|
|
952
|
-
columns: ["parentSpanId", "startedAt DESC"]
|
|
953
|
-
},
|
|
954
|
-
{
|
|
955
|
-
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
956
|
-
table: TABLE_SPANS,
|
|
957
|
-
columns: ["name"]
|
|
958
|
-
},
|
|
959
|
-
{
|
|
960
|
-
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
961
|
-
table: TABLE_SPANS,
|
|
962
|
-
columns: ["spanType", "startedAt DESC"]
|
|
963
|
-
}
|
|
964
|
-
];
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* Creates automatic indexes for optimal query performance
|
|
968
|
-
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
969
|
-
*/
|
|
970
|
-
async createAutomaticIndexes() {
|
|
971
|
-
try {
|
|
972
|
-
const indexes = this.getAutomaticIndexDefinitions();
|
|
973
|
-
for (const indexOptions of indexes) {
|
|
974
|
-
try {
|
|
975
|
-
await this.createIndex(indexOptions);
|
|
976
|
-
} catch (error) {
|
|
977
|
-
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
} catch (error) {
|
|
981
|
-
throw new MastraError(
|
|
982
|
-
{
|
|
983
|
-
id: createStorageErrorId("MSSQL", "CREATE_PERFORMANCE_INDEXES", "FAILED"),
|
|
984
|
-
domain: ErrorDomain.STORAGE,
|
|
985
|
-
category: ErrorCategory.THIRD_PARTY
|
|
986
|
-
},
|
|
987
|
-
error
|
|
988
|
-
);
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
1000
|
};
|
|
992
1001
|
function getSchemaName2(schema) {
|
|
993
1002
|
return schema ? `[${parseSqlIdentifier(schema, "schema name")}]` : void 0;
|
|
@@ -1101,11 +1110,15 @@ function transformFromSqlRow({
|
|
|
1101
1110
|
}
|
|
1102
1111
|
|
|
1103
1112
|
// src/storage/domains/memory/index.ts
|
|
1104
|
-
var MemoryMSSQL = class extends MemoryStorage {
|
|
1113
|
+
var MemoryMSSQL = class _MemoryMSSQL extends MemoryStorage {
|
|
1105
1114
|
pool;
|
|
1106
1115
|
schema;
|
|
1107
1116
|
db;
|
|
1108
1117
|
needsConnect;
|
|
1118
|
+
skipDefaultIndexes;
|
|
1119
|
+
indexes;
|
|
1120
|
+
/** Tables managed by this domain */
|
|
1121
|
+
static MANAGED_TABLES = [TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES];
|
|
1109
1122
|
_parseAndFormatMessages(messages, format) {
|
|
1110
1123
|
const messagesWithParsedContent = messages.map((message) => {
|
|
1111
1124
|
if (typeof message.content === "string") {
|
|
@@ -1123,11 +1136,13 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
1123
1136
|
}
|
|
1124
1137
|
constructor(config) {
|
|
1125
1138
|
super();
|
|
1126
|
-
const { pool,
|
|
1139
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
1127
1140
|
this.pool = pool;
|
|
1128
|
-
this.schema =
|
|
1129
|
-
this.db =
|
|
1141
|
+
this.schema = schemaName;
|
|
1142
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
1130
1143
|
this.needsConnect = needsConnect;
|
|
1144
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
1145
|
+
this.indexes = indexes?.filter((idx) => _MemoryMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
1131
1146
|
}
|
|
1132
1147
|
async init() {
|
|
1133
1148
|
if (this.needsConnect) {
|
|
@@ -1137,6 +1152,57 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
1137
1152
|
await this.db.createTable({ tableName: TABLE_THREADS, schema: TABLE_SCHEMAS[TABLE_THREADS] });
|
|
1138
1153
|
await this.db.createTable({ tableName: TABLE_MESSAGES, schema: TABLE_SCHEMAS[TABLE_MESSAGES] });
|
|
1139
1154
|
await this.db.createTable({ tableName: TABLE_RESOURCES, schema: TABLE_SCHEMAS[TABLE_RESOURCES] });
|
|
1155
|
+
await this.createDefaultIndexes();
|
|
1156
|
+
await this.createCustomIndexes();
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Returns default index definitions for the memory domain tables.
|
|
1160
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
1161
|
+
*/
|
|
1162
|
+
getDefaultIndexDefinitions() {
|
|
1163
|
+
const schemaPrefix = this.schema ? `${this.schema}_` : "";
|
|
1164
|
+
return [
|
|
1165
|
+
{
|
|
1166
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
1167
|
+
table: TABLE_THREADS,
|
|
1168
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
1172
|
+
table: TABLE_MESSAGES,
|
|
1173
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
1174
|
+
}
|
|
1175
|
+
];
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Creates default indexes for optimal query performance.
|
|
1179
|
+
*/
|
|
1180
|
+
async createDefaultIndexes() {
|
|
1181
|
+
if (this.skipDefaultIndexes) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
1185
|
+
try {
|
|
1186
|
+
await this.db.createIndex(indexDef);
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
1194
|
+
*/
|
|
1195
|
+
async createCustomIndexes() {
|
|
1196
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
for (const indexDef of this.indexes) {
|
|
1200
|
+
try {
|
|
1201
|
+
await this.db.createIndex(indexDef);
|
|
1202
|
+
} catch (error) {
|
|
1203
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1140
1206
|
}
|
|
1141
1207
|
async dangerouslyClearAll() {
|
|
1142
1208
|
await this.db.clearTable({ tableName: TABLE_MESSAGES });
|
|
@@ -2015,18 +2081,24 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
2015
2081
|
}
|
|
2016
2082
|
}
|
|
2017
2083
|
};
|
|
2018
|
-
var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
2084
|
+
var ObservabilityMSSQL = class _ObservabilityMSSQL extends ObservabilityStorage {
|
|
2019
2085
|
pool;
|
|
2020
2086
|
db;
|
|
2021
2087
|
schema;
|
|
2022
2088
|
needsConnect;
|
|
2089
|
+
skipDefaultIndexes;
|
|
2090
|
+
indexes;
|
|
2091
|
+
/** Tables managed by this domain */
|
|
2092
|
+
static MANAGED_TABLES = [TABLE_SPANS];
|
|
2023
2093
|
constructor(config) {
|
|
2024
2094
|
super();
|
|
2025
|
-
const { pool,
|
|
2095
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
2026
2096
|
this.pool = pool;
|
|
2027
|
-
this.
|
|
2028
|
-
this.
|
|
2097
|
+
this.schema = schemaName;
|
|
2098
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
2029
2099
|
this.needsConnect = needsConnect;
|
|
2100
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
2101
|
+
this.indexes = indexes?.filter((idx) => _ObservabilityMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
2030
2102
|
}
|
|
2031
2103
|
async init() {
|
|
2032
2104
|
if (this.needsConnect) {
|
|
@@ -2034,6 +2106,92 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2034
2106
|
this.needsConnect = false;
|
|
2035
2107
|
}
|
|
2036
2108
|
await this.db.createTable({ tableName: TABLE_SPANS, schema: SPAN_SCHEMA });
|
|
2109
|
+
await this.createDefaultIndexes();
|
|
2110
|
+
await this.createCustomIndexes();
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Returns default index definitions for the observability domain tables.
|
|
2114
|
+
*/
|
|
2115
|
+
getDefaultIndexDefinitions() {
|
|
2116
|
+
const schemaPrefix = this.schema ? `${this.schema}_` : "";
|
|
2117
|
+
return [
|
|
2118
|
+
{
|
|
2119
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2120
|
+
table: TABLE_SPANS,
|
|
2121
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2122
|
+
},
|
|
2123
|
+
{
|
|
2124
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2125
|
+
table: TABLE_SPANS,
|
|
2126
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2127
|
+
},
|
|
2128
|
+
{
|
|
2129
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2130
|
+
table: TABLE_SPANS,
|
|
2131
|
+
columns: ["name"]
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2135
|
+
table: TABLE_SPANS,
|
|
2136
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2137
|
+
},
|
|
2138
|
+
// Root spans filtered index - every listTraces query filters parentSpanId IS NULL
|
|
2139
|
+
{
|
|
2140
|
+
name: `${schemaPrefix}mastra_ai_spans_root_spans_idx`,
|
|
2141
|
+
table: TABLE_SPANS,
|
|
2142
|
+
columns: ["startedAt DESC"],
|
|
2143
|
+
where: "[parentSpanId] IS NULL"
|
|
2144
|
+
},
|
|
2145
|
+
// Entity identification indexes - common filtering patterns
|
|
2146
|
+
{
|
|
2147
|
+
name: `${schemaPrefix}mastra_ai_spans_entitytype_entityid_idx`,
|
|
2148
|
+
table: TABLE_SPANS,
|
|
2149
|
+
columns: ["entityType", "entityId"]
|
|
2150
|
+
},
|
|
2151
|
+
{
|
|
2152
|
+
name: `${schemaPrefix}mastra_ai_spans_entitytype_entityname_idx`,
|
|
2153
|
+
table: TABLE_SPANS,
|
|
2154
|
+
columns: ["entityType", "entityName"]
|
|
2155
|
+
},
|
|
2156
|
+
// Multi-tenant filtering - organizationId + userId
|
|
2157
|
+
{
|
|
2158
|
+
name: `${schemaPrefix}mastra_ai_spans_orgid_userid_idx`,
|
|
2159
|
+
table: TABLE_SPANS,
|
|
2160
|
+
columns: ["organizationId", "userId"]
|
|
2161
|
+
}
|
|
2162
|
+
// Note: MSSQL doesn't support GIN indexes for JSONB/array containment queries
|
|
2163
|
+
// Metadata and tags filtering will use full table scans on NVARCHAR(MAX) columns
|
|
2164
|
+
];
|
|
2165
|
+
}
|
|
2166
|
+
/**
|
|
2167
|
+
* Creates default indexes for optimal query performance.
|
|
2168
|
+
*/
|
|
2169
|
+
async createDefaultIndexes() {
|
|
2170
|
+
if (this.skipDefaultIndexes) {
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
2174
|
+
try {
|
|
2175
|
+
await this.db.createIndex(indexDef);
|
|
2176
|
+
} catch (error) {
|
|
2177
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
2183
|
+
*/
|
|
2184
|
+
async createCustomIndexes() {
|
|
2185
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
for (const indexDef of this.indexes) {
|
|
2189
|
+
try {
|
|
2190
|
+
await this.db.createIndex(indexDef);
|
|
2191
|
+
} catch (error) {
|
|
2192
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2037
2195
|
}
|
|
2038
2196
|
async dangerouslyClearAll() {
|
|
2039
2197
|
await this.db.clearTable({ tableName: TABLE_SPANS });
|
|
@@ -2044,15 +2202,18 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2044
2202
|
supported: ["batch-with-updates", "insert-only"]
|
|
2045
2203
|
};
|
|
2046
2204
|
}
|
|
2047
|
-
async createSpan(
|
|
2205
|
+
async createSpan(args) {
|
|
2206
|
+
const { span } = args;
|
|
2048
2207
|
try {
|
|
2049
2208
|
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
2050
2209
|
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
2210
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2051
2211
|
const record = {
|
|
2052
2212
|
...span,
|
|
2053
2213
|
startedAt,
|
|
2054
|
-
endedAt
|
|
2055
|
-
|
|
2214
|
+
endedAt,
|
|
2215
|
+
createdAt: now,
|
|
2216
|
+
updatedAt: now
|
|
2056
2217
|
};
|
|
2057
2218
|
return this.db.insert({ tableName: TABLE_SPANS, record });
|
|
2058
2219
|
} catch (error) {
|
|
@@ -2065,14 +2226,15 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2065
2226
|
spanId: span.spanId,
|
|
2066
2227
|
traceId: span.traceId,
|
|
2067
2228
|
spanType: span.spanType,
|
|
2068
|
-
|
|
2229
|
+
name: span.name
|
|
2069
2230
|
}
|
|
2070
2231
|
},
|
|
2071
2232
|
error
|
|
2072
2233
|
);
|
|
2073
2234
|
}
|
|
2074
2235
|
}
|
|
2075
|
-
async getTrace(
|
|
2236
|
+
async getTrace(args) {
|
|
2237
|
+
const { traceId } = args;
|
|
2076
2238
|
try {
|
|
2077
2239
|
const tableName = getTableName2({
|
|
2078
2240
|
indexName: TABLE_SPANS,
|
|
@@ -2082,12 +2244,17 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2082
2244
|
request.input("traceId", traceId);
|
|
2083
2245
|
const result = await request.query(
|
|
2084
2246
|
`SELECT
|
|
2085
|
-
[traceId], [spanId], [parentSpanId], [name],
|
|
2086
|
-
[
|
|
2247
|
+
[traceId], [spanId], [parentSpanId], [name],
|
|
2248
|
+
[entityType], [entityId], [entityName],
|
|
2249
|
+
[userId], [organizationId], [resourceId],
|
|
2250
|
+
[runId], [sessionId], [threadId], [requestId],
|
|
2251
|
+
[environment], [source], [serviceName], [scope],
|
|
2252
|
+
[spanType], [attributes], [metadata], [tags], [links],
|
|
2253
|
+
[input], [output], [error], [isEvent],
|
|
2087
2254
|
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
2088
2255
|
FROM ${tableName}
|
|
2089
2256
|
WHERE [traceId] = @traceId
|
|
2090
|
-
ORDER BY [startedAt]
|
|
2257
|
+
ORDER BY [startedAt] ASC`
|
|
2091
2258
|
);
|
|
2092
2259
|
if (!result.recordset || result.recordset.length === 0) {
|
|
2093
2260
|
return null;
|
|
@@ -2115,11 +2282,95 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2115
2282
|
);
|
|
2116
2283
|
}
|
|
2117
2284
|
}
|
|
2118
|
-
async
|
|
2119
|
-
spanId
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2285
|
+
async getSpan(args) {
|
|
2286
|
+
const { traceId, spanId } = args;
|
|
2287
|
+
try {
|
|
2288
|
+
const tableName = getTableName2({
|
|
2289
|
+
indexName: TABLE_SPANS,
|
|
2290
|
+
schemaName: getSchemaName2(this.schema)
|
|
2291
|
+
});
|
|
2292
|
+
const request = this.pool.request();
|
|
2293
|
+
request.input("traceId", traceId);
|
|
2294
|
+
request.input("spanId", spanId);
|
|
2295
|
+
const result = await request.query(
|
|
2296
|
+
`SELECT
|
|
2297
|
+
[traceId], [spanId], [parentSpanId], [name],
|
|
2298
|
+
[entityType], [entityId], [entityName],
|
|
2299
|
+
[userId], [organizationId], [resourceId],
|
|
2300
|
+
[runId], [sessionId], [threadId], [requestId],
|
|
2301
|
+
[environment], [source], [serviceName], [scope],
|
|
2302
|
+
[spanType], [attributes], [metadata], [tags], [links],
|
|
2303
|
+
[input], [output], [error], [isEvent],
|
|
2304
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
2305
|
+
FROM ${tableName}
|
|
2306
|
+
WHERE [traceId] = @traceId AND [spanId] = @spanId`
|
|
2307
|
+
);
|
|
2308
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2309
|
+
return null;
|
|
2310
|
+
}
|
|
2311
|
+
return {
|
|
2312
|
+
span: transformFromSqlRow({
|
|
2313
|
+
tableName: TABLE_SPANS,
|
|
2314
|
+
sqlRow: result.recordset[0]
|
|
2315
|
+
})
|
|
2316
|
+
};
|
|
2317
|
+
} catch (error) {
|
|
2318
|
+
throw new MastraError(
|
|
2319
|
+
{
|
|
2320
|
+
id: createStorageErrorId("MSSQL", "GET_SPAN", "FAILED"),
|
|
2321
|
+
domain: ErrorDomain.STORAGE,
|
|
2322
|
+
category: ErrorCategory.USER,
|
|
2323
|
+
details: { traceId, spanId }
|
|
2324
|
+
},
|
|
2325
|
+
error
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
async getRootSpan(args) {
|
|
2330
|
+
const { traceId } = args;
|
|
2331
|
+
try {
|
|
2332
|
+
const tableName = getTableName2({
|
|
2333
|
+
indexName: TABLE_SPANS,
|
|
2334
|
+
schemaName: getSchemaName2(this.schema)
|
|
2335
|
+
});
|
|
2336
|
+
const request = this.pool.request();
|
|
2337
|
+
request.input("traceId", traceId);
|
|
2338
|
+
const result = await request.query(
|
|
2339
|
+
`SELECT
|
|
2340
|
+
[traceId], [spanId], [parentSpanId], [name],
|
|
2341
|
+
[entityType], [entityId], [entityName],
|
|
2342
|
+
[userId], [organizationId], [resourceId],
|
|
2343
|
+
[runId], [sessionId], [threadId], [requestId],
|
|
2344
|
+
[environment], [source], [serviceName], [scope],
|
|
2345
|
+
[spanType], [attributes], [metadata], [tags], [links],
|
|
2346
|
+
[input], [output], [error], [isEvent],
|
|
2347
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
2348
|
+
FROM ${tableName}
|
|
2349
|
+
WHERE [traceId] = @traceId AND [parentSpanId] IS NULL`
|
|
2350
|
+
);
|
|
2351
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2352
|
+
return null;
|
|
2353
|
+
}
|
|
2354
|
+
return {
|
|
2355
|
+
span: transformFromSqlRow({
|
|
2356
|
+
tableName: TABLE_SPANS,
|
|
2357
|
+
sqlRow: result.recordset[0]
|
|
2358
|
+
})
|
|
2359
|
+
};
|
|
2360
|
+
} catch (error) {
|
|
2361
|
+
throw new MastraError(
|
|
2362
|
+
{
|
|
2363
|
+
id: createStorageErrorId("MSSQL", "GET_ROOT_SPAN", "FAILED"),
|
|
2364
|
+
domain: ErrorDomain.STORAGE,
|
|
2365
|
+
category: ErrorCategory.USER,
|
|
2366
|
+
details: { traceId }
|
|
2367
|
+
},
|
|
2368
|
+
error
|
|
2369
|
+
);
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
async updateSpan(args) {
|
|
2373
|
+
const { traceId, spanId, updates } = args;
|
|
2123
2374
|
try {
|
|
2124
2375
|
const data = { ...updates };
|
|
2125
2376
|
if (data.endedAt instanceof Date) {
|
|
@@ -2128,6 +2379,7 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2128
2379
|
if (data.startedAt instanceof Date) {
|
|
2129
2380
|
data.startedAt = data.startedAt.toISOString();
|
|
2130
2381
|
}
|
|
2382
|
+
data.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2131
2383
|
await this.db.update({
|
|
2132
2384
|
tableName: TABLE_SPANS,
|
|
2133
2385
|
keys: { spanId, traceId },
|
|
@@ -2148,63 +2400,184 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2148
2400
|
);
|
|
2149
2401
|
}
|
|
2150
2402
|
}
|
|
2151
|
-
async
|
|
2152
|
-
filters,
|
|
2153
|
-
pagination
|
|
2154
|
-
}) {
|
|
2155
|
-
const page = pagination?.page ?? 0;
|
|
2156
|
-
const perPage = pagination?.perPage ?? 10;
|
|
2157
|
-
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
2158
|
-
const filtersWithDateRange = {
|
|
2159
|
-
...actualFilters,
|
|
2160
|
-
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
2161
|
-
parentSpanId: null
|
|
2162
|
-
// Only get root spans for traces
|
|
2163
|
-
};
|
|
2164
|
-
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
2165
|
-
let actualWhereClause = whereClause.sql;
|
|
2166
|
-
const params = { ...whereClause.params };
|
|
2167
|
-
let currentParamIndex = Object.keys(params).length + 1;
|
|
2168
|
-
if (entityId && entityType) {
|
|
2169
|
-
let name = "";
|
|
2170
|
-
if (entityType === "workflow") {
|
|
2171
|
-
name = `workflow run: '${entityId}'`;
|
|
2172
|
-
} else if (entityType === "agent") {
|
|
2173
|
-
name = `agent run: '${entityId}'`;
|
|
2174
|
-
} else {
|
|
2175
|
-
const error = new MastraError({
|
|
2176
|
-
id: createStorageErrorId("MSSQL", "GET_TRACES_PAGINATED", "INVALID_ENTITY_TYPE"),
|
|
2177
|
-
domain: ErrorDomain.STORAGE,
|
|
2178
|
-
category: ErrorCategory.USER,
|
|
2179
|
-
details: {
|
|
2180
|
-
entityType
|
|
2181
|
-
},
|
|
2182
|
-
text: `Cannot filter by entity type: ${entityType}`
|
|
2183
|
-
});
|
|
2184
|
-
throw error;
|
|
2185
|
-
}
|
|
2186
|
-
const entityParam = `p${currentParamIndex++}`;
|
|
2187
|
-
if (actualWhereClause) {
|
|
2188
|
-
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
2189
|
-
} else {
|
|
2190
|
-
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
2191
|
-
}
|
|
2192
|
-
params[entityParam] = name;
|
|
2193
|
-
}
|
|
2403
|
+
async listTraces(args) {
|
|
2404
|
+
const { filters, pagination, orderBy } = listTracesArgsSchema.parse(args);
|
|
2405
|
+
const { page, perPage } = pagination;
|
|
2194
2406
|
const tableName = getTableName2({
|
|
2195
2407
|
indexName: TABLE_SPANS,
|
|
2196
2408
|
schemaName: getSchemaName2(this.schema)
|
|
2197
2409
|
});
|
|
2198
2410
|
try {
|
|
2411
|
+
const conditions = ["r.[parentSpanId] IS NULL"];
|
|
2412
|
+
const params = {};
|
|
2413
|
+
let paramIndex = 1;
|
|
2414
|
+
if (filters) {
|
|
2415
|
+
if (filters.startedAt?.start) {
|
|
2416
|
+
const param = `p${paramIndex++}`;
|
|
2417
|
+
conditions.push(`r.[startedAt] >= @${param}`);
|
|
2418
|
+
params[param] = filters.startedAt.start.toISOString();
|
|
2419
|
+
}
|
|
2420
|
+
if (filters.startedAt?.end) {
|
|
2421
|
+
const param = `p${paramIndex++}`;
|
|
2422
|
+
conditions.push(`r.[startedAt] <= @${param}`);
|
|
2423
|
+
params[param] = filters.startedAt.end.toISOString();
|
|
2424
|
+
}
|
|
2425
|
+
if (filters.endedAt?.start) {
|
|
2426
|
+
const param = `p${paramIndex++}`;
|
|
2427
|
+
conditions.push(`r.[endedAt] >= @${param}`);
|
|
2428
|
+
params[param] = filters.endedAt.start.toISOString();
|
|
2429
|
+
}
|
|
2430
|
+
if (filters.endedAt?.end) {
|
|
2431
|
+
const param = `p${paramIndex++}`;
|
|
2432
|
+
conditions.push(`r.[endedAt] <= @${param}`);
|
|
2433
|
+
params[param] = filters.endedAt.end.toISOString();
|
|
2434
|
+
}
|
|
2435
|
+
if (filters.spanType !== void 0) {
|
|
2436
|
+
const param = `p${paramIndex++}`;
|
|
2437
|
+
conditions.push(`r.[spanType] = @${param}`);
|
|
2438
|
+
params[param] = filters.spanType;
|
|
2439
|
+
}
|
|
2440
|
+
if (filters.entityType !== void 0) {
|
|
2441
|
+
const param = `p${paramIndex++}`;
|
|
2442
|
+
conditions.push(`r.[entityType] = @${param}`);
|
|
2443
|
+
params[param] = filters.entityType;
|
|
2444
|
+
}
|
|
2445
|
+
if (filters.entityId !== void 0) {
|
|
2446
|
+
const param = `p${paramIndex++}`;
|
|
2447
|
+
conditions.push(`r.[entityId] = @${param}`);
|
|
2448
|
+
params[param] = filters.entityId;
|
|
2449
|
+
}
|
|
2450
|
+
if (filters.entityName !== void 0) {
|
|
2451
|
+
const param = `p${paramIndex++}`;
|
|
2452
|
+
conditions.push(`r.[entityName] = @${param}`);
|
|
2453
|
+
params[param] = filters.entityName;
|
|
2454
|
+
}
|
|
2455
|
+
if (filters.userId !== void 0) {
|
|
2456
|
+
const param = `p${paramIndex++}`;
|
|
2457
|
+
conditions.push(`r.[userId] = @${param}`);
|
|
2458
|
+
params[param] = filters.userId;
|
|
2459
|
+
}
|
|
2460
|
+
if (filters.organizationId !== void 0) {
|
|
2461
|
+
const param = `p${paramIndex++}`;
|
|
2462
|
+
conditions.push(`r.[organizationId] = @${param}`);
|
|
2463
|
+
params[param] = filters.organizationId;
|
|
2464
|
+
}
|
|
2465
|
+
if (filters.resourceId !== void 0) {
|
|
2466
|
+
const param = `p${paramIndex++}`;
|
|
2467
|
+
conditions.push(`r.[resourceId] = @${param}`);
|
|
2468
|
+
params[param] = filters.resourceId;
|
|
2469
|
+
}
|
|
2470
|
+
if (filters.runId !== void 0) {
|
|
2471
|
+
const param = `p${paramIndex++}`;
|
|
2472
|
+
conditions.push(`r.[runId] = @${param}`);
|
|
2473
|
+
params[param] = filters.runId;
|
|
2474
|
+
}
|
|
2475
|
+
if (filters.sessionId !== void 0) {
|
|
2476
|
+
const param = `p${paramIndex++}`;
|
|
2477
|
+
conditions.push(`r.[sessionId] = @${param}`);
|
|
2478
|
+
params[param] = filters.sessionId;
|
|
2479
|
+
}
|
|
2480
|
+
if (filters.threadId !== void 0) {
|
|
2481
|
+
const param = `p${paramIndex++}`;
|
|
2482
|
+
conditions.push(`r.[threadId] = @${param}`);
|
|
2483
|
+
params[param] = filters.threadId;
|
|
2484
|
+
}
|
|
2485
|
+
if (filters.requestId !== void 0) {
|
|
2486
|
+
const param = `p${paramIndex++}`;
|
|
2487
|
+
conditions.push(`r.[requestId] = @${param}`);
|
|
2488
|
+
params[param] = filters.requestId;
|
|
2489
|
+
}
|
|
2490
|
+
if (filters.environment !== void 0) {
|
|
2491
|
+
const param = `p${paramIndex++}`;
|
|
2492
|
+
conditions.push(`r.[environment] = @${param}`);
|
|
2493
|
+
params[param] = filters.environment;
|
|
2494
|
+
}
|
|
2495
|
+
if (filters.source !== void 0) {
|
|
2496
|
+
const param = `p${paramIndex++}`;
|
|
2497
|
+
conditions.push(`r.[source] = @${param}`);
|
|
2498
|
+
params[param] = filters.source;
|
|
2499
|
+
}
|
|
2500
|
+
if (filters.serviceName !== void 0) {
|
|
2501
|
+
const param = `p${paramIndex++}`;
|
|
2502
|
+
conditions.push(`r.[serviceName] = @${param}`);
|
|
2503
|
+
params[param] = filters.serviceName;
|
|
2504
|
+
}
|
|
2505
|
+
if (filters.scope != null) {
|
|
2506
|
+
for (const [key, value] of Object.entries(filters.scope)) {
|
|
2507
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
|
|
2508
|
+
throw new MastraError({
|
|
2509
|
+
id: createStorageErrorId("MSSQL", "LIST_TRACES", "INVALID_FILTER_KEY"),
|
|
2510
|
+
domain: ErrorDomain.STORAGE,
|
|
2511
|
+
category: ErrorCategory.USER,
|
|
2512
|
+
details: { key }
|
|
2513
|
+
});
|
|
2514
|
+
}
|
|
2515
|
+
const param = `p${paramIndex++}`;
|
|
2516
|
+
conditions.push(`JSON_VALUE(r.[scope], '$.${key}') = @${param}`);
|
|
2517
|
+
params[param] = typeof value === "string" ? value : JSON.stringify(value);
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
if (filters.metadata != null) {
|
|
2521
|
+
for (const [key, value] of Object.entries(filters.metadata)) {
|
|
2522
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
|
|
2523
|
+
throw new MastraError({
|
|
2524
|
+
id: createStorageErrorId("MSSQL", "LIST_TRACES", "INVALID_FILTER_KEY"),
|
|
2525
|
+
domain: ErrorDomain.STORAGE,
|
|
2526
|
+
category: ErrorCategory.USER,
|
|
2527
|
+
details: { key }
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2530
|
+
const param = `p${paramIndex++}`;
|
|
2531
|
+
conditions.push(`JSON_VALUE(r.[metadata], '$.${key}') = @${param}`);
|
|
2532
|
+
params[param] = typeof value === "string" ? value : JSON.stringify(value);
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
if (filters.tags != null && filters.tags.length > 0) {
|
|
2536
|
+
for (const tag of filters.tags) {
|
|
2537
|
+
const param = `p${paramIndex++}`;
|
|
2538
|
+
conditions.push(`EXISTS (SELECT 1 FROM OPENJSON(r.[tags]) WHERE [value] = @${param})`);
|
|
2539
|
+
params[param] = tag;
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
if (filters.status !== void 0) {
|
|
2543
|
+
switch (filters.status) {
|
|
2544
|
+
case TraceStatus.ERROR:
|
|
2545
|
+
conditions.push(`r.[error] IS NOT NULL`);
|
|
2546
|
+
break;
|
|
2547
|
+
case TraceStatus.RUNNING:
|
|
2548
|
+
conditions.push(`r.[endedAt] IS NULL AND r.[error] IS NULL`);
|
|
2549
|
+
break;
|
|
2550
|
+
case TraceStatus.SUCCESS:
|
|
2551
|
+
conditions.push(`r.[endedAt] IS NOT NULL AND r.[error] IS NULL`);
|
|
2552
|
+
break;
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
if (filters.hasChildError !== void 0) {
|
|
2556
|
+
if (filters.hasChildError) {
|
|
2557
|
+
conditions.push(`EXISTS (
|
|
2558
|
+
SELECT 1 FROM ${tableName} c
|
|
2559
|
+
WHERE c.[traceId] = r.[traceId] AND c.[error] IS NOT NULL
|
|
2560
|
+
)`);
|
|
2561
|
+
} else {
|
|
2562
|
+
conditions.push(`NOT EXISTS (
|
|
2563
|
+
SELECT 1 FROM ${tableName} c
|
|
2564
|
+
WHERE c.[traceId] = r.[traceId] AND c.[error] IS NOT NULL
|
|
2565
|
+
)`);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2570
|
+
const sortField = orderBy.field;
|
|
2571
|
+
const sortDirection = orderBy.direction;
|
|
2199
2572
|
const countRequest = this.pool.request();
|
|
2200
2573
|
Object.entries(params).forEach(([key, value]) => {
|
|
2201
2574
|
countRequest.input(key, value);
|
|
2202
2575
|
});
|
|
2203
2576
|
const countResult = await countRequest.query(
|
|
2204
|
-
`SELECT COUNT(*) as count FROM ${tableName}${
|
|
2577
|
+
`SELECT COUNT(*) as count FROM ${tableName} r ${whereClause}`
|
|
2205
2578
|
);
|
|
2206
|
-
const
|
|
2207
|
-
if (
|
|
2579
|
+
const count = countResult.recordset[0]?.count ?? 0;
|
|
2580
|
+
if (count === 0) {
|
|
2208
2581
|
return {
|
|
2209
2582
|
pagination: {
|
|
2210
2583
|
total: 0,
|
|
@@ -2221,28 +2594,39 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2221
2594
|
});
|
|
2222
2595
|
dataRequest.input("offset", page * perPage);
|
|
2223
2596
|
dataRequest.input("limit", perPage);
|
|
2224
|
-
const
|
|
2225
|
-
`SELECT
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2597
|
+
const result = await dataRequest.query(
|
|
2598
|
+
`SELECT
|
|
2599
|
+
r.[traceId], r.[spanId], r.[parentSpanId], r.[name],
|
|
2600
|
+
r.[entityType], r.[entityId], r.[entityName],
|
|
2601
|
+
r.[userId], r.[organizationId], r.[resourceId],
|
|
2602
|
+
r.[runId], r.[sessionId], r.[threadId], r.[requestId],
|
|
2603
|
+
r.[environment], r.[source], r.[serviceName], r.[scope],
|
|
2604
|
+
r.[spanType], r.[attributes], r.[metadata], r.[tags], r.[links],
|
|
2605
|
+
r.[input], r.[output], r.[error], r.[isEvent],
|
|
2606
|
+
r.[startedAt], r.[endedAt], r.[createdAt], r.[updatedAt]
|
|
2607
|
+
FROM ${tableName} r
|
|
2608
|
+
${whereClause}
|
|
2609
|
+
ORDER BY r.[${sortField}] ${sortDirection}
|
|
2610
|
+
OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
2232
2611
|
);
|
|
2233
2612
|
return {
|
|
2234
2613
|
pagination: {
|
|
2235
|
-
total,
|
|
2614
|
+
total: count,
|
|
2236
2615
|
page,
|
|
2237
2616
|
perPage,
|
|
2238
|
-
hasMore: (page + 1) * perPage <
|
|
2617
|
+
hasMore: (page + 1) * perPage < count
|
|
2239
2618
|
},
|
|
2240
|
-
spans
|
|
2619
|
+
spans: result.recordset.map(
|
|
2620
|
+
(span) => transformFromSqlRow({
|
|
2621
|
+
tableName: TABLE_SPANS,
|
|
2622
|
+
sqlRow: span
|
|
2623
|
+
})
|
|
2624
|
+
)
|
|
2241
2625
|
};
|
|
2242
2626
|
} catch (error) {
|
|
2243
2627
|
throw new MastraError(
|
|
2244
2628
|
{
|
|
2245
|
-
id: createStorageErrorId("MSSQL", "
|
|
2629
|
+
id: createStorageErrorId("MSSQL", "LIST_TRACES", "FAILED"),
|
|
2246
2630
|
domain: ErrorDomain.STORAGE,
|
|
2247
2631
|
category: ErrorCategory.USER
|
|
2248
2632
|
},
|
|
@@ -2255,12 +2639,15 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2255
2639
|
return;
|
|
2256
2640
|
}
|
|
2257
2641
|
try {
|
|
2642
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2258
2643
|
await this.db.batchInsert({
|
|
2259
2644
|
tableName: TABLE_SPANS,
|
|
2260
2645
|
records: args.records.map((span) => ({
|
|
2261
2646
|
...span,
|
|
2262
2647
|
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
2263
|
-
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
2648
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt,
|
|
2649
|
+
createdAt: now,
|
|
2650
|
+
updatedAt: now
|
|
2264
2651
|
}))
|
|
2265
2652
|
});
|
|
2266
2653
|
} catch (error) {
|
|
@@ -2281,6 +2668,7 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2281
2668
|
if (!args.records || args.records.length === 0) {
|
|
2282
2669
|
return;
|
|
2283
2670
|
}
|
|
2671
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2284
2672
|
try {
|
|
2285
2673
|
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
2286
2674
|
const processedData = { ...data };
|
|
@@ -2290,6 +2678,7 @@ var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
|
2290
2678
|
if (processedData.startedAt instanceof Date) {
|
|
2291
2679
|
processedData.startedAt = processedData.startedAt.toISOString();
|
|
2292
2680
|
}
|
|
2681
|
+
processedData.updatedAt = now;
|
|
2293
2682
|
return {
|
|
2294
2683
|
keys: { spanId, traceId },
|
|
2295
2684
|
data: processedData
|
|
@@ -2343,18 +2732,24 @@ function transformScoreRow(row) {
|
|
|
2343
2732
|
convertTimestamps: true
|
|
2344
2733
|
});
|
|
2345
2734
|
}
|
|
2346
|
-
var ScoresMSSQL = class extends ScoresStorage {
|
|
2735
|
+
var ScoresMSSQL = class _ScoresMSSQL extends ScoresStorage {
|
|
2347
2736
|
pool;
|
|
2348
2737
|
db;
|
|
2349
2738
|
schema;
|
|
2350
2739
|
needsConnect;
|
|
2740
|
+
skipDefaultIndexes;
|
|
2741
|
+
indexes;
|
|
2742
|
+
/** Tables managed by this domain */
|
|
2743
|
+
static MANAGED_TABLES = [TABLE_SCORERS];
|
|
2351
2744
|
constructor(config) {
|
|
2352
2745
|
super();
|
|
2353
|
-
const { pool,
|
|
2746
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
2354
2747
|
this.pool = pool;
|
|
2355
|
-
this.
|
|
2356
|
-
this.
|
|
2748
|
+
this.schema = schemaName;
|
|
2749
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
2357
2750
|
this.needsConnect = needsConnect;
|
|
2751
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
2752
|
+
this.indexes = indexes?.filter((idx) => _ScoresMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
2358
2753
|
}
|
|
2359
2754
|
async init() {
|
|
2360
2755
|
if (this.needsConnect) {
|
|
@@ -2362,6 +2757,52 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
2362
2757
|
this.needsConnect = false;
|
|
2363
2758
|
}
|
|
2364
2759
|
await this.db.createTable({ tableName: TABLE_SCORERS, schema: TABLE_SCHEMAS[TABLE_SCORERS] });
|
|
2760
|
+
await this.createDefaultIndexes();
|
|
2761
|
+
await this.createCustomIndexes();
|
|
2762
|
+
}
|
|
2763
|
+
/**
|
|
2764
|
+
* Returns default index definitions for the scores domain tables.
|
|
2765
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2766
|
+
*/
|
|
2767
|
+
getDefaultIndexDefinitions() {
|
|
2768
|
+
const schemaPrefix = this.schema ? `${this.schema}_` : "";
|
|
2769
|
+
return [
|
|
2770
|
+
{
|
|
2771
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2772
|
+
table: TABLE_SCORERS,
|
|
2773
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2774
|
+
}
|
|
2775
|
+
];
|
|
2776
|
+
}
|
|
2777
|
+
/**
|
|
2778
|
+
* Creates default indexes for optimal query performance.
|
|
2779
|
+
*/
|
|
2780
|
+
async createDefaultIndexes() {
|
|
2781
|
+
if (this.skipDefaultIndexes) {
|
|
2782
|
+
return;
|
|
2783
|
+
}
|
|
2784
|
+
for (const indexDef of this.getDefaultIndexDefinitions()) {
|
|
2785
|
+
try {
|
|
2786
|
+
await this.db.createIndex(indexDef);
|
|
2787
|
+
} catch (error) {
|
|
2788
|
+
this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
/**
|
|
2793
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
2794
|
+
*/
|
|
2795
|
+
async createCustomIndexes() {
|
|
2796
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
for (const indexDef of this.indexes) {
|
|
2800
|
+
try {
|
|
2801
|
+
await this.db.createIndex(indexDef);
|
|
2802
|
+
} catch (error) {
|
|
2803
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2365
2806
|
}
|
|
2366
2807
|
async dangerouslyClearAll() {
|
|
2367
2808
|
await this.db.clearTable({ tableName: TABLE_SCORERS });
|
|
@@ -2400,7 +2841,7 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
2400
2841
|
domain: ErrorDomain.STORAGE,
|
|
2401
2842
|
category: ErrorCategory.USER,
|
|
2402
2843
|
details: {
|
|
2403
|
-
scorer: score.scorer?.id ?? "unknown",
|
|
2844
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
2404
2845
|
entityId: score.entityId ?? "unknown",
|
|
2405
2846
|
entityType: score.entityType ?? "unknown",
|
|
2406
2847
|
traceId: score.traceId ?? "",
|
|
@@ -2706,18 +3147,40 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
2706
3147
|
}
|
|
2707
3148
|
}
|
|
2708
3149
|
};
|
|
2709
|
-
var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
3150
|
+
var WorkflowsMSSQL = class _WorkflowsMSSQL extends WorkflowsStorage {
|
|
2710
3151
|
pool;
|
|
2711
3152
|
db;
|
|
2712
3153
|
schema;
|
|
2713
3154
|
needsConnect;
|
|
3155
|
+
skipDefaultIndexes;
|
|
3156
|
+
indexes;
|
|
3157
|
+
/** Tables managed by this domain */
|
|
3158
|
+
static MANAGED_TABLES = [TABLE_WORKFLOW_SNAPSHOT];
|
|
2714
3159
|
constructor(config) {
|
|
2715
3160
|
super();
|
|
2716
|
-
const { pool,
|
|
3161
|
+
const { pool, schemaName, skipDefaultIndexes, indexes, needsConnect } = resolveMssqlConfig(config);
|
|
2717
3162
|
this.pool = pool;
|
|
2718
|
-
this.
|
|
2719
|
-
this.
|
|
3163
|
+
this.schema = schemaName;
|
|
3164
|
+
this.db = new MssqlDB({ pool, schemaName, skipDefaultIndexes });
|
|
2720
3165
|
this.needsConnect = needsConnect;
|
|
3166
|
+
this.skipDefaultIndexes = skipDefaultIndexes;
|
|
3167
|
+
this.indexes = indexes?.filter((idx) => _WorkflowsMSSQL.MANAGED_TABLES.includes(idx.table));
|
|
3168
|
+
}
|
|
3169
|
+
/**
|
|
3170
|
+
* Returns default index definitions for the workflows domain tables.
|
|
3171
|
+
* Currently no default indexes are defined for workflows.
|
|
3172
|
+
*/
|
|
3173
|
+
getDefaultIndexDefinitions() {
|
|
3174
|
+
return [];
|
|
3175
|
+
}
|
|
3176
|
+
/**
|
|
3177
|
+
* Creates default indexes for optimal query performance.
|
|
3178
|
+
* Currently no default indexes are defined for workflows.
|
|
3179
|
+
*/
|
|
3180
|
+
async createDefaultIndexes() {
|
|
3181
|
+
if (this.skipDefaultIndexes) {
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
2721
3184
|
}
|
|
2722
3185
|
async init() {
|
|
2723
3186
|
if (this.needsConnect) {
|
|
@@ -2725,6 +3188,23 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2725
3188
|
this.needsConnect = false;
|
|
2726
3189
|
}
|
|
2727
3190
|
await this.db.createTable({ tableName: TABLE_WORKFLOW_SNAPSHOT, schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT] });
|
|
3191
|
+
await this.createDefaultIndexes();
|
|
3192
|
+
await this.createCustomIndexes();
|
|
3193
|
+
}
|
|
3194
|
+
/**
|
|
3195
|
+
* Creates custom user-defined indexes for this domain's tables.
|
|
3196
|
+
*/
|
|
3197
|
+
async createCustomIndexes() {
|
|
3198
|
+
if (!this.indexes || this.indexes.length === 0) {
|
|
3199
|
+
return;
|
|
3200
|
+
}
|
|
3201
|
+
for (const indexDef of this.indexes) {
|
|
3202
|
+
try {
|
|
3203
|
+
await this.db.createIndex(indexDef);
|
|
3204
|
+
} catch (error) {
|
|
3205
|
+
this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
2728
3208
|
}
|
|
2729
3209
|
async dangerouslyClearAll() {
|
|
2730
3210
|
await this.db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
|
|
@@ -3119,7 +3599,6 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
3119
3599
|
pool;
|
|
3120
3600
|
schema;
|
|
3121
3601
|
isConnected = null;
|
|
3122
|
-
#db;
|
|
3123
3602
|
stores;
|
|
3124
3603
|
constructor(config) {
|
|
3125
3604
|
if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
|
|
@@ -3151,8 +3630,12 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
3151
3630
|
options: config.options || { encrypt: true, trustServerCertificate: true }
|
|
3152
3631
|
});
|
|
3153
3632
|
}
|
|
3154
|
-
|
|
3155
|
-
|
|
3633
|
+
const domainConfig = {
|
|
3634
|
+
pool: this.pool,
|
|
3635
|
+
schemaName: this.schema,
|
|
3636
|
+
skipDefaultIndexes: config.skipDefaultIndexes,
|
|
3637
|
+
indexes: config.indexes
|
|
3638
|
+
};
|
|
3156
3639
|
const scores = new ScoresMSSQL(domainConfig);
|
|
3157
3640
|
const workflows = new WorkflowsMSSQL(domainConfig);
|
|
3158
3641
|
const memory = new MemoryMSSQL(domainConfig);
|
|
@@ -3181,11 +3664,6 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
3181
3664
|
try {
|
|
3182
3665
|
await this.isConnected;
|
|
3183
3666
|
await super.init();
|
|
3184
|
-
try {
|
|
3185
|
-
await this.#db.createAutomaticIndexes();
|
|
3186
|
-
} catch (indexError) {
|
|
3187
|
-
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
3188
|
-
}
|
|
3189
3667
|
} catch (error) {
|
|
3190
3668
|
this.isConnected = null;
|
|
3191
3669
|
throw new MastraError(
|
|
@@ -3213,207 +3691,20 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
3213
3691
|
hasColumn: true,
|
|
3214
3692
|
createTable: true,
|
|
3215
3693
|
deleteMessages: true,
|
|
3694
|
+
observability: true,
|
|
3695
|
+
indexManagement: true,
|
|
3216
3696
|
listScoresBySpan: true,
|
|
3217
|
-
|
|
3218
|
-
indexManagement: true
|
|
3697
|
+
agents: false
|
|
3219
3698
|
};
|
|
3220
3699
|
}
|
|
3221
3700
|
/**
|
|
3222
|
-
*
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
3226
|
-
}
|
|
3227
|
-
async saveThread({ thread }) {
|
|
3228
|
-
return this.stores.memory.saveThread({ thread });
|
|
3229
|
-
}
|
|
3230
|
-
async updateThread({
|
|
3231
|
-
id,
|
|
3232
|
-
title,
|
|
3233
|
-
metadata
|
|
3234
|
-
}) {
|
|
3235
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
3236
|
-
}
|
|
3237
|
-
async deleteThread({ threadId }) {
|
|
3238
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
3239
|
-
}
|
|
3240
|
-
async listMessagesById({ messageIds }) {
|
|
3241
|
-
return this.stores.memory.listMessagesById({ messageIds });
|
|
3242
|
-
}
|
|
3243
|
-
async saveMessages(args) {
|
|
3244
|
-
return this.stores.memory.saveMessages(args);
|
|
3245
|
-
}
|
|
3246
|
-
async updateMessages({
|
|
3247
|
-
messages
|
|
3248
|
-
}) {
|
|
3249
|
-
return this.stores.memory.updateMessages({ messages });
|
|
3250
|
-
}
|
|
3251
|
-
async deleteMessages(messageIds) {
|
|
3252
|
-
return this.stores.memory.deleteMessages(messageIds);
|
|
3253
|
-
}
|
|
3254
|
-
async getResourceById({ resourceId }) {
|
|
3255
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
3256
|
-
}
|
|
3257
|
-
async saveResource({ resource }) {
|
|
3258
|
-
return this.stores.memory.saveResource({ resource });
|
|
3259
|
-
}
|
|
3260
|
-
async updateResource({
|
|
3261
|
-
resourceId,
|
|
3262
|
-
workingMemory,
|
|
3263
|
-
metadata
|
|
3264
|
-
}) {
|
|
3265
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
3266
|
-
}
|
|
3267
|
-
/**
|
|
3268
|
-
* Workflows
|
|
3701
|
+
* Closes the MSSQL connection pool.
|
|
3702
|
+
*
|
|
3703
|
+
* This will close the connection pool, including pre-configured pools.
|
|
3269
3704
|
*/
|
|
3270
|
-
async updateWorkflowResults({
|
|
3271
|
-
workflowName,
|
|
3272
|
-
runId,
|
|
3273
|
-
stepId,
|
|
3274
|
-
result,
|
|
3275
|
-
requestContext
|
|
3276
|
-
}) {
|
|
3277
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
3278
|
-
}
|
|
3279
|
-
async updateWorkflowState({
|
|
3280
|
-
workflowName,
|
|
3281
|
-
runId,
|
|
3282
|
-
opts
|
|
3283
|
-
}) {
|
|
3284
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
3285
|
-
}
|
|
3286
|
-
async persistWorkflowSnapshot({
|
|
3287
|
-
workflowName,
|
|
3288
|
-
runId,
|
|
3289
|
-
resourceId,
|
|
3290
|
-
snapshot
|
|
3291
|
-
}) {
|
|
3292
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
3293
|
-
}
|
|
3294
|
-
async loadWorkflowSnapshot({
|
|
3295
|
-
workflowName,
|
|
3296
|
-
runId
|
|
3297
|
-
}) {
|
|
3298
|
-
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
3299
|
-
}
|
|
3300
|
-
async listWorkflowRuns(args = {}) {
|
|
3301
|
-
return this.stores.workflows.listWorkflowRuns(args);
|
|
3302
|
-
}
|
|
3303
|
-
async getWorkflowRunById({
|
|
3304
|
-
runId,
|
|
3305
|
-
workflowName
|
|
3306
|
-
}) {
|
|
3307
|
-
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
3308
|
-
}
|
|
3309
|
-
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
3310
|
-
return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
|
|
3311
|
-
}
|
|
3312
3705
|
async close() {
|
|
3313
3706
|
await this.pool.close();
|
|
3314
3707
|
}
|
|
3315
|
-
/**
|
|
3316
|
-
* Index Management
|
|
3317
|
-
*/
|
|
3318
|
-
async createIndex(options) {
|
|
3319
|
-
return this.#db.createIndex(options);
|
|
3320
|
-
}
|
|
3321
|
-
async listIndexes(tableName) {
|
|
3322
|
-
return this.#db.listIndexes(tableName);
|
|
3323
|
-
}
|
|
3324
|
-
async describeIndex(indexName) {
|
|
3325
|
-
return this.#db.describeIndex(indexName);
|
|
3326
|
-
}
|
|
3327
|
-
async dropIndex(indexName) {
|
|
3328
|
-
return this.#db.dropIndex(indexName);
|
|
3329
|
-
}
|
|
3330
|
-
/**
|
|
3331
|
-
* Tracing / Observability
|
|
3332
|
-
*/
|
|
3333
|
-
getObservabilityStore() {
|
|
3334
|
-
if (!this.stores.observability) {
|
|
3335
|
-
throw new MastraError({
|
|
3336
|
-
id: createStorageErrorId("MSSQL", "OBSERVABILITY", "NOT_INITIALIZED"),
|
|
3337
|
-
domain: ErrorDomain.STORAGE,
|
|
3338
|
-
category: ErrorCategory.SYSTEM,
|
|
3339
|
-
text: "Observability storage is not initialized"
|
|
3340
|
-
});
|
|
3341
|
-
}
|
|
3342
|
-
return this.stores.observability;
|
|
3343
|
-
}
|
|
3344
|
-
async createSpan(span) {
|
|
3345
|
-
return this.getObservabilityStore().createSpan(span);
|
|
3346
|
-
}
|
|
3347
|
-
async updateSpan({
|
|
3348
|
-
spanId,
|
|
3349
|
-
traceId,
|
|
3350
|
-
updates
|
|
3351
|
-
}) {
|
|
3352
|
-
return this.getObservabilityStore().updateSpan({ spanId, traceId, updates });
|
|
3353
|
-
}
|
|
3354
|
-
async getTrace(traceId) {
|
|
3355
|
-
return this.getObservabilityStore().getTrace(traceId);
|
|
3356
|
-
}
|
|
3357
|
-
async getTracesPaginated(args) {
|
|
3358
|
-
return this.getObservabilityStore().getTracesPaginated(args);
|
|
3359
|
-
}
|
|
3360
|
-
async batchCreateSpans(args) {
|
|
3361
|
-
return this.getObservabilityStore().batchCreateSpans(args);
|
|
3362
|
-
}
|
|
3363
|
-
async batchUpdateSpans(args) {
|
|
3364
|
-
return this.getObservabilityStore().batchUpdateSpans(args);
|
|
3365
|
-
}
|
|
3366
|
-
async batchDeleteTraces(args) {
|
|
3367
|
-
return this.getObservabilityStore().batchDeleteTraces(args);
|
|
3368
|
-
}
|
|
3369
|
-
/**
|
|
3370
|
-
* Scorers
|
|
3371
|
-
*/
|
|
3372
|
-
async getScoreById({ id: _id }) {
|
|
3373
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
3374
|
-
}
|
|
3375
|
-
async listScoresByScorerId({
|
|
3376
|
-
scorerId: _scorerId,
|
|
3377
|
-
pagination: _pagination,
|
|
3378
|
-
entityId: _entityId,
|
|
3379
|
-
entityType: _entityType,
|
|
3380
|
-
source: _source
|
|
3381
|
-
}) {
|
|
3382
|
-
return this.stores.scores.listScoresByScorerId({
|
|
3383
|
-
scorerId: _scorerId,
|
|
3384
|
-
pagination: _pagination,
|
|
3385
|
-
entityId: _entityId,
|
|
3386
|
-
entityType: _entityType,
|
|
3387
|
-
source: _source
|
|
3388
|
-
});
|
|
3389
|
-
}
|
|
3390
|
-
async saveScore(score) {
|
|
3391
|
-
return this.stores.scores.saveScore(score);
|
|
3392
|
-
}
|
|
3393
|
-
async listScoresByRunId({
|
|
3394
|
-
runId: _runId,
|
|
3395
|
-
pagination: _pagination
|
|
3396
|
-
}) {
|
|
3397
|
-
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
3398
|
-
}
|
|
3399
|
-
async listScoresByEntityId({
|
|
3400
|
-
entityId: _entityId,
|
|
3401
|
-
entityType: _entityType,
|
|
3402
|
-
pagination: _pagination
|
|
3403
|
-
}) {
|
|
3404
|
-
return this.stores.scores.listScoresByEntityId({
|
|
3405
|
-
entityId: _entityId,
|
|
3406
|
-
entityType: _entityType,
|
|
3407
|
-
pagination: _pagination
|
|
3408
|
-
});
|
|
3409
|
-
}
|
|
3410
|
-
async listScoresBySpan({
|
|
3411
|
-
traceId,
|
|
3412
|
-
spanId,
|
|
3413
|
-
pagination: _pagination
|
|
3414
|
-
}) {
|
|
3415
|
-
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination: _pagination });
|
|
3416
|
-
}
|
|
3417
3708
|
};
|
|
3418
3709
|
|
|
3419
3710
|
export { MSSQLStore };
|