@mastra/mssql 0.0.0-roamin-openaivoice-speak-options-passing-20250926163614 → 0.0.0-safe-stringify-telemetry-20251205024938
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 +221 -3
- package/README.md +315 -36
- package/dist/index.cjs +1464 -181
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1464 -181
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +44 -0
- package/dist/storage/domains/observability/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +67 -4
- package/dist/storage/domains/operations/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +11 -2
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/utils.d.ts +19 -0
- package/dist/storage/domains/utils.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +5 -11
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +53 -11
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +14 -7
package/dist/index.cjs
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
var error = require('@mastra/core/error');
|
|
4
4
|
var storage = require('@mastra/core/storage');
|
|
5
|
-
var
|
|
5
|
+
var sql3 = require('mssql');
|
|
6
6
|
var utils = require('@mastra/core/utils');
|
|
7
7
|
var agent = require('@mastra/core/agent');
|
|
8
|
+
var crypto = require('crypto');
|
|
9
|
+
var scores = require('@mastra/core/scores');
|
|
8
10
|
|
|
9
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
12
|
|
|
11
|
-
var
|
|
13
|
+
var sql3__default = /*#__PURE__*/_interopDefault(sql3);
|
|
12
14
|
|
|
13
15
|
// src/storage/index.ts
|
|
14
16
|
function getSchemaName(schema) {
|
|
@@ -20,6 +22,69 @@ function getTableName({ indexName, schemaName }) {
|
|
|
20
22
|
const quotedSchemaName = schemaName;
|
|
21
23
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
22
24
|
}
|
|
25
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
26
|
+
const filters = {};
|
|
27
|
+
if (dateRange?.start) {
|
|
28
|
+
filters[`${fieldName}_gte`] = dateRange.start;
|
|
29
|
+
}
|
|
30
|
+
if (dateRange?.end) {
|
|
31
|
+
filters[`${fieldName}_lte`] = dateRange.end;
|
|
32
|
+
}
|
|
33
|
+
return filters;
|
|
34
|
+
}
|
|
35
|
+
function prepareWhereClause(filters, _schema) {
|
|
36
|
+
const conditions = [];
|
|
37
|
+
const params = {};
|
|
38
|
+
let paramIndex = 1;
|
|
39
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
40
|
+
if (value === void 0) return;
|
|
41
|
+
const paramName = `p${paramIndex++}`;
|
|
42
|
+
if (key.endsWith("_gte")) {
|
|
43
|
+
const fieldName = key.slice(0, -4);
|
|
44
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
|
|
45
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
46
|
+
} else if (key.endsWith("_lte")) {
|
|
47
|
+
const fieldName = key.slice(0, -4);
|
|
48
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
|
|
49
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
50
|
+
} else if (value === null) {
|
|
51
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
|
|
52
|
+
} else {
|
|
53
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
54
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
59
|
+
params
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function transformFromSqlRow({
|
|
63
|
+
tableName,
|
|
64
|
+
sqlRow
|
|
65
|
+
}) {
|
|
66
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
67
|
+
const result = {};
|
|
68
|
+
Object.entries(sqlRow).forEach(([key, value]) => {
|
|
69
|
+
const columnSchema = schema?.[key];
|
|
70
|
+
if (columnSchema?.type === "jsonb" && typeof value === "string") {
|
|
71
|
+
try {
|
|
72
|
+
result[key] = JSON.parse(value);
|
|
73
|
+
} catch {
|
|
74
|
+
result[key] = value;
|
|
75
|
+
}
|
|
76
|
+
} else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
|
|
77
|
+
result[key] = new Date(value);
|
|
78
|
+
} else if (columnSchema?.type === "timestamp" && value instanceof Date) {
|
|
79
|
+
result[key] = value;
|
|
80
|
+
} else if (columnSchema?.type === "boolean") {
|
|
81
|
+
result[key] = Boolean(value);
|
|
82
|
+
} else {
|
|
83
|
+
result[key] = value;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
23
88
|
|
|
24
89
|
// src/storage/domains/legacy-evals/index.ts
|
|
25
90
|
function transformEvalRow(row) {
|
|
@@ -30,7 +95,7 @@ function transformEvalRow(row) {
|
|
|
30
95
|
} catch {
|
|
31
96
|
}
|
|
32
97
|
}
|
|
33
|
-
if (row.
|
|
98
|
+
if (row.result) {
|
|
34
99
|
try {
|
|
35
100
|
resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
|
|
36
101
|
} catch {
|
|
@@ -76,7 +141,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
76
141
|
if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
|
|
77
142
|
return [];
|
|
78
143
|
}
|
|
79
|
-
|
|
144
|
+
this.logger?.error?.("Failed to get evals for the specified agent:", error);
|
|
80
145
|
throw error;
|
|
81
146
|
}
|
|
82
147
|
}
|
|
@@ -112,7 +177,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
112
177
|
const countReq = this.pool.request();
|
|
113
178
|
Object.entries(params).forEach(([key, value]) => {
|
|
114
179
|
if (value instanceof Date) {
|
|
115
|
-
countReq.input(key,
|
|
180
|
+
countReq.input(key, sql3__default.default.DateTime, value);
|
|
116
181
|
} else {
|
|
117
182
|
countReq.input(key, value);
|
|
118
183
|
}
|
|
@@ -131,7 +196,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
131
196
|
const req = this.pool.request();
|
|
132
197
|
Object.entries(params).forEach(([key, value]) => {
|
|
133
198
|
if (value instanceof Date) {
|
|
134
|
-
req.input(key,
|
|
199
|
+
req.input(key, sql3__default.default.DateTime, value);
|
|
135
200
|
} else {
|
|
136
201
|
req.input(key, value);
|
|
137
202
|
}
|
|
@@ -163,7 +228,7 @@ var LegacyEvalsMSSQL = class extends storage.LegacyEvalsStorage {
|
|
|
163
228
|
error$1
|
|
164
229
|
);
|
|
165
230
|
this.logger?.error?.(mastraError.toString());
|
|
166
|
-
this.logger?.trackException(mastraError);
|
|
231
|
+
this.logger?.trackException?.(mastraError);
|
|
167
232
|
throw mastraError;
|
|
168
233
|
}
|
|
169
234
|
}
|
|
@@ -256,7 +321,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
256
321
|
};
|
|
257
322
|
}
|
|
258
323
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
259
|
-
const
|
|
324
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
325
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
260
326
|
const dataRequest = this.pool.request();
|
|
261
327
|
dataRequest.input("resourceId", resourceId);
|
|
262
328
|
dataRequest.input("perPage", perPage);
|
|
@@ -313,9 +379,14 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
313
379
|
req.input("id", thread.id);
|
|
314
380
|
req.input("resourceId", thread.resourceId);
|
|
315
381
|
req.input("title", thread.title);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
382
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
383
|
+
if (metadata === null) {
|
|
384
|
+
req.input("metadata", sql3__default.default.NVarChar, null);
|
|
385
|
+
} else {
|
|
386
|
+
req.input("metadata", metadata);
|
|
387
|
+
}
|
|
388
|
+
req.input("createdAt", sql3__default.default.DateTime2, thread.createdAt);
|
|
389
|
+
req.input("updatedAt", sql3__default.default.DateTime2, thread.updatedAt);
|
|
319
390
|
await req.query(mergeSql);
|
|
320
391
|
return thread;
|
|
321
392
|
} catch (error$1) {
|
|
@@ -340,7 +411,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
340
411
|
try {
|
|
341
412
|
const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
342
413
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
343
|
-
const
|
|
414
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
415
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
|
|
344
416
|
const request = this.pool.request();
|
|
345
417
|
request.input("resourceId", resourceId);
|
|
346
418
|
const resultSet = await request.query(dataQuery);
|
|
@@ -589,7 +661,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
589
661
|
error$1
|
|
590
662
|
);
|
|
591
663
|
this.logger?.error?.(mastraError.toString());
|
|
592
|
-
this.logger?.trackException(mastraError);
|
|
664
|
+
this.logger?.trackException?.(mastraError);
|
|
593
665
|
return [];
|
|
594
666
|
}
|
|
595
667
|
}
|
|
@@ -629,7 +701,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
629
701
|
error$1
|
|
630
702
|
);
|
|
631
703
|
this.logger?.error?.(mastraError.toString());
|
|
632
|
-
this.logger?.trackException(mastraError);
|
|
704
|
+
this.logger?.trackException?.(mastraError);
|
|
633
705
|
return [];
|
|
634
706
|
}
|
|
635
707
|
}
|
|
@@ -688,10 +760,11 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
688
760
|
const rows = rowsResult.recordset || [];
|
|
689
761
|
rows.sort((a, b) => a.seq_id - b.seq_id);
|
|
690
762
|
messages.push(...rows);
|
|
691
|
-
|
|
763
|
+
let parsed = this._parseAndFormatMessages(messages, format);
|
|
764
|
+
parsed = parsed.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
692
765
|
return {
|
|
693
766
|
messages: parsed,
|
|
694
|
-
total
|
|
767
|
+
total,
|
|
695
768
|
page,
|
|
696
769
|
perPage,
|
|
697
770
|
hasMore: currentOffset + rows.length < total
|
|
@@ -711,7 +784,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
711
784
|
error$1
|
|
712
785
|
);
|
|
713
786
|
this.logger?.error?.(mastraError.toString());
|
|
714
|
-
this.logger?.trackException(mastraError);
|
|
787
|
+
this.logger?.trackException?.(mastraError);
|
|
715
788
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
716
789
|
}
|
|
717
790
|
}
|
|
@@ -763,7 +836,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
763
836
|
"content",
|
|
764
837
|
typeof message.content === "string" ? message.content : JSON.stringify(message.content)
|
|
765
838
|
);
|
|
766
|
-
request.input("createdAt",
|
|
839
|
+
request.input("createdAt", sql3__default.default.DateTime2, message.createdAt);
|
|
767
840
|
request.input("role", message.role);
|
|
768
841
|
request.input("type", message.type || "v2");
|
|
769
842
|
request.input("resourceId", message.resourceId);
|
|
@@ -782,7 +855,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
782
855
|
await request.query(mergeSql);
|
|
783
856
|
}
|
|
784
857
|
const threadReq = transaction.request();
|
|
785
|
-
threadReq.input("updatedAt",
|
|
858
|
+
threadReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
786
859
|
threadReq.input("id", threadId);
|
|
787
860
|
await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
|
|
788
861
|
await transaction.commit();
|
|
@@ -978,8 +1051,10 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
978
1051
|
return null;
|
|
979
1052
|
}
|
|
980
1053
|
return {
|
|
981
|
-
|
|
982
|
-
|
|
1054
|
+
id: result.id,
|
|
1055
|
+
createdAt: result.createdAt,
|
|
1056
|
+
updatedAt: result.updatedAt,
|
|
1057
|
+
workingMemory: result.workingMemory,
|
|
983
1058
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
984
1059
|
};
|
|
985
1060
|
} catch (error$1) {
|
|
@@ -993,7 +1068,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
993
1068
|
error$1
|
|
994
1069
|
);
|
|
995
1070
|
this.logger?.error?.(mastraError.toString());
|
|
996
|
-
this.logger?.trackException(mastraError);
|
|
1071
|
+
this.logger?.trackException?.(mastraError);
|
|
997
1072
|
throw mastraError;
|
|
998
1073
|
}
|
|
999
1074
|
}
|
|
@@ -1002,7 +1077,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1002
1077
|
tableName: storage.TABLE_RESOURCES,
|
|
1003
1078
|
record: {
|
|
1004
1079
|
...resource,
|
|
1005
|
-
metadata:
|
|
1080
|
+
metadata: resource.metadata
|
|
1006
1081
|
}
|
|
1007
1082
|
});
|
|
1008
1083
|
return resource;
|
|
@@ -1060,20 +1135,337 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1060
1135
|
error$1
|
|
1061
1136
|
);
|
|
1062
1137
|
this.logger?.error?.(mastraError.toString());
|
|
1063
|
-
this.logger?.trackException(mastraError);
|
|
1138
|
+
this.logger?.trackException?.(mastraError);
|
|
1064
1139
|
throw mastraError;
|
|
1065
1140
|
}
|
|
1066
1141
|
}
|
|
1067
1142
|
};
|
|
1143
|
+
var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
|
|
1144
|
+
pool;
|
|
1145
|
+
operations;
|
|
1146
|
+
schema;
|
|
1147
|
+
constructor({
|
|
1148
|
+
pool,
|
|
1149
|
+
operations,
|
|
1150
|
+
schema
|
|
1151
|
+
}) {
|
|
1152
|
+
super();
|
|
1153
|
+
this.pool = pool;
|
|
1154
|
+
this.operations = operations;
|
|
1155
|
+
this.schema = schema;
|
|
1156
|
+
}
|
|
1157
|
+
get aiTracingStrategy() {
|
|
1158
|
+
return {
|
|
1159
|
+
preferred: "batch-with-updates",
|
|
1160
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
async createAISpan(span) {
|
|
1164
|
+
try {
|
|
1165
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
1166
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
1167
|
+
const record = {
|
|
1168
|
+
...span,
|
|
1169
|
+
startedAt,
|
|
1170
|
+
endedAt
|
|
1171
|
+
// Note: createdAt/updatedAt will be set by default values
|
|
1172
|
+
};
|
|
1173
|
+
return this.operations.insert({ tableName: storage.TABLE_AI_SPANS, record });
|
|
1174
|
+
} catch (error$1) {
|
|
1175
|
+
throw new error.MastraError(
|
|
1176
|
+
{
|
|
1177
|
+
id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
|
|
1178
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1179
|
+
category: error.ErrorCategory.USER,
|
|
1180
|
+
details: {
|
|
1181
|
+
spanId: span.spanId,
|
|
1182
|
+
traceId: span.traceId,
|
|
1183
|
+
spanType: span.spanType,
|
|
1184
|
+
spanName: span.name
|
|
1185
|
+
}
|
|
1186
|
+
},
|
|
1187
|
+
error$1
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
async getAITrace(traceId) {
|
|
1192
|
+
try {
|
|
1193
|
+
const tableName = getTableName({
|
|
1194
|
+
indexName: storage.TABLE_AI_SPANS,
|
|
1195
|
+
schemaName: getSchemaName(this.schema)
|
|
1196
|
+
});
|
|
1197
|
+
const request = this.pool.request();
|
|
1198
|
+
request.input("traceId", traceId);
|
|
1199
|
+
const result = await request.query(
|
|
1200
|
+
`SELECT
|
|
1201
|
+
[traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
|
|
1202
|
+
[attributes], [metadata], [links], [input], [output], [error], [isEvent],
|
|
1203
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
1204
|
+
FROM ${tableName}
|
|
1205
|
+
WHERE [traceId] = @traceId
|
|
1206
|
+
ORDER BY [startedAt] DESC`
|
|
1207
|
+
);
|
|
1208
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
return {
|
|
1212
|
+
traceId,
|
|
1213
|
+
spans: result.recordset.map(
|
|
1214
|
+
(span) => transformFromSqlRow({
|
|
1215
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1216
|
+
sqlRow: span
|
|
1217
|
+
})
|
|
1218
|
+
)
|
|
1219
|
+
};
|
|
1220
|
+
} catch (error$1) {
|
|
1221
|
+
throw new error.MastraError(
|
|
1222
|
+
{
|
|
1223
|
+
id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
|
|
1224
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1225
|
+
category: error.ErrorCategory.USER,
|
|
1226
|
+
details: {
|
|
1227
|
+
traceId
|
|
1228
|
+
}
|
|
1229
|
+
},
|
|
1230
|
+
error$1
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
async updateAISpan({
|
|
1235
|
+
spanId,
|
|
1236
|
+
traceId,
|
|
1237
|
+
updates
|
|
1238
|
+
}) {
|
|
1239
|
+
try {
|
|
1240
|
+
const data = { ...updates };
|
|
1241
|
+
if (data.endedAt instanceof Date) {
|
|
1242
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1243
|
+
}
|
|
1244
|
+
if (data.startedAt instanceof Date) {
|
|
1245
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1246
|
+
}
|
|
1247
|
+
await this.operations.update({
|
|
1248
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1249
|
+
keys: { spanId, traceId },
|
|
1250
|
+
data
|
|
1251
|
+
});
|
|
1252
|
+
} catch (error$1) {
|
|
1253
|
+
throw new error.MastraError(
|
|
1254
|
+
{
|
|
1255
|
+
id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
|
|
1256
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1257
|
+
category: error.ErrorCategory.USER,
|
|
1258
|
+
details: {
|
|
1259
|
+
spanId,
|
|
1260
|
+
traceId
|
|
1261
|
+
}
|
|
1262
|
+
},
|
|
1263
|
+
error$1
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
async getAITracesPaginated({
|
|
1268
|
+
filters,
|
|
1269
|
+
pagination
|
|
1270
|
+
}) {
|
|
1271
|
+
const page = pagination?.page ?? 0;
|
|
1272
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1273
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1274
|
+
const filtersWithDateRange = {
|
|
1275
|
+
...actualFilters,
|
|
1276
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
1277
|
+
parentSpanId: null
|
|
1278
|
+
// Only get root spans for traces
|
|
1279
|
+
};
|
|
1280
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
1281
|
+
let actualWhereClause = whereClause.sql;
|
|
1282
|
+
const params = { ...whereClause.params };
|
|
1283
|
+
let currentParamIndex = Object.keys(params).length + 1;
|
|
1284
|
+
if (entityId && entityType) {
|
|
1285
|
+
let name = "";
|
|
1286
|
+
if (entityType === "workflow") {
|
|
1287
|
+
name = `workflow run: '${entityId}'`;
|
|
1288
|
+
} else if (entityType === "agent") {
|
|
1289
|
+
name = `agent run: '${entityId}'`;
|
|
1290
|
+
} else {
|
|
1291
|
+
const error$1 = new error.MastraError({
|
|
1292
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1293
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1294
|
+
category: error.ErrorCategory.USER,
|
|
1295
|
+
details: {
|
|
1296
|
+
entityType
|
|
1297
|
+
},
|
|
1298
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1299
|
+
});
|
|
1300
|
+
throw error$1;
|
|
1301
|
+
}
|
|
1302
|
+
const entityParam = `p${currentParamIndex++}`;
|
|
1303
|
+
if (actualWhereClause) {
|
|
1304
|
+
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
1305
|
+
} else {
|
|
1306
|
+
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
1307
|
+
}
|
|
1308
|
+
params[entityParam] = name;
|
|
1309
|
+
}
|
|
1310
|
+
const tableName = getTableName({
|
|
1311
|
+
indexName: storage.TABLE_AI_SPANS,
|
|
1312
|
+
schemaName: getSchemaName(this.schema)
|
|
1313
|
+
});
|
|
1314
|
+
try {
|
|
1315
|
+
const countRequest = this.pool.request();
|
|
1316
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1317
|
+
countRequest.input(key, value);
|
|
1318
|
+
});
|
|
1319
|
+
const countResult = await countRequest.query(
|
|
1320
|
+
`SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
|
|
1321
|
+
);
|
|
1322
|
+
const total = countResult.recordset[0]?.count ?? 0;
|
|
1323
|
+
if (total === 0) {
|
|
1324
|
+
return {
|
|
1325
|
+
pagination: {
|
|
1326
|
+
total: 0,
|
|
1327
|
+
page,
|
|
1328
|
+
perPage,
|
|
1329
|
+
hasMore: false
|
|
1330
|
+
},
|
|
1331
|
+
spans: []
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
const dataRequest = this.pool.request();
|
|
1335
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1336
|
+
dataRequest.input(key, value);
|
|
1337
|
+
});
|
|
1338
|
+
dataRequest.input("offset", page * perPage);
|
|
1339
|
+
dataRequest.input("limit", perPage);
|
|
1340
|
+
const dataResult = await dataRequest.query(
|
|
1341
|
+
`SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1342
|
+
);
|
|
1343
|
+
const spans = dataResult.recordset.map(
|
|
1344
|
+
(row) => transformFromSqlRow({
|
|
1345
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1346
|
+
sqlRow: row
|
|
1347
|
+
})
|
|
1348
|
+
);
|
|
1349
|
+
return {
|
|
1350
|
+
pagination: {
|
|
1351
|
+
total,
|
|
1352
|
+
page,
|
|
1353
|
+
perPage,
|
|
1354
|
+
hasMore: (page + 1) * perPage < total
|
|
1355
|
+
},
|
|
1356
|
+
spans
|
|
1357
|
+
};
|
|
1358
|
+
} catch (error$1) {
|
|
1359
|
+
throw new error.MastraError(
|
|
1360
|
+
{
|
|
1361
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1362
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1363
|
+
category: error.ErrorCategory.USER
|
|
1364
|
+
},
|
|
1365
|
+
error$1
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
async batchCreateAISpans(args) {
|
|
1370
|
+
if (!args.records || args.records.length === 0) {
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
try {
|
|
1374
|
+
await this.operations.batchInsert({
|
|
1375
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1376
|
+
records: args.records.map((span) => ({
|
|
1377
|
+
...span,
|
|
1378
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
1379
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
1380
|
+
}))
|
|
1381
|
+
});
|
|
1382
|
+
} catch (error$1) {
|
|
1383
|
+
throw new error.MastraError(
|
|
1384
|
+
{
|
|
1385
|
+
id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
1386
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1387
|
+
category: error.ErrorCategory.USER,
|
|
1388
|
+
details: {
|
|
1389
|
+
count: args.records.length
|
|
1390
|
+
}
|
|
1391
|
+
},
|
|
1392
|
+
error$1
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
async batchUpdateAISpans(args) {
|
|
1397
|
+
if (!args.records || args.records.length === 0) {
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
try {
|
|
1401
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
1402
|
+
const processedData = { ...data };
|
|
1403
|
+
if (processedData.endedAt instanceof Date) {
|
|
1404
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
1405
|
+
}
|
|
1406
|
+
if (processedData.startedAt instanceof Date) {
|
|
1407
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
1408
|
+
}
|
|
1409
|
+
return {
|
|
1410
|
+
keys: { spanId, traceId },
|
|
1411
|
+
data: processedData
|
|
1412
|
+
};
|
|
1413
|
+
});
|
|
1414
|
+
await this.operations.batchUpdate({
|
|
1415
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1416
|
+
updates
|
|
1417
|
+
});
|
|
1418
|
+
} catch (error$1) {
|
|
1419
|
+
throw new error.MastraError(
|
|
1420
|
+
{
|
|
1421
|
+
id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
1422
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1423
|
+
category: error.ErrorCategory.USER,
|
|
1424
|
+
details: {
|
|
1425
|
+
count: args.records.length
|
|
1426
|
+
}
|
|
1427
|
+
},
|
|
1428
|
+
error$1
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
async batchDeleteAITraces(args) {
|
|
1433
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
try {
|
|
1437
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
1438
|
+
await this.operations.batchDelete({
|
|
1439
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1440
|
+
keys
|
|
1441
|
+
});
|
|
1442
|
+
} catch (error$1) {
|
|
1443
|
+
throw new error.MastraError(
|
|
1444
|
+
{
|
|
1445
|
+
id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
1446
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1447
|
+
category: error.ErrorCategory.USER,
|
|
1448
|
+
details: {
|
|
1449
|
+
count: args.traceIds.length
|
|
1450
|
+
}
|
|
1451
|
+
},
|
|
1452
|
+
error$1
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1068
1457
|
var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
1069
1458
|
pool;
|
|
1070
1459
|
schemaName;
|
|
1071
1460
|
setupSchemaPromise = null;
|
|
1072
1461
|
schemaSetupComplete = void 0;
|
|
1073
|
-
getSqlType(type, isPrimaryKey = false) {
|
|
1462
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
|
|
1074
1463
|
switch (type) {
|
|
1075
1464
|
case "text":
|
|
1076
|
-
|
|
1465
|
+
if (useLargeStorage) {
|
|
1466
|
+
return "NVARCHAR(MAX)";
|
|
1467
|
+
}
|
|
1468
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
1077
1469
|
case "timestamp":
|
|
1078
1470
|
return "DATETIME2(7)";
|
|
1079
1471
|
case "uuid":
|
|
@@ -1086,6 +1478,8 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1086
1478
|
return "BIGINT";
|
|
1087
1479
|
case "float":
|
|
1088
1480
|
return "FLOAT";
|
|
1481
|
+
case "boolean":
|
|
1482
|
+
return "BIT";
|
|
1089
1483
|
default:
|
|
1090
1484
|
throw new error.MastraError({
|
|
1091
1485
|
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
@@ -1148,20 +1542,26 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1148
1542
|
}
|
|
1149
1543
|
await this.setupSchemaPromise;
|
|
1150
1544
|
}
|
|
1151
|
-
async insert({
|
|
1545
|
+
async insert({
|
|
1546
|
+
tableName,
|
|
1547
|
+
record,
|
|
1548
|
+
transaction
|
|
1549
|
+
}) {
|
|
1152
1550
|
try {
|
|
1153
|
-
const columns = Object.keys(record)
|
|
1154
|
-
const
|
|
1155
|
-
const paramNames =
|
|
1156
|
-
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${
|
|
1157
|
-
const request = this.pool.request();
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
request.input(`param${i}`,
|
|
1551
|
+
const columns = Object.keys(record);
|
|
1552
|
+
const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1553
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
1554
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1555
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1556
|
+
columns.forEach((col, i) => {
|
|
1557
|
+
const value = record[col];
|
|
1558
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
1559
|
+
if (preparedValue instanceof Date) {
|
|
1560
|
+
request.input(`param${i}`, sql3__default.default.DateTime2, preparedValue);
|
|
1561
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
1562
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
1163
1563
|
} else {
|
|
1164
|
-
request.input(`param${i}`,
|
|
1564
|
+
request.input(`param${i}`, preparedValue);
|
|
1165
1565
|
}
|
|
1166
1566
|
});
|
|
1167
1567
|
await request.query(insertSql);
|
|
@@ -1185,7 +1585,7 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1185
1585
|
try {
|
|
1186
1586
|
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
1187
1587
|
} catch (truncateError) {
|
|
1188
|
-
if (truncateError
|
|
1588
|
+
if (truncateError?.number === 4712) {
|
|
1189
1589
|
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
1190
1590
|
} else {
|
|
1191
1591
|
throw truncateError;
|
|
@@ -1208,9 +1608,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1208
1608
|
getDefaultValue(type) {
|
|
1209
1609
|
switch (type) {
|
|
1210
1610
|
case "timestamp":
|
|
1211
|
-
return "DEFAULT
|
|
1611
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
1212
1612
|
case "jsonb":
|
|
1213
1613
|
return "DEFAULT N'{}'";
|
|
1614
|
+
case "boolean":
|
|
1615
|
+
return "DEFAULT 0";
|
|
1214
1616
|
default:
|
|
1215
1617
|
return super.getDefaultValue(type);
|
|
1216
1618
|
}
|
|
@@ -1221,13 +1623,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1221
1623
|
}) {
|
|
1222
1624
|
try {
|
|
1223
1625
|
const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
1626
|
+
const largeDataColumns = [
|
|
1627
|
+
"workingMemory",
|
|
1628
|
+
"snapshot",
|
|
1629
|
+
"metadata",
|
|
1630
|
+
"content",
|
|
1631
|
+
// messages.content - can be very long conversation content
|
|
1632
|
+
"input",
|
|
1633
|
+
// evals.input - test input data
|
|
1634
|
+
"output",
|
|
1635
|
+
// evals.output - test output data
|
|
1636
|
+
"instructions",
|
|
1637
|
+
// evals.instructions - evaluation instructions
|
|
1638
|
+
"other"
|
|
1639
|
+
// traces.other - additional trace data
|
|
1640
|
+
];
|
|
1224
1641
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1225
1642
|
const parsedName = utils.parseSqlIdentifier(name, "column name");
|
|
1226
1643
|
const constraints = [];
|
|
1227
1644
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1228
1645
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1229
1646
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
1230
|
-
|
|
1647
|
+
const useLargeStorage = largeDataColumns.includes(name);
|
|
1648
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
|
|
1231
1649
|
}).join(",\n");
|
|
1232
1650
|
if (this.schemaName) {
|
|
1233
1651
|
await this.setupSchema();
|
|
@@ -1314,7 +1732,19 @@ ${columns}
|
|
|
1314
1732
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1315
1733
|
if (!columnExists) {
|
|
1316
1734
|
const columnDef = schema[columnName];
|
|
1317
|
-
const
|
|
1735
|
+
const largeDataColumns = [
|
|
1736
|
+
"workingMemory",
|
|
1737
|
+
"snapshot",
|
|
1738
|
+
"metadata",
|
|
1739
|
+
"content",
|
|
1740
|
+
"input",
|
|
1741
|
+
"output",
|
|
1742
|
+
"instructions",
|
|
1743
|
+
"other"
|
|
1744
|
+
];
|
|
1745
|
+
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
1746
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
1747
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
1318
1748
|
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1319
1749
|
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1320
1750
|
const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
|
|
@@ -1342,11 +1772,15 @@ ${columns}
|
|
|
1342
1772
|
try {
|
|
1343
1773
|
const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
|
|
1344
1774
|
const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
|
|
1345
|
-
const values = keyEntries.map(([_, value]) => value);
|
|
1346
1775
|
const sql7 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1347
1776
|
const request = this.pool.request();
|
|
1348
|
-
|
|
1349
|
-
|
|
1777
|
+
keyEntries.forEach(([key, value], i) => {
|
|
1778
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1779
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1780
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
1781
|
+
} else {
|
|
1782
|
+
request.input(`param${i}`, preparedValue);
|
|
1783
|
+
}
|
|
1350
1784
|
});
|
|
1351
1785
|
const resultSet = await request.query(sql7);
|
|
1352
1786
|
const result = resultSet.recordset[0] || null;
|
|
@@ -1380,7 +1814,7 @@ ${columns}
|
|
|
1380
1814
|
try {
|
|
1381
1815
|
await transaction.begin();
|
|
1382
1816
|
for (const record of records) {
|
|
1383
|
-
await this.insert({ tableName, record });
|
|
1817
|
+
await this.insert({ tableName, record, transaction });
|
|
1384
1818
|
}
|
|
1385
1819
|
await transaction.commit();
|
|
1386
1820
|
} catch (error$1) {
|
|
@@ -1417,69 +1851,637 @@ ${columns}
|
|
|
1417
1851
|
);
|
|
1418
1852
|
}
|
|
1419
1853
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
operations;
|
|
1447
|
-
schema;
|
|
1448
|
-
constructor({
|
|
1449
|
-
pool,
|
|
1450
|
-
operations,
|
|
1451
|
-
schema
|
|
1452
|
-
}) {
|
|
1453
|
-
super();
|
|
1454
|
-
this.pool = pool;
|
|
1455
|
-
this.operations = operations;
|
|
1456
|
-
this.schema = schema;
|
|
1457
|
-
}
|
|
1458
|
-
async getScoreById({ id }) {
|
|
1459
|
-
try {
|
|
1460
|
-
const request = this.pool.request();
|
|
1461
|
-
request.input("p1", id);
|
|
1462
|
-
const result = await request.query(
|
|
1463
|
-
`SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE id = @p1`
|
|
1464
|
-
);
|
|
1465
|
-
if (result.recordset.length === 0) {
|
|
1466
|
-
return null;
|
|
1854
|
+
/**
|
|
1855
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
1856
|
+
*/
|
|
1857
|
+
prepareValue(value, columnName, tableName) {
|
|
1858
|
+
if (value === null || value === void 0) {
|
|
1859
|
+
return value;
|
|
1860
|
+
}
|
|
1861
|
+
if (value instanceof Date) {
|
|
1862
|
+
return value;
|
|
1863
|
+
}
|
|
1864
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
1865
|
+
const columnSchema = schema?.[columnName];
|
|
1866
|
+
if (columnSchema?.type === "boolean") {
|
|
1867
|
+
return value ? 1 : 0;
|
|
1868
|
+
}
|
|
1869
|
+
if (columnSchema?.type === "jsonb") {
|
|
1870
|
+
if (typeof value === "string") {
|
|
1871
|
+
const trimmed = value.trim();
|
|
1872
|
+
if (trimmed.length > 0) {
|
|
1873
|
+
try {
|
|
1874
|
+
JSON.parse(trimmed);
|
|
1875
|
+
return trimmed;
|
|
1876
|
+
} catch {
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
return JSON.stringify(value);
|
|
1467
1880
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
details: { id }
|
|
1476
|
-
},
|
|
1477
|
-
error$1
|
|
1478
|
-
);
|
|
1881
|
+
if (typeof value === "bigint") {
|
|
1882
|
+
return value.toString();
|
|
1883
|
+
}
|
|
1884
|
+
return JSON.stringify(value);
|
|
1885
|
+
}
|
|
1886
|
+
if (typeof value === "object") {
|
|
1887
|
+
return JSON.stringify(value);
|
|
1479
1888
|
}
|
|
1889
|
+
return value;
|
|
1480
1890
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1891
|
+
/**
|
|
1892
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
1893
|
+
*/
|
|
1894
|
+
getMssqlType(tableName, columnName) {
|
|
1895
|
+
const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
|
|
1896
|
+
switch (col?.type) {
|
|
1897
|
+
case "text":
|
|
1898
|
+
return sql3__default.default.NVarChar;
|
|
1899
|
+
case "timestamp":
|
|
1900
|
+
return sql3__default.default.DateTime2;
|
|
1901
|
+
case "uuid":
|
|
1902
|
+
return sql3__default.default.UniqueIdentifier;
|
|
1903
|
+
case "jsonb":
|
|
1904
|
+
return sql3__default.default.NVarChar;
|
|
1905
|
+
case "integer":
|
|
1906
|
+
return sql3__default.default.Int;
|
|
1907
|
+
case "bigint":
|
|
1908
|
+
return sql3__default.default.BigInt;
|
|
1909
|
+
case "float":
|
|
1910
|
+
return sql3__default.default.Float;
|
|
1911
|
+
case "boolean":
|
|
1912
|
+
return sql3__default.default.Bit;
|
|
1913
|
+
default:
|
|
1914
|
+
return sql3__default.default.NVarChar;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Update a single record in the database
|
|
1919
|
+
*/
|
|
1920
|
+
async update({
|
|
1921
|
+
tableName,
|
|
1922
|
+
keys,
|
|
1923
|
+
data,
|
|
1924
|
+
transaction
|
|
1925
|
+
}) {
|
|
1926
|
+
try {
|
|
1927
|
+
if (!data || Object.keys(data).length === 0) {
|
|
1928
|
+
throw new error.MastraError({
|
|
1929
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
|
|
1930
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1931
|
+
category: error.ErrorCategory.USER,
|
|
1932
|
+
text: "Cannot update with empty data payload"
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1936
|
+
throw new error.MastraError({
|
|
1937
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
|
|
1938
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1939
|
+
category: error.ErrorCategory.USER,
|
|
1940
|
+
text: "Cannot update without keys to identify records"
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
const setClauses = [];
|
|
1944
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1945
|
+
let paramIndex = 0;
|
|
1946
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1947
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
1948
|
+
const paramName = `set${paramIndex++}`;
|
|
1949
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
1950
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1951
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1952
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1953
|
+
} else {
|
|
1954
|
+
request.input(paramName, preparedValue);
|
|
1955
|
+
}
|
|
1956
|
+
});
|
|
1957
|
+
const whereConditions = [];
|
|
1958
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
1959
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
1960
|
+
const paramName = `where${paramIndex++}`;
|
|
1961
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1962
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1963
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1964
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1965
|
+
} else {
|
|
1966
|
+
request.input(paramName, preparedValue);
|
|
1967
|
+
}
|
|
1968
|
+
});
|
|
1969
|
+
const tableName_ = getTableName({
|
|
1970
|
+
indexName: tableName,
|
|
1971
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1972
|
+
});
|
|
1973
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
1974
|
+
await request.query(updateSql);
|
|
1975
|
+
} catch (error$1) {
|
|
1976
|
+
throw new error.MastraError(
|
|
1977
|
+
{
|
|
1978
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
|
|
1979
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1980
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1981
|
+
details: {
|
|
1982
|
+
tableName
|
|
1983
|
+
}
|
|
1984
|
+
},
|
|
1985
|
+
error$1
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
/**
|
|
1990
|
+
* Update multiple records in a single batch transaction
|
|
1991
|
+
*/
|
|
1992
|
+
async batchUpdate({
|
|
1993
|
+
tableName,
|
|
1994
|
+
updates
|
|
1995
|
+
}) {
|
|
1996
|
+
const transaction = this.pool.transaction();
|
|
1997
|
+
try {
|
|
1998
|
+
await transaction.begin();
|
|
1999
|
+
for (const { keys, data } of updates) {
|
|
2000
|
+
await this.update({ tableName, keys, data, transaction });
|
|
2001
|
+
}
|
|
2002
|
+
await transaction.commit();
|
|
2003
|
+
} catch (error$1) {
|
|
2004
|
+
await transaction.rollback();
|
|
2005
|
+
throw new error.MastraError(
|
|
2006
|
+
{
|
|
2007
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
|
|
2008
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2009
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2010
|
+
details: {
|
|
2011
|
+
tableName,
|
|
2012
|
+
numberOfRecords: updates.length
|
|
2013
|
+
}
|
|
2014
|
+
},
|
|
2015
|
+
error$1
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* Delete multiple records by keys
|
|
2021
|
+
*/
|
|
2022
|
+
async batchDelete({ tableName, keys }) {
|
|
2023
|
+
if (keys.length === 0) {
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
const tableName_ = getTableName({
|
|
2027
|
+
indexName: tableName,
|
|
2028
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2029
|
+
});
|
|
2030
|
+
const transaction = this.pool.transaction();
|
|
2031
|
+
try {
|
|
2032
|
+
await transaction.begin();
|
|
2033
|
+
for (const keySet of keys) {
|
|
2034
|
+
const conditions = [];
|
|
2035
|
+
const request = transaction.request();
|
|
2036
|
+
let paramIndex = 0;
|
|
2037
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
2038
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
2039
|
+
const paramName = `p${paramIndex++}`;
|
|
2040
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
2041
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
2042
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
2043
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
2044
|
+
} else {
|
|
2045
|
+
request.input(paramName, preparedValue);
|
|
2046
|
+
}
|
|
2047
|
+
});
|
|
2048
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
2049
|
+
await request.query(deleteSql);
|
|
2050
|
+
}
|
|
2051
|
+
await transaction.commit();
|
|
2052
|
+
} catch (error$1) {
|
|
2053
|
+
await transaction.rollback();
|
|
2054
|
+
throw new error.MastraError(
|
|
2055
|
+
{
|
|
2056
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
|
|
2057
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2058
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2059
|
+
details: {
|
|
2060
|
+
tableName,
|
|
2061
|
+
numberOfRecords: keys.length
|
|
2062
|
+
}
|
|
2063
|
+
},
|
|
2064
|
+
error$1
|
|
2065
|
+
);
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Create a new index on a table
|
|
2070
|
+
*/
|
|
2071
|
+
async createIndex(options) {
|
|
2072
|
+
try {
|
|
2073
|
+
const { name, table, columns, unique = false, where } = options;
|
|
2074
|
+
const schemaName = this.schemaName || "dbo";
|
|
2075
|
+
const fullTableName = getTableName({
|
|
2076
|
+
indexName: table,
|
|
2077
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2078
|
+
});
|
|
2079
|
+
const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
|
|
2080
|
+
const checkRequest = this.pool.request();
|
|
2081
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2082
|
+
checkRequest.input("schemaName", schemaName);
|
|
2083
|
+
checkRequest.input("tableName", table);
|
|
2084
|
+
const indexExists = await checkRequest.query(`
|
|
2085
|
+
SELECT 1 as found
|
|
2086
|
+
FROM sys.indexes i
|
|
2087
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2088
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2089
|
+
WHERE i.name = @indexName
|
|
2090
|
+
AND s.name = @schemaName
|
|
2091
|
+
AND t.name = @tableName
|
|
2092
|
+
`);
|
|
2093
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
2097
|
+
const columnsStr = columns.map((col) => {
|
|
2098
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
2099
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
2100
|
+
if (!colName) {
|
|
2101
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
2102
|
+
}
|
|
2103
|
+
return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
2104
|
+
}
|
|
2105
|
+
return `[${utils.parseSqlIdentifier(col, "column name")}]`;
|
|
2106
|
+
}).join(", ");
|
|
2107
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
2108
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
2109
|
+
await this.pool.request().query(createIndexSql);
|
|
2110
|
+
} catch (error$1) {
|
|
2111
|
+
throw new error.MastraError(
|
|
2112
|
+
{
|
|
2113
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
|
|
2114
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2115
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2116
|
+
details: {
|
|
2117
|
+
indexName: options.name,
|
|
2118
|
+
tableName: options.table
|
|
2119
|
+
}
|
|
2120
|
+
},
|
|
2121
|
+
error$1
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
/**
|
|
2126
|
+
* Drop an existing index
|
|
2127
|
+
*/
|
|
2128
|
+
async dropIndex(indexName) {
|
|
2129
|
+
try {
|
|
2130
|
+
const schemaName = this.schemaName || "dbo";
|
|
2131
|
+
const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
|
|
2132
|
+
const checkRequest = this.pool.request();
|
|
2133
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2134
|
+
checkRequest.input("schemaName", schemaName);
|
|
2135
|
+
const result = await checkRequest.query(`
|
|
2136
|
+
SELECT t.name as table_name
|
|
2137
|
+
FROM sys.indexes i
|
|
2138
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2139
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2140
|
+
WHERE i.name = @indexName
|
|
2141
|
+
AND s.name = @schemaName
|
|
2142
|
+
`);
|
|
2143
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
if (result.recordset.length > 1) {
|
|
2147
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
2148
|
+
throw new error.MastraError({
|
|
2149
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
|
|
2150
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2151
|
+
category: error.ErrorCategory.USER,
|
|
2152
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
const tableName = result.recordset[0].table_name;
|
|
2156
|
+
const fullTableName = getTableName({
|
|
2157
|
+
indexName: tableName,
|
|
2158
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2159
|
+
});
|
|
2160
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
2161
|
+
await this.pool.request().query(dropSql);
|
|
2162
|
+
} catch (error$1) {
|
|
2163
|
+
throw new error.MastraError(
|
|
2164
|
+
{
|
|
2165
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
|
|
2166
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2167
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2168
|
+
details: {
|
|
2169
|
+
indexName
|
|
2170
|
+
}
|
|
2171
|
+
},
|
|
2172
|
+
error$1
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* List indexes for a specific table or all tables
|
|
2178
|
+
*/
|
|
2179
|
+
async listIndexes(tableName) {
|
|
2180
|
+
try {
|
|
2181
|
+
const schemaName = this.schemaName || "dbo";
|
|
2182
|
+
let query;
|
|
2183
|
+
const request = this.pool.request();
|
|
2184
|
+
request.input("schemaName", schemaName);
|
|
2185
|
+
if (tableName) {
|
|
2186
|
+
query = `
|
|
2187
|
+
SELECT
|
|
2188
|
+
i.name as name,
|
|
2189
|
+
o.name as [table],
|
|
2190
|
+
i.is_unique as is_unique,
|
|
2191
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2192
|
+
FROM sys.indexes i
|
|
2193
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2194
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2195
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2196
|
+
WHERE sch.name = @schemaName
|
|
2197
|
+
AND o.name = @tableName
|
|
2198
|
+
AND i.name IS NOT NULL
|
|
2199
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2200
|
+
`;
|
|
2201
|
+
request.input("tableName", tableName);
|
|
2202
|
+
} else {
|
|
2203
|
+
query = `
|
|
2204
|
+
SELECT
|
|
2205
|
+
i.name as name,
|
|
2206
|
+
o.name as [table],
|
|
2207
|
+
i.is_unique as is_unique,
|
|
2208
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2209
|
+
FROM sys.indexes i
|
|
2210
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2211
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2212
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2213
|
+
WHERE sch.name = @schemaName
|
|
2214
|
+
AND i.name IS NOT NULL
|
|
2215
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2216
|
+
`;
|
|
2217
|
+
}
|
|
2218
|
+
const result = await request.query(query);
|
|
2219
|
+
const indexes = [];
|
|
2220
|
+
for (const row of result.recordset) {
|
|
2221
|
+
const colRequest = this.pool.request();
|
|
2222
|
+
colRequest.input("indexName", row.name);
|
|
2223
|
+
colRequest.input("schemaName", schemaName);
|
|
2224
|
+
const colResult = await colRequest.query(`
|
|
2225
|
+
SELECT c.name as column_name
|
|
2226
|
+
FROM sys.indexes i
|
|
2227
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2228
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2229
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2230
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2231
|
+
WHERE i.name = @indexName
|
|
2232
|
+
AND s.name = @schemaName
|
|
2233
|
+
ORDER BY ic.key_ordinal
|
|
2234
|
+
`);
|
|
2235
|
+
indexes.push({
|
|
2236
|
+
name: row.name,
|
|
2237
|
+
table: row.table,
|
|
2238
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2239
|
+
unique: row.is_unique || false,
|
|
2240
|
+
size: row.size || "0 MB",
|
|
2241
|
+
definition: ""
|
|
2242
|
+
// MSSQL doesn't store definition like PG
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
return indexes;
|
|
2246
|
+
} catch (error$1) {
|
|
2247
|
+
throw new error.MastraError(
|
|
2248
|
+
{
|
|
2249
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
|
|
2250
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2251
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2252
|
+
details: tableName ? {
|
|
2253
|
+
tableName
|
|
2254
|
+
} : {}
|
|
2255
|
+
},
|
|
2256
|
+
error$1
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
/**
|
|
2261
|
+
* Get detailed statistics for a specific index
|
|
2262
|
+
*/
|
|
2263
|
+
async describeIndex(indexName) {
|
|
2264
|
+
try {
|
|
2265
|
+
const schemaName = this.schemaName || "dbo";
|
|
2266
|
+
const request = this.pool.request();
|
|
2267
|
+
request.input("indexName", indexName);
|
|
2268
|
+
request.input("schemaName", schemaName);
|
|
2269
|
+
const query = `
|
|
2270
|
+
SELECT
|
|
2271
|
+
i.name as name,
|
|
2272
|
+
o.name as [table],
|
|
2273
|
+
i.is_unique as is_unique,
|
|
2274
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
2275
|
+
i.type_desc as method,
|
|
2276
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
2277
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
2278
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
2279
|
+
FROM sys.indexes i
|
|
2280
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2281
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2282
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2283
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
2284
|
+
WHERE i.name = @indexName
|
|
2285
|
+
AND sch.name = @schemaName
|
|
2286
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
2287
|
+
`;
|
|
2288
|
+
const result = await request.query(query);
|
|
2289
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2290
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
2291
|
+
}
|
|
2292
|
+
const row = result.recordset[0];
|
|
2293
|
+
const colRequest = this.pool.request();
|
|
2294
|
+
colRequest.input("indexName", indexName);
|
|
2295
|
+
colRequest.input("schemaName", schemaName);
|
|
2296
|
+
const colResult = await colRequest.query(`
|
|
2297
|
+
SELECT c.name as column_name
|
|
2298
|
+
FROM sys.indexes i
|
|
2299
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2300
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2301
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2302
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2303
|
+
WHERE i.name = @indexName
|
|
2304
|
+
AND s.name = @schemaName
|
|
2305
|
+
ORDER BY ic.key_ordinal
|
|
2306
|
+
`);
|
|
2307
|
+
return {
|
|
2308
|
+
name: row.name,
|
|
2309
|
+
table: row.table,
|
|
2310
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2311
|
+
unique: row.is_unique || false,
|
|
2312
|
+
size: row.size || "0 MB",
|
|
2313
|
+
definition: "",
|
|
2314
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
2315
|
+
scans: Number(row.scans) || 0,
|
|
2316
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
2317
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
2318
|
+
};
|
|
2319
|
+
} catch (error$1) {
|
|
2320
|
+
throw new error.MastraError(
|
|
2321
|
+
{
|
|
2322
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
|
|
2323
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2324
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2325
|
+
details: {
|
|
2326
|
+
indexName
|
|
2327
|
+
}
|
|
2328
|
+
},
|
|
2329
|
+
error$1
|
|
2330
|
+
);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
/**
|
|
2334
|
+
* Returns definitions for automatic performance indexes
|
|
2335
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2336
|
+
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
2337
|
+
*/
|
|
2338
|
+
getAutomaticIndexDefinitions() {
|
|
2339
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2340
|
+
return [
|
|
2341
|
+
// Composite indexes for optimal filtering + sorting performance
|
|
2342
|
+
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
2343
|
+
{
|
|
2344
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
2345
|
+
table: storage.TABLE_THREADS,
|
|
2346
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
2350
|
+
table: storage.TABLE_MESSAGES,
|
|
2351
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
2352
|
+
},
|
|
2353
|
+
{
|
|
2354
|
+
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
2355
|
+
table: storage.TABLE_TRACES,
|
|
2356
|
+
columns: ["name", "seq_id DESC"]
|
|
2357
|
+
},
|
|
2358
|
+
{
|
|
2359
|
+
name: `${schemaPrefix}mastra_evals_agent_name_seqid_idx`,
|
|
2360
|
+
table: storage.TABLE_EVALS,
|
|
2361
|
+
columns: ["agent_name", "seq_id DESC"]
|
|
2362
|
+
},
|
|
2363
|
+
{
|
|
2364
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2365
|
+
table: storage.TABLE_SCORERS,
|
|
2366
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2367
|
+
},
|
|
2368
|
+
// AI Spans indexes for optimal trace querying
|
|
2369
|
+
{
|
|
2370
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2371
|
+
table: storage.TABLE_AI_SPANS,
|
|
2372
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2373
|
+
},
|
|
2374
|
+
{
|
|
2375
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2376
|
+
table: storage.TABLE_AI_SPANS,
|
|
2377
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2378
|
+
},
|
|
2379
|
+
{
|
|
2380
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2381
|
+
table: storage.TABLE_AI_SPANS,
|
|
2382
|
+
columns: ["name"]
|
|
2383
|
+
},
|
|
2384
|
+
{
|
|
2385
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2386
|
+
table: storage.TABLE_AI_SPANS,
|
|
2387
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2388
|
+
}
|
|
2389
|
+
];
|
|
2390
|
+
}
|
|
2391
|
+
/**
|
|
2392
|
+
* Creates automatic indexes for optimal query performance
|
|
2393
|
+
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
2394
|
+
*/
|
|
2395
|
+
async createAutomaticIndexes() {
|
|
2396
|
+
try {
|
|
2397
|
+
const indexes = this.getAutomaticIndexDefinitions();
|
|
2398
|
+
for (const indexOptions of indexes) {
|
|
2399
|
+
try {
|
|
2400
|
+
await this.createIndex(indexOptions);
|
|
2401
|
+
} catch (error) {
|
|
2402
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
} catch (error$1) {
|
|
2406
|
+
throw new error.MastraError(
|
|
2407
|
+
{
|
|
2408
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
2409
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2410
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2411
|
+
},
|
|
2412
|
+
error$1
|
|
2413
|
+
);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
function transformScoreRow(row) {
|
|
2418
|
+
return {
|
|
2419
|
+
...row,
|
|
2420
|
+
input: storage.safelyParseJSON(row.input),
|
|
2421
|
+
scorer: storage.safelyParseJSON(row.scorer),
|
|
2422
|
+
preprocessStepResult: storage.safelyParseJSON(row.preprocessStepResult),
|
|
2423
|
+
analyzeStepResult: storage.safelyParseJSON(row.analyzeStepResult),
|
|
2424
|
+
metadata: storage.safelyParseJSON(row.metadata),
|
|
2425
|
+
output: storage.safelyParseJSON(row.output),
|
|
2426
|
+
additionalContext: storage.safelyParseJSON(row.additionalContext),
|
|
2427
|
+
runtimeContext: storage.safelyParseJSON(row.runtimeContext),
|
|
2428
|
+
entity: storage.safelyParseJSON(row.entity),
|
|
2429
|
+
createdAt: new Date(row.createdAt),
|
|
2430
|
+
updatedAt: new Date(row.updatedAt)
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
2434
|
+
pool;
|
|
2435
|
+
operations;
|
|
2436
|
+
schema;
|
|
2437
|
+
constructor({
|
|
2438
|
+
pool,
|
|
2439
|
+
operations,
|
|
2440
|
+
schema
|
|
2441
|
+
}) {
|
|
2442
|
+
super();
|
|
2443
|
+
this.pool = pool;
|
|
2444
|
+
this.operations = operations;
|
|
2445
|
+
this.schema = schema;
|
|
2446
|
+
}
|
|
2447
|
+
async getScoreById({ id }) {
|
|
2448
|
+
try {
|
|
2449
|
+
const request = this.pool.request();
|
|
2450
|
+
request.input("p1", id);
|
|
2451
|
+
const result = await request.query(
|
|
2452
|
+
`SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE id = @p1`
|
|
2453
|
+
);
|
|
2454
|
+
if (result.recordset.length === 0) {
|
|
2455
|
+
return null;
|
|
2456
|
+
}
|
|
2457
|
+
return transformScoreRow(result.recordset[0]);
|
|
2458
|
+
} catch (error$1) {
|
|
2459
|
+
throw new error.MastraError(
|
|
2460
|
+
{
|
|
2461
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORE_BY_ID_FAILED",
|
|
2462
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2463
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2464
|
+
details: { id }
|
|
2465
|
+
},
|
|
2466
|
+
error$1
|
|
2467
|
+
);
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
async saveScore(score) {
|
|
2471
|
+
let validatedScore;
|
|
2472
|
+
try {
|
|
2473
|
+
validatedScore = scores.saveScorePayloadSchema.parse(score);
|
|
2474
|
+
} catch (error$1) {
|
|
2475
|
+
throw new error.MastraError(
|
|
2476
|
+
{
|
|
2477
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_VALIDATION_FAILED",
|
|
2478
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2479
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2480
|
+
},
|
|
2481
|
+
error$1
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
2484
|
+
try {
|
|
1483
2485
|
const scoreId = crypto.randomUUID();
|
|
1484
2486
|
const {
|
|
1485
2487
|
scorer,
|
|
@@ -1492,21 +2494,21 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1492
2494
|
runtimeContext,
|
|
1493
2495
|
entity,
|
|
1494
2496
|
...rest
|
|
1495
|
-
} =
|
|
2497
|
+
} = validatedScore;
|
|
1496
2498
|
await this.operations.insert({
|
|
1497
2499
|
tableName: storage.TABLE_SCORERS,
|
|
1498
2500
|
record: {
|
|
1499
2501
|
id: scoreId,
|
|
1500
2502
|
...rest,
|
|
1501
|
-
input:
|
|
1502
|
-
output:
|
|
1503
|
-
preprocessStepResult: preprocessStepResult
|
|
1504
|
-
analyzeStepResult: analyzeStepResult
|
|
1505
|
-
metadata: metadata
|
|
1506
|
-
additionalContext: additionalContext
|
|
1507
|
-
runtimeContext: runtimeContext
|
|
1508
|
-
entity: entity
|
|
1509
|
-
scorer: scorer
|
|
2503
|
+
input: input || "",
|
|
2504
|
+
output: output || "",
|
|
2505
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2506
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2507
|
+
metadata: metadata || null,
|
|
2508
|
+
additionalContext: additionalContext || null,
|
|
2509
|
+
runtimeContext: runtimeContext || null,
|
|
2510
|
+
entity: entity || null,
|
|
2511
|
+
scorer: scorer || null,
|
|
1510
2512
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1511
2513
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1512
2514
|
}
|
|
@@ -1526,14 +2528,37 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1526
2528
|
}
|
|
1527
2529
|
async getScoresByScorerId({
|
|
1528
2530
|
scorerId,
|
|
1529
|
-
pagination
|
|
2531
|
+
pagination,
|
|
2532
|
+
entityId,
|
|
2533
|
+
entityType,
|
|
2534
|
+
source
|
|
1530
2535
|
}) {
|
|
1531
2536
|
try {
|
|
1532
|
-
const
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
2537
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2538
|
+
const params = { p1: scorerId };
|
|
2539
|
+
let paramIndex = 2;
|
|
2540
|
+
if (entityId) {
|
|
2541
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2542
|
+
params[`p${paramIndex}`] = entityId;
|
|
2543
|
+
paramIndex++;
|
|
2544
|
+
}
|
|
2545
|
+
if (entityType) {
|
|
2546
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2547
|
+
params[`p${paramIndex}`] = entityType;
|
|
2548
|
+
paramIndex++;
|
|
2549
|
+
}
|
|
2550
|
+
if (source) {
|
|
2551
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2552
|
+
params[`p${paramIndex}`] = source;
|
|
2553
|
+
paramIndex++;
|
|
2554
|
+
}
|
|
2555
|
+
const whereClause = conditions.join(" AND ");
|
|
2556
|
+
const tableName = getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
|
|
2557
|
+
const countRequest = this.pool.request();
|
|
2558
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2559
|
+
countRequest.input(key, value);
|
|
2560
|
+
});
|
|
2561
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1537
2562
|
const total = totalResult.recordset[0]?.count || 0;
|
|
1538
2563
|
if (total === 0) {
|
|
1539
2564
|
return {
|
|
@@ -1547,12 +2572,13 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1547
2572
|
};
|
|
1548
2573
|
}
|
|
1549
2574
|
const dataRequest = this.pool.request();
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
2575
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2576
|
+
dataRequest.input(key, value);
|
|
2577
|
+
});
|
|
2578
|
+
dataRequest.input("perPage", pagination.perPage);
|
|
2579
|
+
dataRequest.input("offset", pagination.page * pagination.perPage);
|
|
2580
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2581
|
+
const result = await dataRequest.query(dataQuery);
|
|
1556
2582
|
return {
|
|
1557
2583
|
pagination: {
|
|
1558
2584
|
total: Number(total),
|
|
@@ -1677,6 +2703,60 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1677
2703
|
);
|
|
1678
2704
|
}
|
|
1679
2705
|
}
|
|
2706
|
+
async getScoresBySpan({
|
|
2707
|
+
traceId,
|
|
2708
|
+
spanId,
|
|
2709
|
+
pagination
|
|
2710
|
+
}) {
|
|
2711
|
+
try {
|
|
2712
|
+
const request = this.pool.request();
|
|
2713
|
+
request.input("p1", traceId);
|
|
2714
|
+
request.input("p2", spanId);
|
|
2715
|
+
const totalResult = await request.query(
|
|
2716
|
+
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
|
|
2717
|
+
);
|
|
2718
|
+
const total = totalResult.recordset[0]?.count || 0;
|
|
2719
|
+
if (total === 0) {
|
|
2720
|
+
return {
|
|
2721
|
+
pagination: {
|
|
2722
|
+
total: 0,
|
|
2723
|
+
page: pagination.page,
|
|
2724
|
+
perPage: pagination.perPage,
|
|
2725
|
+
hasMore: false
|
|
2726
|
+
},
|
|
2727
|
+
scores: []
|
|
2728
|
+
};
|
|
2729
|
+
}
|
|
2730
|
+
const limit = pagination.perPage + 1;
|
|
2731
|
+
const dataRequest = this.pool.request();
|
|
2732
|
+
dataRequest.input("p1", traceId);
|
|
2733
|
+
dataRequest.input("p2", spanId);
|
|
2734
|
+
dataRequest.input("p3", limit);
|
|
2735
|
+
dataRequest.input("p4", pagination.page * pagination.perPage);
|
|
2736
|
+
const result = await dataRequest.query(
|
|
2737
|
+
`SELECT * FROM ${getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
|
|
2738
|
+
);
|
|
2739
|
+
return {
|
|
2740
|
+
pagination: {
|
|
2741
|
+
total: Number(total),
|
|
2742
|
+
page: pagination.page,
|
|
2743
|
+
perPage: pagination.perPage,
|
|
2744
|
+
hasMore: result.recordset.length > pagination.perPage
|
|
2745
|
+
},
|
|
2746
|
+
scores: result.recordset.slice(0, pagination.perPage).map((row) => transformScoreRow(row))
|
|
2747
|
+
};
|
|
2748
|
+
} catch (error$1) {
|
|
2749
|
+
throw new error.MastraError(
|
|
2750
|
+
{
|
|
2751
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
2752
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2753
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2754
|
+
details: { traceId, spanId }
|
|
2755
|
+
},
|
|
2756
|
+
error$1
|
|
2757
|
+
);
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
1680
2760
|
};
|
|
1681
2761
|
var TracesMSSQL = class extends storage.TracesStorage {
|
|
1682
2762
|
pool;
|
|
@@ -1755,7 +2835,7 @@ var TracesMSSQL = class extends storage.TracesStorage {
|
|
|
1755
2835
|
const countRequest = this.pool.request();
|
|
1756
2836
|
Object.entries(paramMap).forEach(([key, value]) => {
|
|
1757
2837
|
if (value instanceof Date) {
|
|
1758
|
-
countRequest.input(key,
|
|
2838
|
+
countRequest.input(key, sql3__default.default.DateTime, value);
|
|
1759
2839
|
} else {
|
|
1760
2840
|
countRequest.input(key, value);
|
|
1761
2841
|
}
|
|
@@ -1789,7 +2869,7 @@ var TracesMSSQL = class extends storage.TracesStorage {
|
|
|
1789
2869
|
const dataRequest = this.pool.request();
|
|
1790
2870
|
Object.entries(paramMap).forEach(([key, value]) => {
|
|
1791
2871
|
if (value instanceof Date) {
|
|
1792
|
-
dataRequest.input(key,
|
|
2872
|
+
dataRequest.input(key, sql3__default.default.DateTime, value);
|
|
1793
2873
|
} else {
|
|
1794
2874
|
dataRequest.input(key, value);
|
|
1795
2875
|
}
|
|
@@ -1845,24 +2925,6 @@ var TracesMSSQL = class extends storage.TracesStorage {
|
|
|
1845
2925
|
});
|
|
1846
2926
|
}
|
|
1847
2927
|
};
|
|
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
2928
|
var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
1867
2929
|
pool;
|
|
1868
2930
|
operations;
|
|
@@ -1877,21 +2939,164 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1877
2939
|
this.operations = operations;
|
|
1878
2940
|
this.schema = schema;
|
|
1879
2941
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
2942
|
+
parseWorkflowRun(row) {
|
|
2943
|
+
let parsedSnapshot = row.snapshot;
|
|
2944
|
+
if (typeof parsedSnapshot === "string") {
|
|
2945
|
+
try {
|
|
2946
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2947
|
+
} catch (e) {
|
|
2948
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
return {
|
|
2952
|
+
workflowName: row.workflow_name,
|
|
2953
|
+
runId: row.run_id,
|
|
2954
|
+
snapshot: parsedSnapshot,
|
|
2955
|
+
createdAt: row.createdAt,
|
|
2956
|
+
updatedAt: row.updatedAt,
|
|
2957
|
+
resourceId: row.resourceId
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
async updateWorkflowResults({
|
|
2961
|
+
workflowName,
|
|
2962
|
+
runId,
|
|
2963
|
+
stepId,
|
|
2964
|
+
result,
|
|
2965
|
+
runtimeContext
|
|
1886
2966
|
}) {
|
|
1887
|
-
|
|
2967
|
+
const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2968
|
+
const transaction = this.pool.transaction();
|
|
2969
|
+
try {
|
|
2970
|
+
await transaction.begin();
|
|
2971
|
+
const selectRequest = new sql3__default.default.Request(transaction);
|
|
2972
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2973
|
+
selectRequest.input("run_id", runId);
|
|
2974
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2975
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2976
|
+
);
|
|
2977
|
+
let snapshot;
|
|
2978
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2979
|
+
snapshot = {
|
|
2980
|
+
context: {},
|
|
2981
|
+
activePaths: [],
|
|
2982
|
+
activeStepsPath: {},
|
|
2983
|
+
timestamp: Date.now(),
|
|
2984
|
+
suspendedPaths: {},
|
|
2985
|
+
resumeLabels: {},
|
|
2986
|
+
serializedStepGraph: [],
|
|
2987
|
+
status: "pending",
|
|
2988
|
+
value: {},
|
|
2989
|
+
waitingPaths: {},
|
|
2990
|
+
runId,
|
|
2991
|
+
runtimeContext: {}
|
|
2992
|
+
};
|
|
2993
|
+
} else {
|
|
2994
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2995
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2996
|
+
}
|
|
2997
|
+
snapshot.context[stepId] = result;
|
|
2998
|
+
snapshot.runtimeContext = { ...snapshot.runtimeContext, ...runtimeContext };
|
|
2999
|
+
const upsertReq = new sql3__default.default.Request(transaction);
|
|
3000
|
+
upsertReq.input("workflow_name", workflowName);
|
|
3001
|
+
upsertReq.input("run_id", runId);
|
|
3002
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
3003
|
+
upsertReq.input("createdAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
3004
|
+
upsertReq.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
3005
|
+
await upsertReq.query(
|
|
3006
|
+
`MERGE ${table} AS target
|
|
3007
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
3008
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
3009
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
3010
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
3011
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
3012
|
+
);
|
|
3013
|
+
await transaction.commit();
|
|
3014
|
+
return snapshot.context;
|
|
3015
|
+
} catch (error$1) {
|
|
3016
|
+
try {
|
|
3017
|
+
await transaction.rollback();
|
|
3018
|
+
} catch {
|
|
3019
|
+
}
|
|
3020
|
+
throw new error.MastraError(
|
|
3021
|
+
{
|
|
3022
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
|
|
3023
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3024
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
3025
|
+
details: {
|
|
3026
|
+
workflowName,
|
|
3027
|
+
runId,
|
|
3028
|
+
stepId
|
|
3029
|
+
}
|
|
3030
|
+
},
|
|
3031
|
+
error$1
|
|
3032
|
+
);
|
|
3033
|
+
}
|
|
1888
3034
|
}
|
|
1889
|
-
updateWorkflowState({
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
3035
|
+
async updateWorkflowState({
|
|
3036
|
+
workflowName,
|
|
3037
|
+
runId,
|
|
3038
|
+
opts
|
|
1893
3039
|
}) {
|
|
1894
|
-
|
|
3040
|
+
const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
3041
|
+
const transaction = this.pool.transaction();
|
|
3042
|
+
try {
|
|
3043
|
+
await transaction.begin();
|
|
3044
|
+
const selectRequest = new sql3__default.default.Request(transaction);
|
|
3045
|
+
selectRequest.input("workflow_name", workflowName);
|
|
3046
|
+
selectRequest.input("run_id", runId);
|
|
3047
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
3048
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
3049
|
+
);
|
|
3050
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
3051
|
+
await transaction.rollback();
|
|
3052
|
+
return void 0;
|
|
3053
|
+
}
|
|
3054
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
3055
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
3056
|
+
if (!snapshot || !snapshot?.context) {
|
|
3057
|
+
await transaction.rollback();
|
|
3058
|
+
throw new error.MastraError(
|
|
3059
|
+
{
|
|
3060
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
|
|
3061
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3062
|
+
category: error.ErrorCategory.SYSTEM,
|
|
3063
|
+
details: {
|
|
3064
|
+
workflowName,
|
|
3065
|
+
runId
|
|
3066
|
+
}
|
|
3067
|
+
},
|
|
3068
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
3069
|
+
);
|
|
3070
|
+
}
|
|
3071
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
3072
|
+
const updateRequest = new sql3__default.default.Request(transaction);
|
|
3073
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
3074
|
+
updateRequest.input("workflow_name", workflowName);
|
|
3075
|
+
updateRequest.input("run_id", runId);
|
|
3076
|
+
updateRequest.input("updatedAt", sql3__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
3077
|
+
await updateRequest.query(
|
|
3078
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
3079
|
+
);
|
|
3080
|
+
await transaction.commit();
|
|
3081
|
+
return updatedSnapshot;
|
|
3082
|
+
} catch (error$1) {
|
|
3083
|
+
try {
|
|
3084
|
+
await transaction.rollback();
|
|
3085
|
+
} catch {
|
|
3086
|
+
}
|
|
3087
|
+
throw new error.MastraError(
|
|
3088
|
+
{
|
|
3089
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
|
|
3090
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3091
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
3092
|
+
details: {
|
|
3093
|
+
workflowName,
|
|
3094
|
+
runId
|
|
3095
|
+
}
|
|
3096
|
+
},
|
|
3097
|
+
error$1
|
|
3098
|
+
);
|
|
3099
|
+
}
|
|
1895
3100
|
}
|
|
1896
3101
|
async persistWorkflowSnapshot({
|
|
1897
3102
|
workflowName,
|
|
@@ -1907,8 +3112,8 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1907
3112
|
request.input("run_id", runId);
|
|
1908
3113
|
request.input("resourceId", resourceId);
|
|
1909
3114
|
request.input("snapshot", JSON.stringify(snapshot));
|
|
1910
|
-
request.input("createdAt",
|
|
1911
|
-
request.input("updatedAt",
|
|
3115
|
+
request.input("createdAt", sql3__default.default.DateTime2, new Date(now));
|
|
3116
|
+
request.input("updatedAt", sql3__default.default.DateTime2, new Date(now));
|
|
1912
3117
|
const mergeSql = `MERGE INTO ${table} AS target
|
|
1913
3118
|
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
1914
3119
|
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
@@ -1989,7 +3194,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
1989
3194
|
if (!result.recordset || result.recordset.length === 0) {
|
|
1990
3195
|
return null;
|
|
1991
3196
|
}
|
|
1992
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
3197
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
1993
3198
|
} catch (error$1) {
|
|
1994
3199
|
throw new error.MastraError(
|
|
1995
3200
|
{
|
|
@@ -2011,7 +3216,8 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2011
3216
|
toDate,
|
|
2012
3217
|
limit,
|
|
2013
3218
|
offset,
|
|
2014
|
-
resourceId
|
|
3219
|
+
resourceId,
|
|
3220
|
+
status
|
|
2015
3221
|
} = {}) {
|
|
2016
3222
|
try {
|
|
2017
3223
|
const conditions = [];
|
|
@@ -2020,13 +3226,17 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2020
3226
|
conditions.push(`[workflow_name] = @workflowName`);
|
|
2021
3227
|
paramMap["workflowName"] = workflowName;
|
|
2022
3228
|
}
|
|
3229
|
+
if (status) {
|
|
3230
|
+
conditions.push(`JSON_VALUE([snapshot], '$.status') = @status`);
|
|
3231
|
+
paramMap["status"] = status;
|
|
3232
|
+
}
|
|
2023
3233
|
if (resourceId) {
|
|
2024
3234
|
const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2025
3235
|
if (hasResourceId) {
|
|
2026
3236
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2027
3237
|
paramMap["resourceId"] = resourceId;
|
|
2028
3238
|
} else {
|
|
2029
|
-
|
|
3239
|
+
this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2030
3240
|
}
|
|
2031
3241
|
}
|
|
2032
3242
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2043,7 +3253,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2043
3253
|
const request = this.pool.request();
|
|
2044
3254
|
Object.entries(paramMap).forEach(([key, value]) => {
|
|
2045
3255
|
if (value instanceof Date) {
|
|
2046
|
-
request.input(key,
|
|
3256
|
+
request.input(key, sql3__default.default.DateTime, value);
|
|
2047
3257
|
} else {
|
|
2048
3258
|
request.input(key, value);
|
|
2049
3259
|
}
|
|
@@ -2060,7 +3270,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2060
3270
|
request.input("offset", offset);
|
|
2061
3271
|
}
|
|
2062
3272
|
const result = await request.query(query);
|
|
2063
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
3273
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2064
3274
|
return { runs, total: total || runs.length };
|
|
2065
3275
|
} catch (error$1) {
|
|
2066
3276
|
throw new error.MastraError(
|
|
@@ -2100,7 +3310,7 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2100
3310
|
}
|
|
2101
3311
|
}
|
|
2102
3312
|
this.schema = config.schemaName || "dbo";
|
|
2103
|
-
this.pool = "connectionString" in config ? new
|
|
3313
|
+
this.pool = "connectionString" in config ? new sql3__default.default.ConnectionPool(config.connectionString) : new sql3__default.default.ConnectionPool({
|
|
2104
3314
|
server: config.server,
|
|
2105
3315
|
database: config.database,
|
|
2106
3316
|
user: config.user,
|
|
@@ -2114,13 +3324,15 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2114
3324
|
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2115
3325
|
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2116
3326
|
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
3327
|
+
const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2117
3328
|
this.stores = {
|
|
2118
3329
|
operations,
|
|
2119
3330
|
scores,
|
|
2120
3331
|
traces,
|
|
2121
3332
|
workflows,
|
|
2122
3333
|
legacyEvals,
|
|
2123
|
-
memory
|
|
3334
|
+
memory,
|
|
3335
|
+
observability
|
|
2124
3336
|
};
|
|
2125
3337
|
} catch (e) {
|
|
2126
3338
|
throw new error.MastraError(
|
|
@@ -2140,6 +3352,11 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2140
3352
|
try {
|
|
2141
3353
|
await this.isConnected;
|
|
2142
3354
|
await super.init();
|
|
3355
|
+
try {
|
|
3356
|
+
await this.stores.operations.createAutomaticIndexes();
|
|
3357
|
+
} catch (indexError) {
|
|
3358
|
+
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
3359
|
+
}
|
|
2143
3360
|
} catch (error$1) {
|
|
2144
3361
|
this.isConnected = null;
|
|
2145
3362
|
throw new error.MastraError(
|
|
@@ -2166,7 +3383,10 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2166
3383
|
resourceWorkingMemory: true,
|
|
2167
3384
|
hasColumn: true,
|
|
2168
3385
|
createTable: true,
|
|
2169
|
-
deleteMessages: true
|
|
3386
|
+
deleteMessages: true,
|
|
3387
|
+
getScoresBySpan: true,
|
|
3388
|
+
aiTracing: true,
|
|
3389
|
+
indexManagement: true
|
|
2170
3390
|
};
|
|
2171
3391
|
}
|
|
2172
3392
|
/** @deprecated use getEvals instead */
|
|
@@ -2313,15 +3533,8 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2313
3533
|
}) {
|
|
2314
3534
|
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2315
3535
|
}
|
|
2316
|
-
async getWorkflowRuns({
|
|
2317
|
-
|
|
2318
|
-
fromDate,
|
|
2319
|
-
toDate,
|
|
2320
|
-
limit,
|
|
2321
|
-
offset,
|
|
2322
|
-
resourceId
|
|
2323
|
-
} = {}) {
|
|
2324
|
-
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
3536
|
+
async getWorkflowRuns(args = {}) {
|
|
3537
|
+
return this.stores.workflows.getWorkflowRuns(args);
|
|
2325
3538
|
}
|
|
2326
3539
|
async getWorkflowRunById({
|
|
2327
3540
|
runId,
|
|
@@ -2332,6 +3545,60 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2332
3545
|
async close() {
|
|
2333
3546
|
await this.pool.close();
|
|
2334
3547
|
}
|
|
3548
|
+
/**
|
|
3549
|
+
* Index Management
|
|
3550
|
+
*/
|
|
3551
|
+
async createIndex(options) {
|
|
3552
|
+
return this.stores.operations.createIndex(options);
|
|
3553
|
+
}
|
|
3554
|
+
async listIndexes(tableName) {
|
|
3555
|
+
return this.stores.operations.listIndexes(tableName);
|
|
3556
|
+
}
|
|
3557
|
+
async describeIndex(indexName) {
|
|
3558
|
+
return this.stores.operations.describeIndex(indexName);
|
|
3559
|
+
}
|
|
3560
|
+
async dropIndex(indexName) {
|
|
3561
|
+
return this.stores.operations.dropIndex(indexName);
|
|
3562
|
+
}
|
|
3563
|
+
/**
|
|
3564
|
+
* AI Tracing / Observability
|
|
3565
|
+
*/
|
|
3566
|
+
getObservabilityStore() {
|
|
3567
|
+
if (!this.stores.observability) {
|
|
3568
|
+
throw new error.MastraError({
|
|
3569
|
+
id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
3570
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3571
|
+
category: error.ErrorCategory.SYSTEM,
|
|
3572
|
+
text: "Observability storage is not initialized"
|
|
3573
|
+
});
|
|
3574
|
+
}
|
|
3575
|
+
return this.stores.observability;
|
|
3576
|
+
}
|
|
3577
|
+
async createAISpan(span) {
|
|
3578
|
+
return this.getObservabilityStore().createAISpan(span);
|
|
3579
|
+
}
|
|
3580
|
+
async updateAISpan({
|
|
3581
|
+
spanId,
|
|
3582
|
+
traceId,
|
|
3583
|
+
updates
|
|
3584
|
+
}) {
|
|
3585
|
+
return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
|
|
3586
|
+
}
|
|
3587
|
+
async getAITrace(traceId) {
|
|
3588
|
+
return this.getObservabilityStore().getAITrace(traceId);
|
|
3589
|
+
}
|
|
3590
|
+
async getAITracesPaginated(args) {
|
|
3591
|
+
return this.getObservabilityStore().getAITracesPaginated(args);
|
|
3592
|
+
}
|
|
3593
|
+
async batchCreateAISpans(args) {
|
|
3594
|
+
return this.getObservabilityStore().batchCreateAISpans(args);
|
|
3595
|
+
}
|
|
3596
|
+
async batchUpdateAISpans(args) {
|
|
3597
|
+
return this.getObservabilityStore().batchUpdateAISpans(args);
|
|
3598
|
+
}
|
|
3599
|
+
async batchDeleteAITraces(args) {
|
|
3600
|
+
return this.getObservabilityStore().batchDeleteAITraces(args);
|
|
3601
|
+
}
|
|
2335
3602
|
/**
|
|
2336
3603
|
* Scorers
|
|
2337
3604
|
*/
|
|
@@ -2340,9 +3607,18 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2340
3607
|
}
|
|
2341
3608
|
async getScoresByScorerId({
|
|
2342
3609
|
scorerId: _scorerId,
|
|
2343
|
-
pagination: _pagination
|
|
3610
|
+
pagination: _pagination,
|
|
3611
|
+
entityId: _entityId,
|
|
3612
|
+
entityType: _entityType,
|
|
3613
|
+
source: _source
|
|
2344
3614
|
}) {
|
|
2345
|
-
return this.stores.scores.getScoresByScorerId({
|
|
3615
|
+
return this.stores.scores.getScoresByScorerId({
|
|
3616
|
+
scorerId: _scorerId,
|
|
3617
|
+
pagination: _pagination,
|
|
3618
|
+
entityId: _entityId,
|
|
3619
|
+
entityType: _entityType,
|
|
3620
|
+
source: _source
|
|
3621
|
+
});
|
|
2346
3622
|
}
|
|
2347
3623
|
async saveScore(_score) {
|
|
2348
3624
|
return this.stores.scores.saveScore(_score);
|
|
@@ -2364,6 +3640,13 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2364
3640
|
pagination: _pagination
|
|
2365
3641
|
});
|
|
2366
3642
|
}
|
|
3643
|
+
async getScoresBySpan({
|
|
3644
|
+
traceId,
|
|
3645
|
+
spanId,
|
|
3646
|
+
pagination: _pagination
|
|
3647
|
+
}) {
|
|
3648
|
+
return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination: _pagination });
|
|
3649
|
+
}
|
|
2367
3650
|
};
|
|
2368
3651
|
|
|
2369
3652
|
exports.MSSQLStore = MSSQLStore;
|