@mastra/mssql 0.0.0-pgvector-index-fix-20250905222058 → 0.0.0-playground-studio-cloud-20251031080052
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 +167 -10
- package/README.md +315 -36
- package/dist/index.cjs +1412 -320
- 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 +1413 -321
- 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 -3
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +54 -15
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/storage/domains/traces/index.d.ts +0 -37
- package/dist/storage/domains/traces/index.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
2
|
-
import { MastraStorage, LegacyEvalsStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT,
|
|
3
|
-
import
|
|
4
|
-
import { parseSqlIdentifier
|
|
2
|
+
import { MastraStorage, LegacyEvalsStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_EVALS, TABLE_SCORERS, TABLE_AI_SPANS, ScoresStorage, WorkflowsStorage, MemoryStorage, resolveMessageLimit, TABLE_RESOURCES, ObservabilityStorage, safelyParseJSON } from '@mastra/core/storage';
|
|
3
|
+
import sql3 from 'mssql';
|
|
4
|
+
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
5
5
|
import { MessageList } from '@mastra/core/agent';
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
7
|
+
import { saveScorePayloadSchema } from '@mastra/core/scores';
|
|
6
8
|
|
|
7
9
|
// src/storage/index.ts
|
|
8
10
|
function getSchemaName(schema) {
|
|
@@ -14,6 +16,69 @@ function getTableName({ indexName, schemaName }) {
|
|
|
14
16
|
const quotedSchemaName = schemaName;
|
|
15
17
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
16
18
|
}
|
|
19
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
20
|
+
const filters = {};
|
|
21
|
+
if (dateRange?.start) {
|
|
22
|
+
filters[`${fieldName}_gte`] = dateRange.start;
|
|
23
|
+
}
|
|
24
|
+
if (dateRange?.end) {
|
|
25
|
+
filters[`${fieldName}_lte`] = dateRange.end;
|
|
26
|
+
}
|
|
27
|
+
return filters;
|
|
28
|
+
}
|
|
29
|
+
function prepareWhereClause(filters, _schema) {
|
|
30
|
+
const conditions = [];
|
|
31
|
+
const params = {};
|
|
32
|
+
let paramIndex = 1;
|
|
33
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
34
|
+
if (value === void 0) return;
|
|
35
|
+
const paramName = `p${paramIndex++}`;
|
|
36
|
+
if (key.endsWith("_gte")) {
|
|
37
|
+
const fieldName = key.slice(0, -4);
|
|
38
|
+
conditions.push(`[${parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
|
|
39
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
40
|
+
} else if (key.endsWith("_lte")) {
|
|
41
|
+
const fieldName = key.slice(0, -4);
|
|
42
|
+
conditions.push(`[${parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
|
|
43
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
44
|
+
} else if (value === null) {
|
|
45
|
+
conditions.push(`[${parseSqlIdentifier(key, "field name")}] IS NULL`);
|
|
46
|
+
} else {
|
|
47
|
+
conditions.push(`[${parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
48
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
53
|
+
params
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function transformFromSqlRow({
|
|
57
|
+
tableName,
|
|
58
|
+
sqlRow
|
|
59
|
+
}) {
|
|
60
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
61
|
+
const result = {};
|
|
62
|
+
Object.entries(sqlRow).forEach(([key, value]) => {
|
|
63
|
+
const columnSchema = schema?.[key];
|
|
64
|
+
if (columnSchema?.type === "jsonb" && typeof value === "string") {
|
|
65
|
+
try {
|
|
66
|
+
result[key] = JSON.parse(value);
|
|
67
|
+
} catch {
|
|
68
|
+
result[key] = value;
|
|
69
|
+
}
|
|
70
|
+
} else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
|
|
71
|
+
result[key] = new Date(value);
|
|
72
|
+
} else if (columnSchema?.type === "timestamp" && value instanceof Date) {
|
|
73
|
+
result[key] = value;
|
|
74
|
+
} else if (columnSchema?.type === "boolean") {
|
|
75
|
+
result[key] = Boolean(value);
|
|
76
|
+
} else {
|
|
77
|
+
result[key] = value;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
17
82
|
|
|
18
83
|
// src/storage/domains/legacy-evals/index.ts
|
|
19
84
|
function transformEvalRow(row) {
|
|
@@ -24,7 +89,7 @@ function transformEvalRow(row) {
|
|
|
24
89
|
} catch {
|
|
25
90
|
}
|
|
26
91
|
}
|
|
27
|
-
if (row.
|
|
92
|
+
if (row.result) {
|
|
28
93
|
try {
|
|
29
94
|
resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
|
|
30
95
|
} catch {
|
|
@@ -70,7 +135,7 @@ var LegacyEvalsMSSQL = class extends LegacyEvalsStorage {
|
|
|
70
135
|
if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
|
|
71
136
|
return [];
|
|
72
137
|
}
|
|
73
|
-
|
|
138
|
+
this.logger?.error?.("Failed to get evals for the specified agent:", error);
|
|
74
139
|
throw error;
|
|
75
140
|
}
|
|
76
141
|
}
|
|
@@ -106,7 +171,7 @@ var LegacyEvalsMSSQL = class extends LegacyEvalsStorage {
|
|
|
106
171
|
const countReq = this.pool.request();
|
|
107
172
|
Object.entries(params).forEach(([key, value]) => {
|
|
108
173
|
if (value instanceof Date) {
|
|
109
|
-
countReq.input(key,
|
|
174
|
+
countReq.input(key, sql3.DateTime, value);
|
|
110
175
|
} else {
|
|
111
176
|
countReq.input(key, value);
|
|
112
177
|
}
|
|
@@ -125,7 +190,7 @@ var LegacyEvalsMSSQL = class extends LegacyEvalsStorage {
|
|
|
125
190
|
const req = this.pool.request();
|
|
126
191
|
Object.entries(params).forEach(([key, value]) => {
|
|
127
192
|
if (value instanceof Date) {
|
|
128
|
-
req.input(key,
|
|
193
|
+
req.input(key, sql3.DateTime, value);
|
|
129
194
|
} else {
|
|
130
195
|
req.input(key, value);
|
|
131
196
|
}
|
|
@@ -157,7 +222,7 @@ var LegacyEvalsMSSQL = class extends LegacyEvalsStorage {
|
|
|
157
222
|
error
|
|
158
223
|
);
|
|
159
224
|
this.logger?.error?.(mastraError.toString());
|
|
160
|
-
this.logger?.trackException(mastraError);
|
|
225
|
+
this.logger?.trackException?.(mastraError);
|
|
161
226
|
throw mastraError;
|
|
162
227
|
}
|
|
163
228
|
}
|
|
@@ -193,7 +258,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
193
258
|
}
|
|
194
259
|
async getThreadById({ threadId }) {
|
|
195
260
|
try {
|
|
196
|
-
const
|
|
261
|
+
const sql6 = `SELECT
|
|
197
262
|
id,
|
|
198
263
|
[resourceId],
|
|
199
264
|
title,
|
|
@@ -204,7 +269,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
204
269
|
WHERE id = @threadId`;
|
|
205
270
|
const request = this.pool.request();
|
|
206
271
|
request.input("threadId", threadId);
|
|
207
|
-
const resultSet = await request.query(
|
|
272
|
+
const resultSet = await request.query(sql6);
|
|
208
273
|
const thread = resultSet.recordset[0] || null;
|
|
209
274
|
if (!thread) {
|
|
210
275
|
return null;
|
|
@@ -250,7 +315,8 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
250
315
|
};
|
|
251
316
|
}
|
|
252
317
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
253
|
-
const
|
|
318
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
319
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
254
320
|
const dataRequest = this.pool.request();
|
|
255
321
|
dataRequest.input("resourceId", resourceId);
|
|
256
322
|
dataRequest.input("perPage", perPage);
|
|
@@ -307,9 +373,14 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
307
373
|
req.input("id", thread.id);
|
|
308
374
|
req.input("resourceId", thread.resourceId);
|
|
309
375
|
req.input("title", thread.title);
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
376
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
377
|
+
if (metadata === null) {
|
|
378
|
+
req.input("metadata", sql3.NVarChar, null);
|
|
379
|
+
} else {
|
|
380
|
+
req.input("metadata", metadata);
|
|
381
|
+
}
|
|
382
|
+
req.input("createdAt", sql3.DateTime2, thread.createdAt);
|
|
383
|
+
req.input("updatedAt", sql3.DateTime2, thread.updatedAt);
|
|
313
384
|
await req.query(mergeSql);
|
|
314
385
|
return thread;
|
|
315
386
|
} catch (error) {
|
|
@@ -334,7 +405,8 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
334
405
|
try {
|
|
335
406
|
const baseQuery = `FROM ${getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
336
407
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
337
|
-
const
|
|
408
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
409
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
|
|
338
410
|
const request = this.pool.request();
|
|
339
411
|
request.input("resourceId", resourceId);
|
|
340
412
|
const resultSet = await request.query(dataQuery);
|
|
@@ -377,7 +449,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
377
449
|
};
|
|
378
450
|
try {
|
|
379
451
|
const table = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
380
|
-
const
|
|
452
|
+
const sql6 = `UPDATE ${table}
|
|
381
453
|
SET title = @title,
|
|
382
454
|
metadata = @metadata,
|
|
383
455
|
[updatedAt] = @updatedAt
|
|
@@ -388,7 +460,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
388
460
|
req.input("title", title);
|
|
389
461
|
req.input("metadata", JSON.stringify(mergedMetadata));
|
|
390
462
|
req.input("updatedAt", /* @__PURE__ */ new Date());
|
|
391
|
-
const result = await req.query(
|
|
463
|
+
const result = await req.query(sql6);
|
|
392
464
|
let thread = result.recordset && result.recordset[0];
|
|
393
465
|
if (thread && "seq_id" in thread) {
|
|
394
466
|
const { seq_id, ...rest } = thread;
|
|
@@ -583,7 +655,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
583
655
|
error
|
|
584
656
|
);
|
|
585
657
|
this.logger?.error?.(mastraError.toString());
|
|
586
|
-
this.logger?.trackException(mastraError);
|
|
658
|
+
this.logger?.trackException?.(mastraError);
|
|
587
659
|
return [];
|
|
588
660
|
}
|
|
589
661
|
}
|
|
@@ -623,7 +695,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
623
695
|
error
|
|
624
696
|
);
|
|
625
697
|
this.logger?.error?.(mastraError.toString());
|
|
626
|
-
this.logger?.trackException(mastraError);
|
|
698
|
+
this.logger?.trackException?.(mastraError);
|
|
627
699
|
return [];
|
|
628
700
|
}
|
|
629
701
|
}
|
|
@@ -685,7 +757,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
685
757
|
const parsed = this._parseAndFormatMessages(messages, format);
|
|
686
758
|
return {
|
|
687
759
|
messages: parsed,
|
|
688
|
-
total
|
|
760
|
+
total,
|
|
689
761
|
page,
|
|
690
762
|
perPage,
|
|
691
763
|
hasMore: currentOffset + rows.length < total
|
|
@@ -705,7 +777,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
705
777
|
error
|
|
706
778
|
);
|
|
707
779
|
this.logger?.error?.(mastraError.toString());
|
|
708
|
-
this.logger?.trackException(mastraError);
|
|
780
|
+
this.logger?.trackException?.(mastraError);
|
|
709
781
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
710
782
|
}
|
|
711
783
|
}
|
|
@@ -757,7 +829,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
757
829
|
"content",
|
|
758
830
|
typeof message.content === "string" ? message.content : JSON.stringify(message.content)
|
|
759
831
|
);
|
|
760
|
-
request.input("createdAt",
|
|
832
|
+
request.input("createdAt", sql3.DateTime2, message.createdAt);
|
|
761
833
|
request.input("role", message.role);
|
|
762
834
|
request.input("type", message.type || "v2");
|
|
763
835
|
request.input("resourceId", message.resourceId);
|
|
@@ -776,7 +848,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
776
848
|
await request.query(mergeSql);
|
|
777
849
|
}
|
|
778
850
|
const threadReq = transaction.request();
|
|
779
|
-
threadReq.input("updatedAt",
|
|
851
|
+
threadReq.input("updatedAt", sql3.DateTime2, /* @__PURE__ */ new Date());
|
|
780
852
|
threadReq.input("id", threadId);
|
|
781
853
|
await threadReq.query(`UPDATE ${tableThreads} SET [updatedAt] = @updatedAt WHERE id = @id`);
|
|
782
854
|
await transaction.commit();
|
|
@@ -972,8 +1044,10 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
972
1044
|
return null;
|
|
973
1045
|
}
|
|
974
1046
|
return {
|
|
975
|
-
|
|
976
|
-
|
|
1047
|
+
id: result.id,
|
|
1048
|
+
createdAt: result.createdAt,
|
|
1049
|
+
updatedAt: result.updatedAt,
|
|
1050
|
+
workingMemory: result.workingMemory,
|
|
977
1051
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
978
1052
|
};
|
|
979
1053
|
} catch (error) {
|
|
@@ -987,7 +1061,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
987
1061
|
error
|
|
988
1062
|
);
|
|
989
1063
|
this.logger?.error?.(mastraError.toString());
|
|
990
|
-
this.logger?.trackException(mastraError);
|
|
1064
|
+
this.logger?.trackException?.(mastraError);
|
|
991
1065
|
throw mastraError;
|
|
992
1066
|
}
|
|
993
1067
|
}
|
|
@@ -996,7 +1070,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
996
1070
|
tableName: TABLE_RESOURCES,
|
|
997
1071
|
record: {
|
|
998
1072
|
...resource,
|
|
999
|
-
metadata:
|
|
1073
|
+
metadata: resource.metadata
|
|
1000
1074
|
}
|
|
1001
1075
|
});
|
|
1002
1076
|
return resource;
|
|
@@ -1054,20 +1128,337 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
1054
1128
|
error
|
|
1055
1129
|
);
|
|
1056
1130
|
this.logger?.error?.(mastraError.toString());
|
|
1057
|
-
this.logger?.trackException(mastraError);
|
|
1131
|
+
this.logger?.trackException?.(mastraError);
|
|
1058
1132
|
throw mastraError;
|
|
1059
1133
|
}
|
|
1060
1134
|
}
|
|
1061
1135
|
};
|
|
1136
|
+
var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
1137
|
+
pool;
|
|
1138
|
+
operations;
|
|
1139
|
+
schema;
|
|
1140
|
+
constructor({
|
|
1141
|
+
pool,
|
|
1142
|
+
operations,
|
|
1143
|
+
schema
|
|
1144
|
+
}) {
|
|
1145
|
+
super();
|
|
1146
|
+
this.pool = pool;
|
|
1147
|
+
this.operations = operations;
|
|
1148
|
+
this.schema = schema;
|
|
1149
|
+
}
|
|
1150
|
+
get aiTracingStrategy() {
|
|
1151
|
+
return {
|
|
1152
|
+
preferred: "batch-with-updates",
|
|
1153
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
async createAISpan(span) {
|
|
1157
|
+
try {
|
|
1158
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
1159
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
1160
|
+
const record = {
|
|
1161
|
+
...span,
|
|
1162
|
+
startedAt,
|
|
1163
|
+
endedAt
|
|
1164
|
+
// Note: createdAt/updatedAt will be set by default values
|
|
1165
|
+
};
|
|
1166
|
+
return this.operations.insert({ tableName: TABLE_AI_SPANS, record });
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
throw new MastraError(
|
|
1169
|
+
{
|
|
1170
|
+
id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
|
|
1171
|
+
domain: ErrorDomain.STORAGE,
|
|
1172
|
+
category: ErrorCategory.USER,
|
|
1173
|
+
details: {
|
|
1174
|
+
spanId: span.spanId,
|
|
1175
|
+
traceId: span.traceId,
|
|
1176
|
+
spanType: span.spanType,
|
|
1177
|
+
spanName: span.name
|
|
1178
|
+
}
|
|
1179
|
+
},
|
|
1180
|
+
error
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
async getAITrace(traceId) {
|
|
1185
|
+
try {
|
|
1186
|
+
const tableName = getTableName({
|
|
1187
|
+
indexName: TABLE_AI_SPANS,
|
|
1188
|
+
schemaName: getSchemaName(this.schema)
|
|
1189
|
+
});
|
|
1190
|
+
const request = this.pool.request();
|
|
1191
|
+
request.input("traceId", traceId);
|
|
1192
|
+
const result = await request.query(
|
|
1193
|
+
`SELECT
|
|
1194
|
+
[traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
|
|
1195
|
+
[attributes], [metadata], [links], [input], [output], [error], [isEvent],
|
|
1196
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
1197
|
+
FROM ${tableName}
|
|
1198
|
+
WHERE [traceId] = @traceId
|
|
1199
|
+
ORDER BY [startedAt] DESC`
|
|
1200
|
+
);
|
|
1201
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1202
|
+
return null;
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
traceId,
|
|
1206
|
+
spans: result.recordset.map(
|
|
1207
|
+
(span) => transformFromSqlRow({
|
|
1208
|
+
tableName: TABLE_AI_SPANS,
|
|
1209
|
+
sqlRow: span
|
|
1210
|
+
})
|
|
1211
|
+
)
|
|
1212
|
+
};
|
|
1213
|
+
} catch (error) {
|
|
1214
|
+
throw new MastraError(
|
|
1215
|
+
{
|
|
1216
|
+
id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
|
|
1217
|
+
domain: ErrorDomain.STORAGE,
|
|
1218
|
+
category: ErrorCategory.USER,
|
|
1219
|
+
details: {
|
|
1220
|
+
traceId
|
|
1221
|
+
}
|
|
1222
|
+
},
|
|
1223
|
+
error
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
async updateAISpan({
|
|
1228
|
+
spanId,
|
|
1229
|
+
traceId,
|
|
1230
|
+
updates
|
|
1231
|
+
}) {
|
|
1232
|
+
try {
|
|
1233
|
+
const data = { ...updates };
|
|
1234
|
+
if (data.endedAt instanceof Date) {
|
|
1235
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1236
|
+
}
|
|
1237
|
+
if (data.startedAt instanceof Date) {
|
|
1238
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1239
|
+
}
|
|
1240
|
+
await this.operations.update({
|
|
1241
|
+
tableName: TABLE_AI_SPANS,
|
|
1242
|
+
keys: { spanId, traceId },
|
|
1243
|
+
data
|
|
1244
|
+
});
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
throw new MastraError(
|
|
1247
|
+
{
|
|
1248
|
+
id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
|
|
1249
|
+
domain: ErrorDomain.STORAGE,
|
|
1250
|
+
category: ErrorCategory.USER,
|
|
1251
|
+
details: {
|
|
1252
|
+
spanId,
|
|
1253
|
+
traceId
|
|
1254
|
+
}
|
|
1255
|
+
},
|
|
1256
|
+
error
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
async getAITracesPaginated({
|
|
1261
|
+
filters,
|
|
1262
|
+
pagination
|
|
1263
|
+
}) {
|
|
1264
|
+
const page = pagination?.page ?? 0;
|
|
1265
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1266
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1267
|
+
const filtersWithDateRange = {
|
|
1268
|
+
...actualFilters,
|
|
1269
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
1270
|
+
parentSpanId: null
|
|
1271
|
+
// Only get root spans for traces
|
|
1272
|
+
};
|
|
1273
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
1274
|
+
let actualWhereClause = whereClause.sql;
|
|
1275
|
+
const params = { ...whereClause.params };
|
|
1276
|
+
let currentParamIndex = Object.keys(params).length + 1;
|
|
1277
|
+
if (entityId && entityType) {
|
|
1278
|
+
let name = "";
|
|
1279
|
+
if (entityType === "workflow") {
|
|
1280
|
+
name = `workflow run: '${entityId}'`;
|
|
1281
|
+
} else if (entityType === "agent") {
|
|
1282
|
+
name = `agent run: '${entityId}'`;
|
|
1283
|
+
} else {
|
|
1284
|
+
const error = new MastraError({
|
|
1285
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1286
|
+
domain: ErrorDomain.STORAGE,
|
|
1287
|
+
category: ErrorCategory.USER,
|
|
1288
|
+
details: {
|
|
1289
|
+
entityType
|
|
1290
|
+
},
|
|
1291
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1292
|
+
});
|
|
1293
|
+
throw error;
|
|
1294
|
+
}
|
|
1295
|
+
const entityParam = `p${currentParamIndex++}`;
|
|
1296
|
+
if (actualWhereClause) {
|
|
1297
|
+
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
1298
|
+
} else {
|
|
1299
|
+
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
1300
|
+
}
|
|
1301
|
+
params[entityParam] = name;
|
|
1302
|
+
}
|
|
1303
|
+
const tableName = getTableName({
|
|
1304
|
+
indexName: TABLE_AI_SPANS,
|
|
1305
|
+
schemaName: getSchemaName(this.schema)
|
|
1306
|
+
});
|
|
1307
|
+
try {
|
|
1308
|
+
const countRequest = this.pool.request();
|
|
1309
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1310
|
+
countRequest.input(key, value);
|
|
1311
|
+
});
|
|
1312
|
+
const countResult = await countRequest.query(
|
|
1313
|
+
`SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
|
|
1314
|
+
);
|
|
1315
|
+
const total = countResult.recordset[0]?.count ?? 0;
|
|
1316
|
+
if (total === 0) {
|
|
1317
|
+
return {
|
|
1318
|
+
pagination: {
|
|
1319
|
+
total: 0,
|
|
1320
|
+
page,
|
|
1321
|
+
perPage,
|
|
1322
|
+
hasMore: false
|
|
1323
|
+
},
|
|
1324
|
+
spans: []
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
const dataRequest = this.pool.request();
|
|
1328
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1329
|
+
dataRequest.input(key, value);
|
|
1330
|
+
});
|
|
1331
|
+
dataRequest.input("offset", page * perPage);
|
|
1332
|
+
dataRequest.input("limit", perPage);
|
|
1333
|
+
const dataResult = await dataRequest.query(
|
|
1334
|
+
`SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1335
|
+
);
|
|
1336
|
+
const spans = dataResult.recordset.map(
|
|
1337
|
+
(row) => transformFromSqlRow({
|
|
1338
|
+
tableName: TABLE_AI_SPANS,
|
|
1339
|
+
sqlRow: row
|
|
1340
|
+
})
|
|
1341
|
+
);
|
|
1342
|
+
return {
|
|
1343
|
+
pagination: {
|
|
1344
|
+
total,
|
|
1345
|
+
page,
|
|
1346
|
+
perPage,
|
|
1347
|
+
hasMore: (page + 1) * perPage < total
|
|
1348
|
+
},
|
|
1349
|
+
spans
|
|
1350
|
+
};
|
|
1351
|
+
} catch (error) {
|
|
1352
|
+
throw new MastraError(
|
|
1353
|
+
{
|
|
1354
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1355
|
+
domain: ErrorDomain.STORAGE,
|
|
1356
|
+
category: ErrorCategory.USER
|
|
1357
|
+
},
|
|
1358
|
+
error
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
async batchCreateAISpans(args) {
|
|
1363
|
+
if (!args.records || args.records.length === 0) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
try {
|
|
1367
|
+
await this.operations.batchInsert({
|
|
1368
|
+
tableName: TABLE_AI_SPANS,
|
|
1369
|
+
records: args.records.map((span) => ({
|
|
1370
|
+
...span,
|
|
1371
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
1372
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
1373
|
+
}))
|
|
1374
|
+
});
|
|
1375
|
+
} catch (error) {
|
|
1376
|
+
throw new MastraError(
|
|
1377
|
+
{
|
|
1378
|
+
id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
1379
|
+
domain: ErrorDomain.STORAGE,
|
|
1380
|
+
category: ErrorCategory.USER,
|
|
1381
|
+
details: {
|
|
1382
|
+
count: args.records.length
|
|
1383
|
+
}
|
|
1384
|
+
},
|
|
1385
|
+
error
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
async batchUpdateAISpans(args) {
|
|
1390
|
+
if (!args.records || args.records.length === 0) {
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
try {
|
|
1394
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
1395
|
+
const processedData = { ...data };
|
|
1396
|
+
if (processedData.endedAt instanceof Date) {
|
|
1397
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
1398
|
+
}
|
|
1399
|
+
if (processedData.startedAt instanceof Date) {
|
|
1400
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
1401
|
+
}
|
|
1402
|
+
return {
|
|
1403
|
+
keys: { spanId, traceId },
|
|
1404
|
+
data: processedData
|
|
1405
|
+
};
|
|
1406
|
+
});
|
|
1407
|
+
await this.operations.batchUpdate({
|
|
1408
|
+
tableName: TABLE_AI_SPANS,
|
|
1409
|
+
updates
|
|
1410
|
+
});
|
|
1411
|
+
} catch (error) {
|
|
1412
|
+
throw new MastraError(
|
|
1413
|
+
{
|
|
1414
|
+
id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
1415
|
+
domain: ErrorDomain.STORAGE,
|
|
1416
|
+
category: ErrorCategory.USER,
|
|
1417
|
+
details: {
|
|
1418
|
+
count: args.records.length
|
|
1419
|
+
}
|
|
1420
|
+
},
|
|
1421
|
+
error
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
async batchDeleteAITraces(args) {
|
|
1426
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
try {
|
|
1430
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
1431
|
+
await this.operations.batchDelete({
|
|
1432
|
+
tableName: TABLE_AI_SPANS,
|
|
1433
|
+
keys
|
|
1434
|
+
});
|
|
1435
|
+
} catch (error) {
|
|
1436
|
+
throw new MastraError(
|
|
1437
|
+
{
|
|
1438
|
+
id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
1439
|
+
domain: ErrorDomain.STORAGE,
|
|
1440
|
+
category: ErrorCategory.USER,
|
|
1441
|
+
details: {
|
|
1442
|
+
count: args.traceIds.length
|
|
1443
|
+
}
|
|
1444
|
+
},
|
|
1445
|
+
error
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1062
1450
|
var StoreOperationsMSSQL = class extends StoreOperations {
|
|
1063
1451
|
pool;
|
|
1064
1452
|
schemaName;
|
|
1065
1453
|
setupSchemaPromise = null;
|
|
1066
1454
|
schemaSetupComplete = void 0;
|
|
1067
|
-
getSqlType(type, isPrimaryKey = false) {
|
|
1455
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
|
|
1068
1456
|
switch (type) {
|
|
1069
1457
|
case "text":
|
|
1070
|
-
|
|
1458
|
+
if (useLargeStorage) {
|
|
1459
|
+
return "NVARCHAR(MAX)";
|
|
1460
|
+
}
|
|
1461
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
1071
1462
|
case "timestamp":
|
|
1072
1463
|
return "DATETIME2(7)";
|
|
1073
1464
|
case "uuid":
|
|
@@ -1080,6 +1471,8 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1080
1471
|
return "BIGINT";
|
|
1081
1472
|
case "float":
|
|
1082
1473
|
return "FLOAT";
|
|
1474
|
+
case "boolean":
|
|
1475
|
+
return "BIT";
|
|
1083
1476
|
default:
|
|
1084
1477
|
throw new MastraError({
|
|
1085
1478
|
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
@@ -1142,20 +1535,26 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1142
1535
|
}
|
|
1143
1536
|
await this.setupSchemaPromise;
|
|
1144
1537
|
}
|
|
1145
|
-
async insert({
|
|
1538
|
+
async insert({
|
|
1539
|
+
tableName,
|
|
1540
|
+
record,
|
|
1541
|
+
transaction
|
|
1542
|
+
}) {
|
|
1146
1543
|
try {
|
|
1147
|
-
const columns = Object.keys(record)
|
|
1148
|
-
const
|
|
1149
|
-
const paramNames =
|
|
1150
|
-
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${
|
|
1151
|
-
const request = this.pool.request();
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
request.input(`param${i}`,
|
|
1544
|
+
const columns = Object.keys(record);
|
|
1545
|
+
const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
|
|
1546
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
1547
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1548
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1549
|
+
columns.forEach((col, i) => {
|
|
1550
|
+
const value = record[col];
|
|
1551
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
1552
|
+
if (preparedValue instanceof Date) {
|
|
1553
|
+
request.input(`param${i}`, sql3.DateTime2, preparedValue);
|
|
1554
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
1555
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
1157
1556
|
} else {
|
|
1158
|
-
request.input(`param${i}`,
|
|
1557
|
+
request.input(`param${i}`, preparedValue);
|
|
1159
1558
|
}
|
|
1160
1559
|
});
|
|
1161
1560
|
await request.query(insertSql);
|
|
@@ -1179,7 +1578,7 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1179
1578
|
try {
|
|
1180
1579
|
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
1181
1580
|
} catch (truncateError) {
|
|
1182
|
-
if (truncateError
|
|
1581
|
+
if (truncateError?.number === 4712) {
|
|
1183
1582
|
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
1184
1583
|
} else {
|
|
1185
1584
|
throw truncateError;
|
|
@@ -1202,9 +1601,11 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1202
1601
|
getDefaultValue(type) {
|
|
1203
1602
|
switch (type) {
|
|
1204
1603
|
case "timestamp":
|
|
1205
|
-
return "DEFAULT
|
|
1604
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
1206
1605
|
case "jsonb":
|
|
1207
1606
|
return "DEFAULT N'{}'";
|
|
1607
|
+
case "boolean":
|
|
1608
|
+
return "DEFAULT 0";
|
|
1208
1609
|
default:
|
|
1209
1610
|
return super.getDefaultValue(type);
|
|
1210
1611
|
}
|
|
@@ -1215,13 +1616,29 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1215
1616
|
}) {
|
|
1216
1617
|
try {
|
|
1217
1618
|
const uniqueConstraintColumns = tableName === TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
1619
|
+
const largeDataColumns = [
|
|
1620
|
+
"workingMemory",
|
|
1621
|
+
"snapshot",
|
|
1622
|
+
"metadata",
|
|
1623
|
+
"content",
|
|
1624
|
+
// messages.content - can be very long conversation content
|
|
1625
|
+
"input",
|
|
1626
|
+
// evals.input - test input data
|
|
1627
|
+
"output",
|
|
1628
|
+
// evals.output - test output data
|
|
1629
|
+
"instructions",
|
|
1630
|
+
// evals.instructions - evaluation instructions
|
|
1631
|
+
"other"
|
|
1632
|
+
// traces.other - additional trace data
|
|
1633
|
+
];
|
|
1218
1634
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1219
1635
|
const parsedName = parseSqlIdentifier(name, "column name");
|
|
1220
1636
|
const constraints = [];
|
|
1221
1637
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1222
1638
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1223
1639
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
1224
|
-
|
|
1640
|
+
const useLargeStorage = largeDataColumns.includes(name);
|
|
1641
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
|
|
1225
1642
|
}).join(",\n");
|
|
1226
1643
|
if (this.schemaName) {
|
|
1227
1644
|
await this.setupSchema();
|
|
@@ -1308,7 +1725,19 @@ ${columns}
|
|
|
1308
1725
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1309
1726
|
if (!columnExists) {
|
|
1310
1727
|
const columnDef = schema[columnName];
|
|
1311
|
-
const
|
|
1728
|
+
const largeDataColumns = [
|
|
1729
|
+
"workingMemory",
|
|
1730
|
+
"snapshot",
|
|
1731
|
+
"metadata",
|
|
1732
|
+
"content",
|
|
1733
|
+
"input",
|
|
1734
|
+
"output",
|
|
1735
|
+
"instructions",
|
|
1736
|
+
"other"
|
|
1737
|
+
];
|
|
1738
|
+
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
1739
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
1740
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
1312
1741
|
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1313
1742
|
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1314
1743
|
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
@@ -1336,13 +1765,17 @@ ${columns}
|
|
|
1336
1765
|
try {
|
|
1337
1766
|
const keyEntries = Object.entries(keys).map(([key, value]) => [parseSqlIdentifier(key, "column name"), value]);
|
|
1338
1767
|
const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
|
|
1339
|
-
const
|
|
1340
|
-
const sql7 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1768
|
+
const sql6 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1341
1769
|
const request = this.pool.request();
|
|
1342
|
-
|
|
1343
|
-
|
|
1770
|
+
keyEntries.forEach(([key, value], i) => {
|
|
1771
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1772
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1773
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
1774
|
+
} else {
|
|
1775
|
+
request.input(`param${i}`, preparedValue);
|
|
1776
|
+
}
|
|
1344
1777
|
});
|
|
1345
|
-
const resultSet = await request.query(
|
|
1778
|
+
const resultSet = await request.query(sql6);
|
|
1346
1779
|
const result = resultSet.recordset[0] || null;
|
|
1347
1780
|
if (!result) {
|
|
1348
1781
|
return null;
|
|
@@ -1374,7 +1807,7 @@ ${columns}
|
|
|
1374
1807
|
try {
|
|
1375
1808
|
await transaction.begin();
|
|
1376
1809
|
for (const record of records) {
|
|
1377
|
-
await this.insert({ tableName, record });
|
|
1810
|
+
await this.insert({ tableName, record, transaction });
|
|
1378
1811
|
}
|
|
1379
1812
|
await transaction.commit();
|
|
1380
1813
|
} catch (error) {
|
|
@@ -1411,52 +1844,593 @@ ${columns}
|
|
|
1411
1844
|
);
|
|
1412
1845
|
}
|
|
1413
1846
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1847
|
+
/**
|
|
1848
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
1849
|
+
*/
|
|
1850
|
+
prepareValue(value, columnName, tableName) {
|
|
1851
|
+
if (value === null || value === void 0) {
|
|
1852
|
+
return value;
|
|
1853
|
+
}
|
|
1854
|
+
if (value instanceof Date) {
|
|
1855
|
+
return value;
|
|
1856
|
+
}
|
|
1857
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
1858
|
+
const columnSchema = schema?.[columnName];
|
|
1859
|
+
if (columnSchema?.type === "boolean") {
|
|
1860
|
+
return value ? 1 : 0;
|
|
1861
|
+
}
|
|
1862
|
+
if (columnSchema?.type === "jsonb") {
|
|
1863
|
+
return JSON.stringify(value);
|
|
1864
|
+
}
|
|
1865
|
+
if (typeof value === "object") {
|
|
1866
|
+
return JSON.stringify(value);
|
|
1867
|
+
}
|
|
1868
|
+
return value;
|
|
1420
1869
|
}
|
|
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
|
-
}) {
|
|
1447
|
-
super();
|
|
1448
|
-
this.pool = pool;
|
|
1449
|
-
this.operations = operations;
|
|
1450
|
-
this.schema = schema;
|
|
1870
|
+
/**
|
|
1871
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
1872
|
+
*/
|
|
1873
|
+
getMssqlType(tableName, columnName) {
|
|
1874
|
+
const col = TABLE_SCHEMAS[tableName]?.[columnName];
|
|
1875
|
+
switch (col?.type) {
|
|
1876
|
+
case "text":
|
|
1877
|
+
return sql3.NVarChar;
|
|
1878
|
+
case "timestamp":
|
|
1879
|
+
return sql3.DateTime2;
|
|
1880
|
+
case "uuid":
|
|
1881
|
+
return sql3.UniqueIdentifier;
|
|
1882
|
+
case "jsonb":
|
|
1883
|
+
return sql3.NVarChar;
|
|
1884
|
+
case "integer":
|
|
1885
|
+
return sql3.Int;
|
|
1886
|
+
case "bigint":
|
|
1887
|
+
return sql3.BigInt;
|
|
1888
|
+
case "float":
|
|
1889
|
+
return sql3.Float;
|
|
1890
|
+
case "boolean":
|
|
1891
|
+
return sql3.Bit;
|
|
1892
|
+
default:
|
|
1893
|
+
return sql3.NVarChar;
|
|
1894
|
+
}
|
|
1451
1895
|
}
|
|
1452
|
-
|
|
1896
|
+
/**
|
|
1897
|
+
* Update a single record in the database
|
|
1898
|
+
*/
|
|
1899
|
+
async update({
|
|
1900
|
+
tableName,
|
|
1901
|
+
keys,
|
|
1902
|
+
data,
|
|
1903
|
+
transaction
|
|
1904
|
+
}) {
|
|
1453
1905
|
try {
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1906
|
+
if (!data || Object.keys(data).length === 0) {
|
|
1907
|
+
throw new MastraError({
|
|
1908
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
|
|
1909
|
+
domain: ErrorDomain.STORAGE,
|
|
1910
|
+
category: ErrorCategory.USER,
|
|
1911
|
+
text: "Cannot update with empty data payload"
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1915
|
+
throw new MastraError({
|
|
1916
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
|
|
1917
|
+
domain: ErrorDomain.STORAGE,
|
|
1918
|
+
category: ErrorCategory.USER,
|
|
1919
|
+
text: "Cannot update without keys to identify records"
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
const setClauses = [];
|
|
1923
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1924
|
+
let paramIndex = 0;
|
|
1925
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1926
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1927
|
+
const paramName = `set${paramIndex++}`;
|
|
1928
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
1929
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1930
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1931
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1932
|
+
} else {
|
|
1933
|
+
request.input(paramName, preparedValue);
|
|
1934
|
+
}
|
|
1935
|
+
});
|
|
1936
|
+
const whereConditions = [];
|
|
1937
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
1938
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1939
|
+
const paramName = `where${paramIndex++}`;
|
|
1940
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1941
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1942
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1943
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1944
|
+
} else {
|
|
1945
|
+
request.input(paramName, preparedValue);
|
|
1946
|
+
}
|
|
1947
|
+
});
|
|
1948
|
+
const tableName_ = getTableName({
|
|
1949
|
+
indexName: tableName,
|
|
1950
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1951
|
+
});
|
|
1952
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
1953
|
+
await request.query(updateSql);
|
|
1954
|
+
} catch (error) {
|
|
1955
|
+
throw new MastraError(
|
|
1956
|
+
{
|
|
1957
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
|
|
1958
|
+
domain: ErrorDomain.STORAGE,
|
|
1959
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1960
|
+
details: {
|
|
1961
|
+
tableName
|
|
1962
|
+
}
|
|
1963
|
+
},
|
|
1964
|
+
error
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
/**
|
|
1969
|
+
* Update multiple records in a single batch transaction
|
|
1970
|
+
*/
|
|
1971
|
+
async batchUpdate({
|
|
1972
|
+
tableName,
|
|
1973
|
+
updates
|
|
1974
|
+
}) {
|
|
1975
|
+
const transaction = this.pool.transaction();
|
|
1976
|
+
try {
|
|
1977
|
+
await transaction.begin();
|
|
1978
|
+
for (const { keys, data } of updates) {
|
|
1979
|
+
await this.update({ tableName, keys, data, transaction });
|
|
1980
|
+
}
|
|
1981
|
+
await transaction.commit();
|
|
1982
|
+
} catch (error) {
|
|
1983
|
+
await transaction.rollback();
|
|
1984
|
+
throw new MastraError(
|
|
1985
|
+
{
|
|
1986
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
|
|
1987
|
+
domain: ErrorDomain.STORAGE,
|
|
1988
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1989
|
+
details: {
|
|
1990
|
+
tableName,
|
|
1991
|
+
numberOfRecords: updates.length
|
|
1992
|
+
}
|
|
1993
|
+
},
|
|
1994
|
+
error
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Delete multiple records by keys
|
|
2000
|
+
*/
|
|
2001
|
+
async batchDelete({ tableName, keys }) {
|
|
2002
|
+
if (keys.length === 0) {
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
const tableName_ = getTableName({
|
|
2006
|
+
indexName: tableName,
|
|
2007
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2008
|
+
});
|
|
2009
|
+
const transaction = this.pool.transaction();
|
|
2010
|
+
try {
|
|
2011
|
+
await transaction.begin();
|
|
2012
|
+
for (const keySet of keys) {
|
|
2013
|
+
const conditions = [];
|
|
2014
|
+
const request = transaction.request();
|
|
2015
|
+
let paramIndex = 0;
|
|
2016
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
2017
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
2018
|
+
const paramName = `p${paramIndex++}`;
|
|
2019
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
2020
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
2021
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
2022
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
2023
|
+
} else {
|
|
2024
|
+
request.input(paramName, preparedValue);
|
|
2025
|
+
}
|
|
2026
|
+
});
|
|
2027
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
2028
|
+
await request.query(deleteSql);
|
|
2029
|
+
}
|
|
2030
|
+
await transaction.commit();
|
|
2031
|
+
} catch (error) {
|
|
2032
|
+
await transaction.rollback();
|
|
2033
|
+
throw new MastraError(
|
|
2034
|
+
{
|
|
2035
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
|
|
2036
|
+
domain: ErrorDomain.STORAGE,
|
|
2037
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2038
|
+
details: {
|
|
2039
|
+
tableName,
|
|
2040
|
+
numberOfRecords: keys.length
|
|
2041
|
+
}
|
|
2042
|
+
},
|
|
2043
|
+
error
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* Create a new index on a table
|
|
2049
|
+
*/
|
|
2050
|
+
async createIndex(options) {
|
|
2051
|
+
try {
|
|
2052
|
+
const { name, table, columns, unique = false, where } = options;
|
|
2053
|
+
const schemaName = this.schemaName || "dbo";
|
|
2054
|
+
const fullTableName = getTableName({
|
|
2055
|
+
indexName: table,
|
|
2056
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2057
|
+
});
|
|
2058
|
+
const indexNameSafe = parseSqlIdentifier(name, "index name");
|
|
2059
|
+
const checkRequest = this.pool.request();
|
|
2060
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2061
|
+
checkRequest.input("schemaName", schemaName);
|
|
2062
|
+
checkRequest.input("tableName", table);
|
|
2063
|
+
const indexExists = await checkRequest.query(`
|
|
2064
|
+
SELECT 1 as found
|
|
2065
|
+
FROM sys.indexes i
|
|
2066
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2067
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2068
|
+
WHERE i.name = @indexName
|
|
2069
|
+
AND s.name = @schemaName
|
|
2070
|
+
AND t.name = @tableName
|
|
2071
|
+
`);
|
|
2072
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
2076
|
+
const columnsStr = columns.map((col) => {
|
|
2077
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
2078
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
2079
|
+
if (!colName) {
|
|
2080
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
2081
|
+
}
|
|
2082
|
+
return `[${parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
2083
|
+
}
|
|
2084
|
+
return `[${parseSqlIdentifier(col, "column name")}]`;
|
|
2085
|
+
}).join(", ");
|
|
2086
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
2087
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
2088
|
+
await this.pool.request().query(createIndexSql);
|
|
2089
|
+
} catch (error) {
|
|
2090
|
+
throw new MastraError(
|
|
2091
|
+
{
|
|
2092
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
|
|
2093
|
+
domain: ErrorDomain.STORAGE,
|
|
2094
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2095
|
+
details: {
|
|
2096
|
+
indexName: options.name,
|
|
2097
|
+
tableName: options.table
|
|
2098
|
+
}
|
|
2099
|
+
},
|
|
2100
|
+
error
|
|
2101
|
+
);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Drop an existing index
|
|
2106
|
+
*/
|
|
2107
|
+
async dropIndex(indexName) {
|
|
2108
|
+
try {
|
|
2109
|
+
const schemaName = this.schemaName || "dbo";
|
|
2110
|
+
const indexNameSafe = parseSqlIdentifier(indexName, "index name");
|
|
2111
|
+
const checkRequest = this.pool.request();
|
|
2112
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2113
|
+
checkRequest.input("schemaName", schemaName);
|
|
2114
|
+
const result = await checkRequest.query(`
|
|
2115
|
+
SELECT t.name as table_name
|
|
2116
|
+
FROM sys.indexes i
|
|
2117
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2118
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2119
|
+
WHERE i.name = @indexName
|
|
2120
|
+
AND s.name = @schemaName
|
|
2121
|
+
`);
|
|
2122
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
if (result.recordset.length > 1) {
|
|
2126
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
2127
|
+
throw new MastraError({
|
|
2128
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
|
|
2129
|
+
domain: ErrorDomain.STORAGE,
|
|
2130
|
+
category: ErrorCategory.USER,
|
|
2131
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
2134
|
+
const tableName = result.recordset[0].table_name;
|
|
2135
|
+
const fullTableName = getTableName({
|
|
2136
|
+
indexName: tableName,
|
|
2137
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2138
|
+
});
|
|
2139
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
2140
|
+
await this.pool.request().query(dropSql);
|
|
2141
|
+
} catch (error) {
|
|
2142
|
+
throw new MastraError(
|
|
2143
|
+
{
|
|
2144
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
|
|
2145
|
+
domain: ErrorDomain.STORAGE,
|
|
2146
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2147
|
+
details: {
|
|
2148
|
+
indexName
|
|
2149
|
+
}
|
|
2150
|
+
},
|
|
2151
|
+
error
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
/**
|
|
2156
|
+
* List indexes for a specific table or all tables
|
|
2157
|
+
*/
|
|
2158
|
+
async listIndexes(tableName) {
|
|
2159
|
+
try {
|
|
2160
|
+
const schemaName = this.schemaName || "dbo";
|
|
2161
|
+
let query;
|
|
2162
|
+
const request = this.pool.request();
|
|
2163
|
+
request.input("schemaName", schemaName);
|
|
2164
|
+
if (tableName) {
|
|
2165
|
+
query = `
|
|
2166
|
+
SELECT
|
|
2167
|
+
i.name as name,
|
|
2168
|
+
o.name as [table],
|
|
2169
|
+
i.is_unique as is_unique,
|
|
2170
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2171
|
+
FROM sys.indexes i
|
|
2172
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2173
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2174
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2175
|
+
WHERE sch.name = @schemaName
|
|
2176
|
+
AND o.name = @tableName
|
|
2177
|
+
AND i.name IS NOT NULL
|
|
2178
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2179
|
+
`;
|
|
2180
|
+
request.input("tableName", tableName);
|
|
2181
|
+
} else {
|
|
2182
|
+
query = `
|
|
2183
|
+
SELECT
|
|
2184
|
+
i.name as name,
|
|
2185
|
+
o.name as [table],
|
|
2186
|
+
i.is_unique as is_unique,
|
|
2187
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2188
|
+
FROM sys.indexes i
|
|
2189
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2190
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2191
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2192
|
+
WHERE sch.name = @schemaName
|
|
2193
|
+
AND i.name IS NOT NULL
|
|
2194
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2195
|
+
`;
|
|
2196
|
+
}
|
|
2197
|
+
const result = await request.query(query);
|
|
2198
|
+
const indexes = [];
|
|
2199
|
+
for (const row of result.recordset) {
|
|
2200
|
+
const colRequest = this.pool.request();
|
|
2201
|
+
colRequest.input("indexName", row.name);
|
|
2202
|
+
colRequest.input("schemaName", schemaName);
|
|
2203
|
+
const colResult = await colRequest.query(`
|
|
2204
|
+
SELECT c.name as column_name
|
|
2205
|
+
FROM sys.indexes i
|
|
2206
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2207
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2208
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2209
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2210
|
+
WHERE i.name = @indexName
|
|
2211
|
+
AND s.name = @schemaName
|
|
2212
|
+
ORDER BY ic.key_ordinal
|
|
2213
|
+
`);
|
|
2214
|
+
indexes.push({
|
|
2215
|
+
name: row.name,
|
|
2216
|
+
table: row.table,
|
|
2217
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2218
|
+
unique: row.is_unique || false,
|
|
2219
|
+
size: row.size || "0 MB",
|
|
2220
|
+
definition: ""
|
|
2221
|
+
// MSSQL doesn't store definition like PG
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
return indexes;
|
|
2225
|
+
} catch (error) {
|
|
2226
|
+
throw new MastraError(
|
|
2227
|
+
{
|
|
2228
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
|
|
2229
|
+
domain: ErrorDomain.STORAGE,
|
|
2230
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2231
|
+
details: tableName ? {
|
|
2232
|
+
tableName
|
|
2233
|
+
} : {}
|
|
2234
|
+
},
|
|
2235
|
+
error
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
/**
|
|
2240
|
+
* Get detailed statistics for a specific index
|
|
2241
|
+
*/
|
|
2242
|
+
async describeIndex(indexName) {
|
|
2243
|
+
try {
|
|
2244
|
+
const schemaName = this.schemaName || "dbo";
|
|
2245
|
+
const request = this.pool.request();
|
|
2246
|
+
request.input("indexName", indexName);
|
|
2247
|
+
request.input("schemaName", schemaName);
|
|
2248
|
+
const query = `
|
|
2249
|
+
SELECT
|
|
2250
|
+
i.name as name,
|
|
2251
|
+
o.name as [table],
|
|
2252
|
+
i.is_unique as is_unique,
|
|
2253
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
2254
|
+
i.type_desc as method,
|
|
2255
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
2256
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
2257
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
2258
|
+
FROM sys.indexes i
|
|
2259
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2260
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2261
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2262
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
2263
|
+
WHERE i.name = @indexName
|
|
2264
|
+
AND sch.name = @schemaName
|
|
2265
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
2266
|
+
`;
|
|
2267
|
+
const result = await request.query(query);
|
|
2268
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2269
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
2270
|
+
}
|
|
2271
|
+
const row = result.recordset[0];
|
|
2272
|
+
const colRequest = this.pool.request();
|
|
2273
|
+
colRequest.input("indexName", indexName);
|
|
2274
|
+
colRequest.input("schemaName", schemaName);
|
|
2275
|
+
const colResult = await colRequest.query(`
|
|
2276
|
+
SELECT c.name as column_name
|
|
2277
|
+
FROM sys.indexes i
|
|
2278
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2279
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2280
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2281
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2282
|
+
WHERE i.name = @indexName
|
|
2283
|
+
AND s.name = @schemaName
|
|
2284
|
+
ORDER BY ic.key_ordinal
|
|
2285
|
+
`);
|
|
2286
|
+
return {
|
|
2287
|
+
name: row.name,
|
|
2288
|
+
table: row.table,
|
|
2289
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2290
|
+
unique: row.is_unique || false,
|
|
2291
|
+
size: row.size || "0 MB",
|
|
2292
|
+
definition: "",
|
|
2293
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
2294
|
+
scans: Number(row.scans) || 0,
|
|
2295
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
2296
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
2297
|
+
};
|
|
2298
|
+
} catch (error) {
|
|
2299
|
+
throw new MastraError(
|
|
2300
|
+
{
|
|
2301
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
|
|
2302
|
+
domain: ErrorDomain.STORAGE,
|
|
2303
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2304
|
+
details: {
|
|
2305
|
+
indexName
|
|
2306
|
+
}
|
|
2307
|
+
},
|
|
2308
|
+
error
|
|
2309
|
+
);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
/**
|
|
2313
|
+
* Returns definitions for automatic performance indexes
|
|
2314
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2315
|
+
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
2316
|
+
*/
|
|
2317
|
+
getAutomaticIndexDefinitions() {
|
|
2318
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2319
|
+
return [
|
|
2320
|
+
// Composite indexes for optimal filtering + sorting performance
|
|
2321
|
+
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
2322
|
+
{
|
|
2323
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
2324
|
+
table: TABLE_THREADS,
|
|
2325
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
2326
|
+
},
|
|
2327
|
+
{
|
|
2328
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
2329
|
+
table: TABLE_MESSAGES,
|
|
2330
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
2331
|
+
},
|
|
2332
|
+
{
|
|
2333
|
+
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
2334
|
+
table: TABLE_TRACES,
|
|
2335
|
+
columns: ["name", "seq_id DESC"]
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
name: `${schemaPrefix}mastra_evals_agent_name_seqid_idx`,
|
|
2339
|
+
table: TABLE_EVALS,
|
|
2340
|
+
columns: ["agent_name", "seq_id DESC"]
|
|
2341
|
+
},
|
|
2342
|
+
{
|
|
2343
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2344
|
+
table: TABLE_SCORERS,
|
|
2345
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2346
|
+
},
|
|
2347
|
+
// AI Spans indexes for optimal trace querying
|
|
2348
|
+
{
|
|
2349
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2350
|
+
table: TABLE_AI_SPANS,
|
|
2351
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2352
|
+
},
|
|
2353
|
+
{
|
|
2354
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2355
|
+
table: TABLE_AI_SPANS,
|
|
2356
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2357
|
+
},
|
|
2358
|
+
{
|
|
2359
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2360
|
+
table: TABLE_AI_SPANS,
|
|
2361
|
+
columns: ["name"]
|
|
2362
|
+
},
|
|
2363
|
+
{
|
|
2364
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2365
|
+
table: TABLE_AI_SPANS,
|
|
2366
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2367
|
+
}
|
|
2368
|
+
];
|
|
2369
|
+
}
|
|
2370
|
+
/**
|
|
2371
|
+
* Creates automatic indexes for optimal query performance
|
|
2372
|
+
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
2373
|
+
*/
|
|
2374
|
+
async createAutomaticIndexes() {
|
|
2375
|
+
try {
|
|
2376
|
+
const indexes = this.getAutomaticIndexDefinitions();
|
|
2377
|
+
for (const indexOptions of indexes) {
|
|
2378
|
+
try {
|
|
2379
|
+
await this.createIndex(indexOptions);
|
|
2380
|
+
} catch (error) {
|
|
2381
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
} catch (error) {
|
|
2385
|
+
throw new MastraError(
|
|
2386
|
+
{
|
|
2387
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
2388
|
+
domain: ErrorDomain.STORAGE,
|
|
2389
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2390
|
+
},
|
|
2391
|
+
error
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
2396
|
+
function transformScoreRow(row) {
|
|
2397
|
+
return {
|
|
2398
|
+
...row,
|
|
2399
|
+
input: safelyParseJSON(row.input),
|
|
2400
|
+
scorer: safelyParseJSON(row.scorer),
|
|
2401
|
+
preprocessStepResult: safelyParseJSON(row.preprocessStepResult),
|
|
2402
|
+
analyzeStepResult: safelyParseJSON(row.analyzeStepResult),
|
|
2403
|
+
metadata: safelyParseJSON(row.metadata),
|
|
2404
|
+
output: safelyParseJSON(row.output),
|
|
2405
|
+
additionalContext: safelyParseJSON(row.additionalContext),
|
|
2406
|
+
runtimeContext: safelyParseJSON(row.runtimeContext),
|
|
2407
|
+
entity: safelyParseJSON(row.entity),
|
|
2408
|
+
createdAt: row.createdAt,
|
|
2409
|
+
updatedAt: row.updatedAt
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
var ScoresMSSQL = class extends ScoresStorage {
|
|
2413
|
+
pool;
|
|
2414
|
+
operations;
|
|
2415
|
+
schema;
|
|
2416
|
+
constructor({
|
|
2417
|
+
pool,
|
|
2418
|
+
operations,
|
|
2419
|
+
schema
|
|
2420
|
+
}) {
|
|
2421
|
+
super();
|
|
2422
|
+
this.pool = pool;
|
|
2423
|
+
this.operations = operations;
|
|
2424
|
+
this.schema = schema;
|
|
2425
|
+
}
|
|
2426
|
+
async getScoreById({ id }) {
|
|
2427
|
+
try {
|
|
2428
|
+
const request = this.pool.request();
|
|
2429
|
+
request.input("p1", id);
|
|
2430
|
+
const result = await request.query(
|
|
2431
|
+
`SELECT * FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE id = @p1`
|
|
2432
|
+
);
|
|
2433
|
+
if (result.recordset.length === 0) {
|
|
1460
2434
|
return null;
|
|
1461
2435
|
}
|
|
1462
2436
|
return transformScoreRow(result.recordset[0]);
|
|
@@ -1473,8 +2447,21 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1473
2447
|
}
|
|
1474
2448
|
}
|
|
1475
2449
|
async saveScore(score) {
|
|
2450
|
+
let validatedScore;
|
|
1476
2451
|
try {
|
|
1477
|
-
|
|
2452
|
+
validatedScore = saveScorePayloadSchema.parse(score);
|
|
2453
|
+
} catch (error) {
|
|
2454
|
+
throw new MastraError(
|
|
2455
|
+
{
|
|
2456
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_VALIDATION_FAILED",
|
|
2457
|
+
domain: ErrorDomain.STORAGE,
|
|
2458
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2459
|
+
},
|
|
2460
|
+
error
|
|
2461
|
+
);
|
|
2462
|
+
}
|
|
2463
|
+
try {
|
|
2464
|
+
const scoreId = randomUUID();
|
|
1478
2465
|
const {
|
|
1479
2466
|
scorer,
|
|
1480
2467
|
preprocessStepResult,
|
|
@@ -1486,21 +2473,21 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1486
2473
|
runtimeContext,
|
|
1487
2474
|
entity,
|
|
1488
2475
|
...rest
|
|
1489
|
-
} =
|
|
2476
|
+
} = validatedScore;
|
|
1490
2477
|
await this.operations.insert({
|
|
1491
2478
|
tableName: TABLE_SCORERS,
|
|
1492
2479
|
record: {
|
|
1493
2480
|
id: scoreId,
|
|
1494
2481
|
...rest,
|
|
1495
|
-
input:
|
|
1496
|
-
output:
|
|
1497
|
-
preprocessStepResult: preprocessStepResult
|
|
1498
|
-
analyzeStepResult: analyzeStepResult
|
|
1499
|
-
metadata: metadata
|
|
1500
|
-
additionalContext: additionalContext
|
|
1501
|
-
runtimeContext: runtimeContext
|
|
1502
|
-
entity: entity
|
|
1503
|
-
scorer: scorer
|
|
2482
|
+
input: input || "",
|
|
2483
|
+
output: output || "",
|
|
2484
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2485
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2486
|
+
metadata: metadata || null,
|
|
2487
|
+
additionalContext: additionalContext || null,
|
|
2488
|
+
runtimeContext: runtimeContext || null,
|
|
2489
|
+
entity: entity || null,
|
|
2490
|
+
scorer: scorer || null,
|
|
1504
2491
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1505
2492
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1506
2493
|
}
|
|
@@ -1520,14 +2507,37 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1520
2507
|
}
|
|
1521
2508
|
async getScoresByScorerId({
|
|
1522
2509
|
scorerId,
|
|
1523
|
-
pagination
|
|
2510
|
+
pagination,
|
|
2511
|
+
entityId,
|
|
2512
|
+
entityType,
|
|
2513
|
+
source
|
|
1524
2514
|
}) {
|
|
1525
2515
|
try {
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
2516
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2517
|
+
const params = { p1: scorerId };
|
|
2518
|
+
let paramIndex = 2;
|
|
2519
|
+
if (entityId) {
|
|
2520
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2521
|
+
params[`p${paramIndex}`] = entityId;
|
|
2522
|
+
paramIndex++;
|
|
2523
|
+
}
|
|
2524
|
+
if (entityType) {
|
|
2525
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2526
|
+
params[`p${paramIndex}`] = entityType;
|
|
2527
|
+
paramIndex++;
|
|
2528
|
+
}
|
|
2529
|
+
if (source) {
|
|
2530
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2531
|
+
params[`p${paramIndex}`] = source;
|
|
2532
|
+
paramIndex++;
|
|
2533
|
+
}
|
|
2534
|
+
const whereClause = conditions.join(" AND ");
|
|
2535
|
+
const tableName = getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
|
|
2536
|
+
const countRequest = this.pool.request();
|
|
2537
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2538
|
+
countRequest.input(key, value);
|
|
2539
|
+
});
|
|
2540
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1531
2541
|
const total = totalResult.recordset[0]?.count || 0;
|
|
1532
2542
|
if (total === 0) {
|
|
1533
2543
|
return {
|
|
@@ -1541,12 +2551,13 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1541
2551
|
};
|
|
1542
2552
|
}
|
|
1543
2553
|
const dataRequest = this.pool.request();
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
2554
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2555
|
+
dataRequest.input(key, value);
|
|
2556
|
+
});
|
|
2557
|
+
dataRequest.input("perPage", pagination.perPage);
|
|
2558
|
+
dataRequest.input("offset", pagination.page * pagination.perPage);
|
|
2559
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2560
|
+
const result = await dataRequest.query(dataQuery);
|
|
1550
2561
|
return {
|
|
1551
2562
|
pagination: {
|
|
1552
2563
|
total: Number(total),
|
|
@@ -1671,8 +2682,62 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1671
2682
|
);
|
|
1672
2683
|
}
|
|
1673
2684
|
}
|
|
2685
|
+
async getScoresBySpan({
|
|
2686
|
+
traceId,
|
|
2687
|
+
spanId,
|
|
2688
|
+
pagination
|
|
2689
|
+
}) {
|
|
2690
|
+
try {
|
|
2691
|
+
const request = this.pool.request();
|
|
2692
|
+
request.input("p1", traceId);
|
|
2693
|
+
request.input("p2", spanId);
|
|
2694
|
+
const totalResult = await request.query(
|
|
2695
|
+
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
|
|
2696
|
+
);
|
|
2697
|
+
const total = totalResult.recordset[0]?.count || 0;
|
|
2698
|
+
if (total === 0) {
|
|
2699
|
+
return {
|
|
2700
|
+
pagination: {
|
|
2701
|
+
total: 0,
|
|
2702
|
+
page: pagination.page,
|
|
2703
|
+
perPage: pagination.perPage,
|
|
2704
|
+
hasMore: false
|
|
2705
|
+
},
|
|
2706
|
+
scores: []
|
|
2707
|
+
};
|
|
2708
|
+
}
|
|
2709
|
+
const limit = pagination.perPage + 1;
|
|
2710
|
+
const dataRequest = this.pool.request();
|
|
2711
|
+
dataRequest.input("p1", traceId);
|
|
2712
|
+
dataRequest.input("p2", spanId);
|
|
2713
|
+
dataRequest.input("p3", limit);
|
|
2714
|
+
dataRequest.input("p4", pagination.page * pagination.perPage);
|
|
2715
|
+
const result = await dataRequest.query(
|
|
2716
|
+
`SELECT * FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2 ORDER BY [createdAt] DESC OFFSET @p4 ROWS FETCH NEXT @p3 ROWS ONLY`
|
|
2717
|
+
);
|
|
2718
|
+
return {
|
|
2719
|
+
pagination: {
|
|
2720
|
+
total: Number(total),
|
|
2721
|
+
page: pagination.page,
|
|
2722
|
+
perPage: pagination.perPage,
|
|
2723
|
+
hasMore: result.recordset.length > pagination.perPage
|
|
2724
|
+
},
|
|
2725
|
+
scores: result.recordset.slice(0, pagination.perPage).map((row) => transformScoreRow(row))
|
|
2726
|
+
};
|
|
2727
|
+
} catch (error) {
|
|
2728
|
+
throw new MastraError(
|
|
2729
|
+
{
|
|
2730
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
2731
|
+
domain: ErrorDomain.STORAGE,
|
|
2732
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2733
|
+
details: { traceId, spanId }
|
|
2734
|
+
},
|
|
2735
|
+
error
|
|
2736
|
+
);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
1674
2739
|
};
|
|
1675
|
-
var
|
|
2740
|
+
var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
1676
2741
|
pool;
|
|
1677
2742
|
operations;
|
|
1678
2743
|
schema;
|
|
@@ -1686,210 +2751,168 @@ var TracesMSSQL = class extends TracesStorage {
|
|
|
1686
2751
|
this.operations = operations;
|
|
1687
2752
|
this.schema = schema;
|
|
1688
2753
|
}
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
if (
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
2754
|
+
parseWorkflowRun(row) {
|
|
2755
|
+
let parsedSnapshot = row.snapshot;
|
|
2756
|
+
if (typeof parsedSnapshot === "string") {
|
|
2757
|
+
try {
|
|
2758
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2759
|
+
} catch (e) {
|
|
2760
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
2761
|
+
}
|
|
1696
2762
|
}
|
|
1697
|
-
|
|
1698
|
-
|
|
2763
|
+
return {
|
|
2764
|
+
workflowName: row.workflow_name,
|
|
2765
|
+
runId: row.run_id,
|
|
2766
|
+
snapshot: parsedSnapshot,
|
|
2767
|
+
createdAt: row.createdAt,
|
|
2768
|
+
updatedAt: row.updatedAt,
|
|
2769
|
+
resourceId: row.resourceId
|
|
2770
|
+
};
|
|
1699
2771
|
}
|
|
1700
|
-
async
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
const
|
|
1708
|
-
|
|
1709
|
-
if (name) {
|
|
1710
|
-
const paramName = `p${paramIndex++}`;
|
|
1711
|
-
conditions.push(`[name] LIKE @${paramName}`);
|
|
1712
|
-
paramMap[paramName] = `${name}%`;
|
|
1713
|
-
}
|
|
1714
|
-
if (scope) {
|
|
1715
|
-
const paramName = `p${paramIndex++}`;
|
|
1716
|
-
conditions.push(`[scope] = @${paramName}`);
|
|
1717
|
-
paramMap[paramName] = scope;
|
|
1718
|
-
}
|
|
1719
|
-
if (attributes) {
|
|
1720
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
1721
|
-
const parsedKey = parseFieldKey(key);
|
|
1722
|
-
const paramName = `p${paramIndex++}`;
|
|
1723
|
-
conditions.push(`JSON_VALUE([attributes], '$.${parsedKey}') = @${paramName}`);
|
|
1724
|
-
paramMap[paramName] = value;
|
|
1725
|
-
});
|
|
1726
|
-
}
|
|
1727
|
-
if (filters) {
|
|
1728
|
-
Object.entries(filters).forEach(([key, value]) => {
|
|
1729
|
-
const parsedKey = parseFieldKey(key);
|
|
1730
|
-
const paramName = `p${paramIndex++}`;
|
|
1731
|
-
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1732
|
-
paramMap[paramName] = value;
|
|
1733
|
-
});
|
|
1734
|
-
}
|
|
1735
|
-
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
1736
|
-
const paramName = `p${paramIndex++}`;
|
|
1737
|
-
conditions.push(`[createdAt] >= @${paramName}`);
|
|
1738
|
-
paramMap[paramName] = fromDate.toISOString();
|
|
1739
|
-
}
|
|
1740
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
1741
|
-
const paramName = `p${paramIndex++}`;
|
|
1742
|
-
conditions.push(`[createdAt] <= @${paramName}`);
|
|
1743
|
-
paramMap[paramName] = toDate.toISOString();
|
|
1744
|
-
}
|
|
1745
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1746
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${getTableName({ indexName: TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause}`;
|
|
1747
|
-
let total = 0;
|
|
2772
|
+
async updateWorkflowResults({
|
|
2773
|
+
workflowName,
|
|
2774
|
+
runId,
|
|
2775
|
+
stepId,
|
|
2776
|
+
result,
|
|
2777
|
+
runtimeContext
|
|
2778
|
+
}) {
|
|
2779
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2780
|
+
const transaction = this.pool.transaction();
|
|
1748
2781
|
try {
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
2782
|
+
await transaction.begin();
|
|
2783
|
+
const selectRequest = new sql3.Request(transaction);
|
|
2784
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2785
|
+
selectRequest.input("run_id", runId);
|
|
2786
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2787
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2788
|
+
);
|
|
2789
|
+
let snapshot;
|
|
2790
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2791
|
+
snapshot = {
|
|
2792
|
+
context: {},
|
|
2793
|
+
activePaths: [],
|
|
2794
|
+
timestamp: Date.now(),
|
|
2795
|
+
suspendedPaths: {},
|
|
2796
|
+
resumeLabels: {},
|
|
2797
|
+
serializedStepGraph: [],
|
|
2798
|
+
value: {},
|
|
2799
|
+
waitingPaths: {},
|
|
2800
|
+
status: "pending",
|
|
2801
|
+
runId,
|
|
2802
|
+
runtimeContext: {}
|
|
2803
|
+
};
|
|
2804
|
+
} else {
|
|
2805
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2806
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2807
|
+
}
|
|
2808
|
+
snapshot.context[stepId] = result;
|
|
2809
|
+
snapshot.runtimeContext = { ...snapshot.runtimeContext, ...runtimeContext };
|
|
2810
|
+
const upsertReq = new sql3.Request(transaction);
|
|
2811
|
+
upsertReq.input("workflow_name", workflowName);
|
|
2812
|
+
upsertReq.input("run_id", runId);
|
|
2813
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
2814
|
+
upsertReq.input("createdAt", sql3.DateTime2, /* @__PURE__ */ new Date());
|
|
2815
|
+
upsertReq.input("updatedAt", sql3.DateTime2, /* @__PURE__ */ new Date());
|
|
2816
|
+
await upsertReq.query(
|
|
2817
|
+
`MERGE ${table} AS target
|
|
2818
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
2819
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
2820
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
2821
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
2822
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
2823
|
+
);
|
|
2824
|
+
await transaction.commit();
|
|
2825
|
+
return snapshot.context;
|
|
1759
2826
|
} catch (error) {
|
|
2827
|
+
try {
|
|
2828
|
+
await transaction.rollback();
|
|
2829
|
+
} catch {
|
|
2830
|
+
}
|
|
1760
2831
|
throw new MastraError(
|
|
1761
2832
|
{
|
|
1762
|
-
id: "
|
|
2833
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
|
|
1763
2834
|
domain: ErrorDomain.STORAGE,
|
|
1764
2835
|
category: ErrorCategory.THIRD_PARTY,
|
|
1765
2836
|
details: {
|
|
1766
|
-
|
|
1767
|
-
|
|
2837
|
+
workflowName,
|
|
2838
|
+
runId,
|
|
2839
|
+
stepId
|
|
1768
2840
|
}
|
|
1769
2841
|
},
|
|
1770
2842
|
error
|
|
1771
2843
|
);
|
|
1772
2844
|
}
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
}
|
|
1782
|
-
const dataQuery = `SELECT * FROM ${getTableName({ indexName: TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause} ORDER BY [seq_id] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
1783
|
-
const dataRequest = this.pool.request();
|
|
1784
|
-
Object.entries(paramMap).forEach(([key, value]) => {
|
|
1785
|
-
if (value instanceof Date) {
|
|
1786
|
-
dataRequest.input(key, sql2.DateTime, value);
|
|
1787
|
-
} else {
|
|
1788
|
-
dataRequest.input(key, value);
|
|
1789
|
-
}
|
|
1790
|
-
});
|
|
1791
|
-
dataRequest.input("offset", currentOffset);
|
|
1792
|
-
dataRequest.input("limit", perPage);
|
|
2845
|
+
}
|
|
2846
|
+
async updateWorkflowState({
|
|
2847
|
+
workflowName,
|
|
2848
|
+
runId,
|
|
2849
|
+
opts
|
|
2850
|
+
}) {
|
|
2851
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2852
|
+
const transaction = this.pool.transaction();
|
|
1793
2853
|
try {
|
|
1794
|
-
|
|
1795
|
-
const
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2854
|
+
await transaction.begin();
|
|
2855
|
+
const selectRequest = new sql3.Request(transaction);
|
|
2856
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2857
|
+
selectRequest.input("run_id", runId);
|
|
2858
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2859
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2860
|
+
);
|
|
2861
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2862
|
+
await transaction.rollback();
|
|
2863
|
+
return void 0;
|
|
2864
|
+
}
|
|
2865
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2866
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2867
|
+
if (!snapshot || !snapshot?.context) {
|
|
2868
|
+
await transaction.rollback();
|
|
2869
|
+
throw new MastraError(
|
|
2870
|
+
{
|
|
2871
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
|
|
2872
|
+
domain: ErrorDomain.STORAGE,
|
|
2873
|
+
category: ErrorCategory.SYSTEM,
|
|
2874
|
+
details: {
|
|
2875
|
+
workflowName,
|
|
2876
|
+
runId
|
|
2877
|
+
}
|
|
2878
|
+
},
|
|
2879
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
2880
|
+
);
|
|
2881
|
+
}
|
|
2882
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
2883
|
+
const updateRequest = new sql3.Request(transaction);
|
|
2884
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
2885
|
+
updateRequest.input("workflow_name", workflowName);
|
|
2886
|
+
updateRequest.input("run_id", runId);
|
|
2887
|
+
updateRequest.input("updatedAt", sql3.DateTime2, /* @__PURE__ */ new Date());
|
|
2888
|
+
await updateRequest.query(
|
|
2889
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2890
|
+
);
|
|
2891
|
+
await transaction.commit();
|
|
2892
|
+
return updatedSnapshot;
|
|
1819
2893
|
} catch (error) {
|
|
2894
|
+
try {
|
|
2895
|
+
await transaction.rollback();
|
|
2896
|
+
} catch {
|
|
2897
|
+
}
|
|
1820
2898
|
throw new MastraError(
|
|
1821
2899
|
{
|
|
1822
|
-
id: "
|
|
2900
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
|
|
1823
2901
|
domain: ErrorDomain.STORAGE,
|
|
1824
2902
|
category: ErrorCategory.THIRD_PARTY,
|
|
1825
2903
|
details: {
|
|
1826
|
-
|
|
1827
|
-
|
|
2904
|
+
workflowName,
|
|
2905
|
+
runId
|
|
1828
2906
|
}
|
|
1829
2907
|
},
|
|
1830
2908
|
error
|
|
1831
2909
|
);
|
|
1832
2910
|
}
|
|
1833
2911
|
}
|
|
1834
|
-
async batchTraceInsert({ records }) {
|
|
1835
|
-
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1836
|
-
await this.operations.batchInsert({
|
|
1837
|
-
tableName: TABLE_TRACES,
|
|
1838
|
-
records
|
|
1839
|
-
});
|
|
1840
|
-
}
|
|
1841
|
-
};
|
|
1842
|
-
function parseWorkflowRun(row) {
|
|
1843
|
-
let parsedSnapshot = row.snapshot;
|
|
1844
|
-
if (typeof parsedSnapshot === "string") {
|
|
1845
|
-
try {
|
|
1846
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1847
|
-
} catch (e) {
|
|
1848
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
return {
|
|
1852
|
-
workflowName: row.workflow_name,
|
|
1853
|
-
runId: row.run_id,
|
|
1854
|
-
snapshot: parsedSnapshot,
|
|
1855
|
-
createdAt: row.createdAt,
|
|
1856
|
-
updatedAt: row.updatedAt,
|
|
1857
|
-
resourceId: row.resourceId
|
|
1858
|
-
};
|
|
1859
|
-
}
|
|
1860
|
-
var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
1861
|
-
pool;
|
|
1862
|
-
operations;
|
|
1863
|
-
schema;
|
|
1864
|
-
constructor({
|
|
1865
|
-
pool,
|
|
1866
|
-
operations,
|
|
1867
|
-
schema
|
|
1868
|
-
}) {
|
|
1869
|
-
super();
|
|
1870
|
-
this.pool = pool;
|
|
1871
|
-
this.operations = operations;
|
|
1872
|
-
this.schema = schema;
|
|
1873
|
-
}
|
|
1874
|
-
updateWorkflowResults({
|
|
1875
|
-
// workflowName,
|
|
1876
|
-
// runId,
|
|
1877
|
-
// stepId,
|
|
1878
|
-
// result,
|
|
1879
|
-
// runtimeContext,
|
|
1880
|
-
}) {
|
|
1881
|
-
throw new Error("Method not implemented.");
|
|
1882
|
-
}
|
|
1883
|
-
updateWorkflowState({
|
|
1884
|
-
// workflowName,
|
|
1885
|
-
// runId,
|
|
1886
|
-
// opts,
|
|
1887
|
-
}) {
|
|
1888
|
-
throw new Error("Method not implemented.");
|
|
1889
|
-
}
|
|
1890
2912
|
async persistWorkflowSnapshot({
|
|
1891
2913
|
workflowName,
|
|
1892
2914
|
runId,
|
|
2915
|
+
resourceId,
|
|
1893
2916
|
snapshot
|
|
1894
2917
|
}) {
|
|
1895
2918
|
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
@@ -1898,17 +2921,19 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1898
2921
|
const request = this.pool.request();
|
|
1899
2922
|
request.input("workflow_name", workflowName);
|
|
1900
2923
|
request.input("run_id", runId);
|
|
2924
|
+
request.input("resourceId", resourceId);
|
|
1901
2925
|
request.input("snapshot", JSON.stringify(snapshot));
|
|
1902
|
-
request.input("createdAt",
|
|
1903
|
-
request.input("updatedAt",
|
|
2926
|
+
request.input("createdAt", sql3.DateTime2, new Date(now));
|
|
2927
|
+
request.input("updatedAt", sql3.DateTime2, new Date(now));
|
|
1904
2928
|
const mergeSql = `MERGE INTO ${table} AS target
|
|
1905
2929
|
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
1906
2930
|
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
1907
2931
|
WHEN MATCHED THEN UPDATE SET
|
|
2932
|
+
resourceId = @resourceId,
|
|
1908
2933
|
snapshot = @snapshot,
|
|
1909
2934
|
[updatedAt] = @updatedAt
|
|
1910
|
-
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
1911
|
-
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
|
|
2935
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
|
|
2936
|
+
VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
|
|
1912
2937
|
await request.query(mergeSql);
|
|
1913
2938
|
} catch (error) {
|
|
1914
2939
|
throw new MastraError(
|
|
@@ -1980,7 +3005,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1980
3005
|
if (!result.recordset || result.recordset.length === 0) {
|
|
1981
3006
|
return null;
|
|
1982
3007
|
}
|
|
1983
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
3008
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
1984
3009
|
} catch (error) {
|
|
1985
3010
|
throw new MastraError(
|
|
1986
3011
|
{
|
|
@@ -2017,7 +3042,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2017
3042
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2018
3043
|
paramMap["resourceId"] = resourceId;
|
|
2019
3044
|
} else {
|
|
2020
|
-
|
|
3045
|
+
this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2021
3046
|
}
|
|
2022
3047
|
}
|
|
2023
3048
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2034,7 +3059,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2034
3059
|
const request = this.pool.request();
|
|
2035
3060
|
Object.entries(paramMap).forEach(([key, value]) => {
|
|
2036
3061
|
if (value instanceof Date) {
|
|
2037
|
-
request.input(key,
|
|
3062
|
+
request.input(key, sql3.DateTime, value);
|
|
2038
3063
|
} else {
|
|
2039
3064
|
request.input(key, value);
|
|
2040
3065
|
}
|
|
@@ -2051,7 +3076,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2051
3076
|
request.input("offset", offset);
|
|
2052
3077
|
}
|
|
2053
3078
|
const result = await request.query(query);
|
|
2054
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
3079
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2055
3080
|
return { runs, total: total || runs.length };
|
|
2056
3081
|
} catch (error) {
|
|
2057
3082
|
throw new MastraError(
|
|
@@ -2091,7 +3116,7 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2091
3116
|
}
|
|
2092
3117
|
}
|
|
2093
3118
|
this.schema = config.schemaName || "dbo";
|
|
2094
|
-
this.pool = "connectionString" in config ? new
|
|
3119
|
+
this.pool = "connectionString" in config ? new sql3.ConnectionPool(config.connectionString) : new sql3.ConnectionPool({
|
|
2095
3120
|
server: config.server,
|
|
2096
3121
|
database: config.database,
|
|
2097
3122
|
user: config.user,
|
|
@@ -2102,16 +3127,16 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2102
3127
|
const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
|
|
2103
3128
|
const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
|
|
2104
3129
|
const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2105
|
-
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2106
3130
|
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2107
3131
|
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
3132
|
+
const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2108
3133
|
this.stores = {
|
|
2109
3134
|
operations,
|
|
2110
3135
|
scores,
|
|
2111
|
-
traces,
|
|
2112
3136
|
workflows,
|
|
2113
3137
|
legacyEvals,
|
|
2114
|
-
memory
|
|
3138
|
+
memory,
|
|
3139
|
+
observability
|
|
2115
3140
|
};
|
|
2116
3141
|
} catch (e) {
|
|
2117
3142
|
throw new MastraError(
|
|
@@ -2131,6 +3156,11 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2131
3156
|
try {
|
|
2132
3157
|
await this.isConnected;
|
|
2133
3158
|
await super.init();
|
|
3159
|
+
try {
|
|
3160
|
+
await this.stores.operations.createAutomaticIndexes();
|
|
3161
|
+
} catch (indexError) {
|
|
3162
|
+
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
3163
|
+
}
|
|
2134
3164
|
} catch (error) {
|
|
2135
3165
|
this.isConnected = null;
|
|
2136
3166
|
throw new MastraError(
|
|
@@ -2157,7 +3187,10 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2157
3187
|
resourceWorkingMemory: true,
|
|
2158
3188
|
hasColumn: true,
|
|
2159
3189
|
createTable: true,
|
|
2160
|
-
deleteMessages: true
|
|
3190
|
+
deleteMessages: true,
|
|
3191
|
+
getScoresBySpan: true,
|
|
3192
|
+
aiTracing: true,
|
|
3193
|
+
indexManagement: true
|
|
2161
3194
|
};
|
|
2162
3195
|
}
|
|
2163
3196
|
/** @deprecated use getEvals instead */
|
|
@@ -2167,18 +3200,6 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2167
3200
|
async getEvals(options = {}) {
|
|
2168
3201
|
return this.stores.legacyEvals.getEvals(options);
|
|
2169
3202
|
}
|
|
2170
|
-
/**
|
|
2171
|
-
* @deprecated use getTracesPaginated instead
|
|
2172
|
-
*/
|
|
2173
|
-
async getTraces(args) {
|
|
2174
|
-
return this.stores.traces.getTraces(args);
|
|
2175
|
-
}
|
|
2176
|
-
async getTracesPaginated(args) {
|
|
2177
|
-
return this.stores.traces.getTracesPaginated(args);
|
|
2178
|
-
}
|
|
2179
|
-
async batchTraceInsert({ records }) {
|
|
2180
|
-
return this.stores.traces.batchTraceInsert({ records });
|
|
2181
|
-
}
|
|
2182
3203
|
async createTable({
|
|
2183
3204
|
tableName,
|
|
2184
3205
|
schema
|
|
@@ -2293,9 +3314,10 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2293
3314
|
async persistWorkflowSnapshot({
|
|
2294
3315
|
workflowName,
|
|
2295
3316
|
runId,
|
|
3317
|
+
resourceId,
|
|
2296
3318
|
snapshot
|
|
2297
3319
|
}) {
|
|
2298
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
3320
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2299
3321
|
}
|
|
2300
3322
|
async loadWorkflowSnapshot({
|
|
2301
3323
|
workflowName,
|
|
@@ -2322,6 +3344,60 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2322
3344
|
async close() {
|
|
2323
3345
|
await this.pool.close();
|
|
2324
3346
|
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Index Management
|
|
3349
|
+
*/
|
|
3350
|
+
async createIndex(options) {
|
|
3351
|
+
return this.stores.operations.createIndex(options);
|
|
3352
|
+
}
|
|
3353
|
+
async listIndexes(tableName) {
|
|
3354
|
+
return this.stores.operations.listIndexes(tableName);
|
|
3355
|
+
}
|
|
3356
|
+
async describeIndex(indexName) {
|
|
3357
|
+
return this.stores.operations.describeIndex(indexName);
|
|
3358
|
+
}
|
|
3359
|
+
async dropIndex(indexName) {
|
|
3360
|
+
return this.stores.operations.dropIndex(indexName);
|
|
3361
|
+
}
|
|
3362
|
+
/**
|
|
3363
|
+
* AI Tracing / Observability
|
|
3364
|
+
*/
|
|
3365
|
+
getObservabilityStore() {
|
|
3366
|
+
if (!this.stores.observability) {
|
|
3367
|
+
throw new MastraError({
|
|
3368
|
+
id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
3369
|
+
domain: ErrorDomain.STORAGE,
|
|
3370
|
+
category: ErrorCategory.SYSTEM,
|
|
3371
|
+
text: "Observability storage is not initialized"
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
return this.stores.observability;
|
|
3375
|
+
}
|
|
3376
|
+
async createAISpan(span) {
|
|
3377
|
+
return this.getObservabilityStore().createAISpan(span);
|
|
3378
|
+
}
|
|
3379
|
+
async updateAISpan({
|
|
3380
|
+
spanId,
|
|
3381
|
+
traceId,
|
|
3382
|
+
updates
|
|
3383
|
+
}) {
|
|
3384
|
+
return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
|
|
3385
|
+
}
|
|
3386
|
+
async getAITrace(traceId) {
|
|
3387
|
+
return this.getObservabilityStore().getAITrace(traceId);
|
|
3388
|
+
}
|
|
3389
|
+
async getAITracesPaginated(args) {
|
|
3390
|
+
return this.getObservabilityStore().getAITracesPaginated(args);
|
|
3391
|
+
}
|
|
3392
|
+
async batchCreateAISpans(args) {
|
|
3393
|
+
return this.getObservabilityStore().batchCreateAISpans(args);
|
|
3394
|
+
}
|
|
3395
|
+
async batchUpdateAISpans(args) {
|
|
3396
|
+
return this.getObservabilityStore().batchUpdateAISpans(args);
|
|
3397
|
+
}
|
|
3398
|
+
async batchDeleteAITraces(args) {
|
|
3399
|
+
return this.getObservabilityStore().batchDeleteAITraces(args);
|
|
3400
|
+
}
|
|
2325
3401
|
/**
|
|
2326
3402
|
* Scorers
|
|
2327
3403
|
*/
|
|
@@ -2330,9 +3406,18 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2330
3406
|
}
|
|
2331
3407
|
async getScoresByScorerId({
|
|
2332
3408
|
scorerId: _scorerId,
|
|
2333
|
-
pagination: _pagination
|
|
3409
|
+
pagination: _pagination,
|
|
3410
|
+
entityId: _entityId,
|
|
3411
|
+
entityType: _entityType,
|
|
3412
|
+
source: _source
|
|
2334
3413
|
}) {
|
|
2335
|
-
return this.stores.scores.getScoresByScorerId({
|
|
3414
|
+
return this.stores.scores.getScoresByScorerId({
|
|
3415
|
+
scorerId: _scorerId,
|
|
3416
|
+
pagination: _pagination,
|
|
3417
|
+
entityId: _entityId,
|
|
3418
|
+
entityType: _entityType,
|
|
3419
|
+
source: _source
|
|
3420
|
+
});
|
|
2336
3421
|
}
|
|
2337
3422
|
async saveScore(_score) {
|
|
2338
3423
|
return this.stores.scores.saveScore(_score);
|
|
@@ -2354,6 +3439,13 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2354
3439
|
pagination: _pagination
|
|
2355
3440
|
});
|
|
2356
3441
|
}
|
|
3442
|
+
async getScoresBySpan({
|
|
3443
|
+
traceId,
|
|
3444
|
+
spanId,
|
|
3445
|
+
pagination: _pagination
|
|
3446
|
+
}) {
|
|
3447
|
+
return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination: _pagination });
|
|
3448
|
+
}
|
|
2357
3449
|
};
|
|
2358
3450
|
|
|
2359
3451
|
export { MSSQLStore };
|