@mastra/mssql 0.0.0-remove-unused-import-20250909212718 → 0.0.0-remove-unused-model-providers-api-20251030210744
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +179 -3
- package/README.md +315 -36
- package/dist/index.cjs +1602 -549
- 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 +1616 -563
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +4 -7
- 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 +8 -12
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +57 -41
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/storage/domains/legacy-evals/index.d.ts +0 -20
- package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
- 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,
|
|
2
|
+
import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_SCORERS, TABLE_AI_SPANS, ScoresStorage, WorkflowsStorage, MemoryStorage, resolveMessageLimit, TABLE_RESOURCES, ObservabilityStorage, safelyParseJSON } from '@mastra/core/storage';
|
|
3
3
|
import sql2 from 'mssql';
|
|
4
|
-
import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
|
|
5
4
|
import { MessageList } from '@mastra/core/agent';
|
|
5
|
+
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
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,154 +16,71 @@ function getTableName({ indexName, schemaName }) {
|
|
|
14
16
|
const quotedSchemaName = schemaName;
|
|
15
17
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
16
18
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (row.test_info) {
|
|
22
|
-
try {
|
|
23
|
-
testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
|
|
24
|
-
} catch {
|
|
25
|
-
}
|
|
19
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
20
|
+
const filters = {};
|
|
21
|
+
if (dateRange?.start) {
|
|
22
|
+
filters[`${fieldName}_gte`] = dateRange.start;
|
|
26
23
|
}
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
|
|
30
|
-
} catch {
|
|
31
|
-
}
|
|
24
|
+
if (dateRange?.end) {
|
|
25
|
+
filters[`${fieldName}_lte`] = dateRange.end;
|
|
32
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
|
+
});
|
|
33
51
|
return {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
output: row.output,
|
|
37
|
-
result: resultValue,
|
|
38
|
-
metricName: row.metric_name,
|
|
39
|
-
instructions: row.instructions,
|
|
40
|
-
testInfo: testInfoValue,
|
|
41
|
-
globalRunId: row.global_run_id,
|
|
42
|
-
runId: row.run_id,
|
|
43
|
-
createdAt: row.created_at
|
|
52
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
53
|
+
params
|
|
44
54
|
};
|
|
45
55
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
query += " AND test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL";
|
|
60
|
-
} else if (type === "live") {
|
|
61
|
-
query += " AND (test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)";
|
|
62
|
-
}
|
|
63
|
-
query += " ORDER BY created_at DESC";
|
|
64
|
-
const request = this.pool.request();
|
|
65
|
-
request.input("p1", agentName);
|
|
66
|
-
const result = await request.query(query);
|
|
67
|
-
const rows = result.recordset;
|
|
68
|
-
return typeof transformEvalRow === "function" ? rows?.map((row) => transformEvalRow(row)) ?? [] : rows ?? [];
|
|
69
|
-
} catch (error) {
|
|
70
|
-
if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
|
|
71
|
-
return [];
|
|
72
|
-
}
|
|
73
|
-
console.error("Failed to get evals for the specified agent: " + error?.message);
|
|
74
|
-
throw error;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
async getEvals(options = {}) {
|
|
78
|
-
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
79
|
-
const fromDate = dateRange?.start;
|
|
80
|
-
const toDate = dateRange?.end;
|
|
81
|
-
const where = [];
|
|
82
|
-
const params = {};
|
|
83
|
-
if (agentName) {
|
|
84
|
-
where.push("agent_name = @agentName");
|
|
85
|
-
params["agentName"] = agentName;
|
|
86
|
-
}
|
|
87
|
-
if (type === "test") {
|
|
88
|
-
where.push("test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL");
|
|
89
|
-
} else if (type === "live") {
|
|
90
|
-
where.push("(test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)");
|
|
91
|
-
}
|
|
92
|
-
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
93
|
-
where.push(`[created_at] >= @fromDate`);
|
|
94
|
-
params[`fromDate`] = fromDate.toISOString();
|
|
95
|
-
}
|
|
96
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
97
|
-
where.push(`[created_at] <= @toDate`);
|
|
98
|
-
params[`toDate`] = toDate.toISOString();
|
|
99
|
-
}
|
|
100
|
-
const whereClause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
|
|
101
|
-
const tableName = getTableName({ indexName: TABLE_EVALS, schemaName: getSchemaName(this.schema) });
|
|
102
|
-
const offset = page * perPage;
|
|
103
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
|
|
104
|
-
const dataQuery = `SELECT * FROM ${tableName} ${whereClause} ORDER BY seq_id DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
105
|
-
try {
|
|
106
|
-
const countReq = this.pool.request();
|
|
107
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
108
|
-
if (value instanceof Date) {
|
|
109
|
-
countReq.input(key, sql2.DateTime, value);
|
|
110
|
-
} else {
|
|
111
|
-
countReq.input(key, value);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
const countResult = await countReq.query(countQuery);
|
|
115
|
-
const total = countResult.recordset[0]?.total || 0;
|
|
116
|
-
if (total === 0) {
|
|
117
|
-
return {
|
|
118
|
-
evals: [],
|
|
119
|
-
total: 0,
|
|
120
|
-
page,
|
|
121
|
-
perPage,
|
|
122
|
-
hasMore: false
|
|
123
|
-
};
|
|
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;
|
|
124
69
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
req.input("offset", offset);
|
|
134
|
-
req.input("perPage", perPage);
|
|
135
|
-
const result = await req.query(dataQuery);
|
|
136
|
-
const rows = result.recordset;
|
|
137
|
-
return {
|
|
138
|
-
evals: rows?.map((row) => transformEvalRow(row)) ?? [],
|
|
139
|
-
total,
|
|
140
|
-
page,
|
|
141
|
-
perPage,
|
|
142
|
-
hasMore: offset + (rows?.length ?? 0) < total
|
|
143
|
-
};
|
|
144
|
-
} catch (error) {
|
|
145
|
-
const mastraError = new MastraError(
|
|
146
|
-
{
|
|
147
|
-
id: "MASTRA_STORAGE_MSSQL_STORE_GET_EVALS_FAILED",
|
|
148
|
-
domain: ErrorDomain.STORAGE,
|
|
149
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
150
|
-
details: {
|
|
151
|
-
agentName: agentName || "all",
|
|
152
|
-
type: type || "all",
|
|
153
|
-
page,
|
|
154
|
-
perPage
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
error
|
|
158
|
-
);
|
|
159
|
-
this.logger?.error?.(mastraError.toString());
|
|
160
|
-
this.logger?.trackException(mastraError);
|
|
161
|
-
throw mastraError;
|
|
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;
|
|
162
78
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
79
|
+
});
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/storage/domains/memory/index.ts
|
|
165
84
|
var MemoryMSSQL = class extends MemoryStorage {
|
|
166
85
|
pool;
|
|
167
86
|
schema;
|
|
@@ -193,7 +112,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
193
112
|
}
|
|
194
113
|
async getThreadById({ threadId }) {
|
|
195
114
|
try {
|
|
196
|
-
const
|
|
115
|
+
const sql5 = `SELECT
|
|
197
116
|
id,
|
|
198
117
|
[resourceId],
|
|
199
118
|
title,
|
|
@@ -204,7 +123,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
204
123
|
WHERE id = @threadId`;
|
|
205
124
|
const request = this.pool.request();
|
|
206
125
|
request.input("threadId", threadId);
|
|
207
|
-
const resultSet = await request.query(
|
|
126
|
+
const resultSet = await request.query(sql5);
|
|
208
127
|
const thread = resultSet.recordset[0] || null;
|
|
209
128
|
if (!thread) {
|
|
210
129
|
return null;
|
|
@@ -250,7 +169,8 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
250
169
|
};
|
|
251
170
|
}
|
|
252
171
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
253
|
-
const
|
|
172
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
173
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
254
174
|
const dataRequest = this.pool.request();
|
|
255
175
|
dataRequest.input("resourceId", resourceId);
|
|
256
176
|
dataRequest.input("perPage", perPage);
|
|
@@ -307,7 +227,12 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
307
227
|
req.input("id", thread.id);
|
|
308
228
|
req.input("resourceId", thread.resourceId);
|
|
309
229
|
req.input("title", thread.title);
|
|
310
|
-
|
|
230
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
231
|
+
if (metadata === null) {
|
|
232
|
+
req.input("metadata", sql2.NVarChar, null);
|
|
233
|
+
} else {
|
|
234
|
+
req.input("metadata", metadata);
|
|
235
|
+
}
|
|
311
236
|
req.input("createdAt", sql2.DateTime2, thread.createdAt);
|
|
312
237
|
req.input("updatedAt", sql2.DateTime2, thread.updatedAt);
|
|
313
238
|
await req.query(mergeSql);
|
|
@@ -334,7 +259,8 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
334
259
|
try {
|
|
335
260
|
const baseQuery = `FROM ${getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
336
261
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
337
|
-
const
|
|
262
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
263
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
|
|
338
264
|
const request = this.pool.request();
|
|
339
265
|
request.input("resourceId", resourceId);
|
|
340
266
|
const resultSet = await request.query(dataQuery);
|
|
@@ -377,7 +303,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
377
303
|
};
|
|
378
304
|
try {
|
|
379
305
|
const table = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
380
|
-
const
|
|
306
|
+
const sql5 = `UPDATE ${table}
|
|
381
307
|
SET title = @title,
|
|
382
308
|
metadata = @metadata,
|
|
383
309
|
[updatedAt] = @updatedAt
|
|
@@ -388,7 +314,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
388
314
|
req.input("title", title);
|
|
389
315
|
req.input("metadata", JSON.stringify(mergedMetadata));
|
|
390
316
|
req.input("updatedAt", /* @__PURE__ */ new Date());
|
|
391
|
-
const result = await req.query(
|
|
317
|
+
const result = await req.query(sql5);
|
|
392
318
|
let thread = result.recordset && result.recordset[0];
|
|
393
319
|
if (thread && "seq_id" in thread) {
|
|
394
320
|
const { seq_id, ...rest } = thread;
|
|
@@ -458,8 +384,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
458
384
|
}
|
|
459
385
|
async _getIncludedMessages({
|
|
460
386
|
threadId,
|
|
461
|
-
selectBy
|
|
462
|
-
orderByStatement
|
|
387
|
+
selectBy
|
|
463
388
|
}) {
|
|
464
389
|
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
465
390
|
const include = selectBy?.include;
|
|
@@ -487,7 +412,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
487
412
|
m.[resourceId],
|
|
488
413
|
m.seq_id
|
|
489
414
|
FROM (
|
|
490
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
415
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
491
416
|
FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
492
417
|
WHERE [thread_id] = ${pThreadId}
|
|
493
418
|
) AS m
|
|
@@ -495,15 +420,17 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
495
420
|
OR EXISTS (
|
|
496
421
|
SELECT 1
|
|
497
422
|
FROM (
|
|
498
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
423
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
499
424
|
FROM ${getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
500
425
|
WHERE [thread_id] = ${pThreadId}
|
|
501
426
|
) AS target
|
|
502
427
|
WHERE target.id = ${pId}
|
|
503
428
|
AND (
|
|
504
|
-
|
|
429
|
+
-- Get previous messages (messages that come BEFORE the target)
|
|
430
|
+
(m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
|
|
505
431
|
OR
|
|
506
|
-
|
|
432
|
+
-- Get next messages (messages that come AFTER the target)
|
|
433
|
+
(m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
|
|
507
434
|
)
|
|
508
435
|
)
|
|
509
436
|
`
|
|
@@ -542,7 +469,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
542
469
|
let rows = [];
|
|
543
470
|
const include = selectBy?.include || [];
|
|
544
471
|
if (include?.length) {
|
|
545
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy
|
|
472
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
546
473
|
if (includeMessages) {
|
|
547
474
|
rows.push(...includeMessages);
|
|
548
475
|
}
|
|
@@ -583,14 +510,11 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
583
510
|
error
|
|
584
511
|
);
|
|
585
512
|
this.logger?.error?.(mastraError.toString());
|
|
586
|
-
this.logger?.trackException(mastraError);
|
|
513
|
+
this.logger?.trackException?.(mastraError);
|
|
587
514
|
return [];
|
|
588
515
|
}
|
|
589
516
|
}
|
|
590
|
-
async
|
|
591
|
-
messageIds,
|
|
592
|
-
format
|
|
593
|
-
}) {
|
|
517
|
+
async listMessagesById({ messageIds }) {
|
|
594
518
|
if (messageIds.length === 0) return [];
|
|
595
519
|
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
596
520
|
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
@@ -608,8 +532,8 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
608
532
|
return timeDiff;
|
|
609
533
|
});
|
|
610
534
|
rows = rows.map(({ seq_id, ...rest }) => rest);
|
|
611
|
-
|
|
612
|
-
return
|
|
535
|
+
const messages = this._parseAndFormatMessages(rows, `v2`);
|
|
536
|
+
return messages;
|
|
613
537
|
} catch (error) {
|
|
614
538
|
const mastraError = new MastraError(
|
|
615
539
|
{
|
|
@@ -623,10 +547,139 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
623
547
|
error
|
|
624
548
|
);
|
|
625
549
|
this.logger?.error?.(mastraError.toString());
|
|
626
|
-
this.logger?.trackException(mastraError);
|
|
550
|
+
this.logger?.trackException?.(mastraError);
|
|
627
551
|
return [];
|
|
628
552
|
}
|
|
629
553
|
}
|
|
554
|
+
async listMessages(args) {
|
|
555
|
+
const { threadId, resourceId, include, filter, limit, offset = 0, orderBy } = args;
|
|
556
|
+
if (!threadId.trim()) {
|
|
557
|
+
throw new MastraError(
|
|
558
|
+
{
|
|
559
|
+
id: "STORAGE_MSSQL_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
560
|
+
domain: ErrorDomain.STORAGE,
|
|
561
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
562
|
+
details: { threadId }
|
|
563
|
+
},
|
|
564
|
+
new Error("threadId must be a non-empty string")
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
try {
|
|
568
|
+
let perPage = 40;
|
|
569
|
+
if (limit !== void 0) {
|
|
570
|
+
if (limit === false) {
|
|
571
|
+
perPage = Number.MAX_SAFE_INTEGER;
|
|
572
|
+
} else if (limit === 0) {
|
|
573
|
+
perPage = 0;
|
|
574
|
+
} else if (typeof limit === "number" && limit > 0) {
|
|
575
|
+
perPage = limit;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const page = perPage === 0 ? 0 : Math.floor(offset / perPage);
|
|
579
|
+
const sortField = orderBy?.field || "createdAt";
|
|
580
|
+
const sortDirection = orderBy?.direction || "DESC";
|
|
581
|
+
const orderByStatement = `ORDER BY [${sortField}] ${sortDirection}`;
|
|
582
|
+
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
583
|
+
const tableName = getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
584
|
+
const conditions = ["[thread_id] = @threadId"];
|
|
585
|
+
const request = this.pool.request();
|
|
586
|
+
request.input("threadId", threadId);
|
|
587
|
+
if (resourceId) {
|
|
588
|
+
conditions.push("[resourceId] = @resourceId");
|
|
589
|
+
request.input("resourceId", resourceId);
|
|
590
|
+
}
|
|
591
|
+
if (filter?.dateRange?.start) {
|
|
592
|
+
conditions.push("[createdAt] >= @fromDate");
|
|
593
|
+
request.input("fromDate", filter.dateRange.start);
|
|
594
|
+
}
|
|
595
|
+
if (filter?.dateRange?.end) {
|
|
596
|
+
conditions.push("[createdAt] <= @toDate");
|
|
597
|
+
request.input("toDate", filter.dateRange.end);
|
|
598
|
+
}
|
|
599
|
+
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
600
|
+
const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
|
|
601
|
+
const countResult = await request.query(countQuery);
|
|
602
|
+
const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
|
|
603
|
+
const dataQuery = `${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
604
|
+
request.input("offset", offset);
|
|
605
|
+
if (perPage > 2147483647) {
|
|
606
|
+
request.input("limit", sql2.BigInt, perPage);
|
|
607
|
+
} else {
|
|
608
|
+
request.input("limit", perPage);
|
|
609
|
+
}
|
|
610
|
+
const rowsResult = await request.query(dataQuery);
|
|
611
|
+
const rows = rowsResult.recordset || [];
|
|
612
|
+
const messages = [...rows];
|
|
613
|
+
if (total === 0 && messages.length === 0) {
|
|
614
|
+
return {
|
|
615
|
+
messages: [],
|
|
616
|
+
total: 0,
|
|
617
|
+
page,
|
|
618
|
+
perPage,
|
|
619
|
+
hasMore: false
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
623
|
+
if (include && include.length > 0) {
|
|
624
|
+
const selectBy = { include };
|
|
625
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
626
|
+
if (includeMessages) {
|
|
627
|
+
for (const includeMsg of includeMessages) {
|
|
628
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
629
|
+
messages.push(includeMsg);
|
|
630
|
+
messageIds.add(includeMsg.id);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const parsed = this._parseAndFormatMessages(messages, "v2");
|
|
636
|
+
let finalMessages = parsed;
|
|
637
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
638
|
+
const aValue = sortField === "createdAt" ? new Date(a.createdAt).getTime() : a[sortField];
|
|
639
|
+
const bValue = sortField === "createdAt" ? new Date(b.createdAt).getTime() : b[sortField];
|
|
640
|
+
return sortDirection === "ASC" ? aValue - bValue : bValue - aValue;
|
|
641
|
+
});
|
|
642
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
643
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
644
|
+
const hasMore = limit === false ? false : allThreadMessagesReturned ? false : offset + rows.length < total;
|
|
645
|
+
return {
|
|
646
|
+
messages: finalMessages,
|
|
647
|
+
total,
|
|
648
|
+
page,
|
|
649
|
+
perPage,
|
|
650
|
+
hasMore
|
|
651
|
+
};
|
|
652
|
+
} catch (error) {
|
|
653
|
+
const errorPerPage = limit === false ? Number.MAX_SAFE_INTEGER : limit === 0 ? 0 : limit || 40;
|
|
654
|
+
const mastraError = new MastraError(
|
|
655
|
+
{
|
|
656
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_MESSAGES_FAILED",
|
|
657
|
+
domain: ErrorDomain.STORAGE,
|
|
658
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
659
|
+
details: {
|
|
660
|
+
threadId,
|
|
661
|
+
resourceId: resourceId ?? ""
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
error
|
|
665
|
+
);
|
|
666
|
+
this.logger?.error?.(mastraError.toString());
|
|
667
|
+
this.logger?.trackException?.(mastraError);
|
|
668
|
+
return {
|
|
669
|
+
messages: [],
|
|
670
|
+
total: 0,
|
|
671
|
+
page: errorPerPage === 0 ? 0 : Math.floor(offset / errorPerPage),
|
|
672
|
+
perPage: errorPerPage,
|
|
673
|
+
hasMore: false
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
async listThreadsByResourceId(args) {
|
|
678
|
+
const { resourceId, limit, offset, orderBy, sortDirection } = args;
|
|
679
|
+
const page = Math.floor(offset / limit);
|
|
680
|
+
const perPage = limit;
|
|
681
|
+
return this.getThreadsByResourceIdPaginated({ resourceId, page, perPage, orderBy, sortDirection });
|
|
682
|
+
}
|
|
630
683
|
async getMessagesPaginated(args) {
|
|
631
684
|
const { threadId, resourceId, format, selectBy } = args;
|
|
632
685
|
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
@@ -638,7 +691,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
638
691
|
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
639
692
|
let messages = [];
|
|
640
693
|
if (selectBy?.include?.length) {
|
|
641
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy
|
|
694
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
642
695
|
if (includeMessages) messages.push(...includeMessages);
|
|
643
696
|
}
|
|
644
697
|
const perPage = perPageInput !== void 0 ? perPageInput : resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
@@ -685,7 +738,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
685
738
|
const parsed = this._parseAndFormatMessages(messages, format);
|
|
686
739
|
return {
|
|
687
740
|
messages: parsed,
|
|
688
|
-
total
|
|
741
|
+
total,
|
|
689
742
|
page,
|
|
690
743
|
perPage,
|
|
691
744
|
hasMore: currentOffset + rows.length < total
|
|
@@ -705,7 +758,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
705
758
|
error
|
|
706
759
|
);
|
|
707
760
|
this.logger?.error?.(mastraError.toString());
|
|
708
|
-
this.logger?.trackException(mastraError);
|
|
761
|
+
this.logger?.trackException?.(mastraError);
|
|
709
762
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
710
763
|
}
|
|
711
764
|
}
|
|
@@ -972,8 +1025,10 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
972
1025
|
return null;
|
|
973
1026
|
}
|
|
974
1027
|
return {
|
|
975
|
-
|
|
976
|
-
|
|
1028
|
+
id: result.id,
|
|
1029
|
+
createdAt: result.createdAt,
|
|
1030
|
+
updatedAt: result.updatedAt,
|
|
1031
|
+
workingMemory: result.workingMemory,
|
|
977
1032
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
978
1033
|
};
|
|
979
1034
|
} catch (error) {
|
|
@@ -987,7 +1042,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
987
1042
|
error
|
|
988
1043
|
);
|
|
989
1044
|
this.logger?.error?.(mastraError.toString());
|
|
990
|
-
this.logger?.trackException(mastraError);
|
|
1045
|
+
this.logger?.trackException?.(mastraError);
|
|
991
1046
|
throw mastraError;
|
|
992
1047
|
}
|
|
993
1048
|
}
|
|
@@ -996,7 +1051,7 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
996
1051
|
tableName: TABLE_RESOURCES,
|
|
997
1052
|
record: {
|
|
998
1053
|
...resource,
|
|
999
|
-
metadata:
|
|
1054
|
+
metadata: resource.metadata
|
|
1000
1055
|
}
|
|
1001
1056
|
});
|
|
1002
1057
|
return resource;
|
|
@@ -1054,141 +1109,466 @@ var MemoryMSSQL = class extends MemoryStorage {
|
|
|
1054
1109
|
error
|
|
1055
1110
|
);
|
|
1056
1111
|
this.logger?.error?.(mastraError.toString());
|
|
1057
|
-
this.logger?.trackException(mastraError);
|
|
1112
|
+
this.logger?.trackException?.(mastraError);
|
|
1058
1113
|
throw mastraError;
|
|
1059
1114
|
}
|
|
1060
1115
|
}
|
|
1061
1116
|
};
|
|
1062
|
-
var
|
|
1117
|
+
var ObservabilityMSSQL = class extends ObservabilityStorage {
|
|
1063
1118
|
pool;
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
case "timestamp":
|
|
1072
|
-
return "DATETIME2(7)";
|
|
1073
|
-
case "uuid":
|
|
1074
|
-
return "UNIQUEIDENTIFIER";
|
|
1075
|
-
case "jsonb":
|
|
1076
|
-
return "NVARCHAR(MAX)";
|
|
1077
|
-
case "integer":
|
|
1078
|
-
return "INT";
|
|
1079
|
-
case "bigint":
|
|
1080
|
-
return "BIGINT";
|
|
1081
|
-
case "float":
|
|
1082
|
-
return "FLOAT";
|
|
1083
|
-
default:
|
|
1084
|
-
throw new MastraError({
|
|
1085
|
-
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1086
|
-
domain: ErrorDomain.STORAGE,
|
|
1087
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
constructor({ pool, schemaName }) {
|
|
1119
|
+
operations;
|
|
1120
|
+
schema;
|
|
1121
|
+
constructor({
|
|
1122
|
+
pool,
|
|
1123
|
+
operations,
|
|
1124
|
+
schema
|
|
1125
|
+
}) {
|
|
1092
1126
|
super();
|
|
1093
1127
|
this.pool = pool;
|
|
1094
|
-
this.
|
|
1095
|
-
|
|
1096
|
-
async hasColumn(table, column) {
|
|
1097
|
-
const schema = this.schemaName || "dbo";
|
|
1098
|
-
const request = this.pool.request();
|
|
1099
|
-
request.input("schema", schema);
|
|
1100
|
-
request.input("table", table);
|
|
1101
|
-
request.input("column", column);
|
|
1102
|
-
request.input("columnLower", column.toLowerCase());
|
|
1103
|
-
const result = await request.query(
|
|
1104
|
-
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1105
|
-
);
|
|
1106
|
-
return result.recordset.length > 0;
|
|
1128
|
+
this.operations = operations;
|
|
1129
|
+
this.schema = schema;
|
|
1107
1130
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
this.setupSchemaPromise = (async () => {
|
|
1114
|
-
try {
|
|
1115
|
-
const checkRequest = this.pool.request();
|
|
1116
|
-
checkRequest.input("schemaName", this.schemaName);
|
|
1117
|
-
const checkResult = await checkRequest.query(`
|
|
1118
|
-
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
1119
|
-
`);
|
|
1120
|
-
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1121
|
-
if (!schemaExists) {
|
|
1122
|
-
try {
|
|
1123
|
-
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
1124
|
-
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
1125
|
-
} catch (error) {
|
|
1126
|
-
this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
|
|
1127
|
-
throw new Error(
|
|
1128
|
-
`Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
|
|
1129
|
-
);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
this.schemaSetupComplete = true;
|
|
1133
|
-
this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
|
|
1134
|
-
} catch (error) {
|
|
1135
|
-
this.schemaSetupComplete = void 0;
|
|
1136
|
-
this.setupSchemaPromise = null;
|
|
1137
|
-
throw error;
|
|
1138
|
-
} finally {
|
|
1139
|
-
this.setupSchemaPromise = null;
|
|
1140
|
-
}
|
|
1141
|
-
})();
|
|
1142
|
-
}
|
|
1143
|
-
await this.setupSchemaPromise;
|
|
1131
|
+
get aiTracingStrategy() {
|
|
1132
|
+
return {
|
|
1133
|
+
preferred: "batch-with-updates",
|
|
1134
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
1135
|
+
};
|
|
1144
1136
|
}
|
|
1145
|
-
async
|
|
1137
|
+
async createAISpan(span) {
|
|
1146
1138
|
try {
|
|
1147
|
-
const
|
|
1148
|
-
const
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
request.input(`param${i}`, JSON.stringify(value));
|
|
1157
|
-
} else {
|
|
1158
|
-
request.input(`param${i}`, value);
|
|
1159
|
-
}
|
|
1160
|
-
});
|
|
1161
|
-
await request.query(insertSql);
|
|
1139
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
1140
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
1141
|
+
const record = {
|
|
1142
|
+
...span,
|
|
1143
|
+
startedAt,
|
|
1144
|
+
endedAt
|
|
1145
|
+
// Note: createdAt/updatedAt will be set by default values
|
|
1146
|
+
};
|
|
1147
|
+
return this.operations.insert({ tableName: TABLE_AI_SPANS, record });
|
|
1162
1148
|
} catch (error) {
|
|
1163
1149
|
throw new MastraError(
|
|
1164
1150
|
{
|
|
1165
|
-
id: "
|
|
1151
|
+
id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
|
|
1166
1152
|
domain: ErrorDomain.STORAGE,
|
|
1167
|
-
category: ErrorCategory.
|
|
1153
|
+
category: ErrorCategory.USER,
|
|
1168
1154
|
details: {
|
|
1169
|
-
|
|
1155
|
+
spanId: span.spanId,
|
|
1156
|
+
traceId: span.traceId,
|
|
1157
|
+
spanType: span.spanType,
|
|
1158
|
+
spanName: span.name
|
|
1170
1159
|
}
|
|
1171
1160
|
},
|
|
1172
1161
|
error
|
|
1173
1162
|
);
|
|
1174
1163
|
}
|
|
1175
1164
|
}
|
|
1176
|
-
async
|
|
1177
|
-
const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1165
|
+
async getAITrace(traceId) {
|
|
1178
1166
|
try {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1167
|
+
const tableName = getTableName({
|
|
1168
|
+
indexName: TABLE_AI_SPANS,
|
|
1169
|
+
schemaName: getSchemaName(this.schema)
|
|
1170
|
+
});
|
|
1171
|
+
const request = this.pool.request();
|
|
1172
|
+
request.input("traceId", traceId);
|
|
1173
|
+
const result = await request.query(
|
|
1174
|
+
`SELECT
|
|
1175
|
+
[traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
|
|
1176
|
+
[attributes], [metadata], [links], [input], [output], [error], [isEvent],
|
|
1177
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
1178
|
+
FROM ${tableName}
|
|
1179
|
+
WHERE [traceId] = @traceId
|
|
1180
|
+
ORDER BY [startedAt] DESC`
|
|
1181
|
+
);
|
|
1182
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1183
|
+
return null;
|
|
1187
1184
|
}
|
|
1185
|
+
return {
|
|
1186
|
+
traceId,
|
|
1187
|
+
spans: result.recordset.map(
|
|
1188
|
+
(span) => transformFromSqlRow({
|
|
1189
|
+
tableName: TABLE_AI_SPANS,
|
|
1190
|
+
sqlRow: span
|
|
1191
|
+
})
|
|
1192
|
+
)
|
|
1193
|
+
};
|
|
1188
1194
|
} catch (error) {
|
|
1189
1195
|
throw new MastraError(
|
|
1190
1196
|
{
|
|
1191
|
-
id: "
|
|
1197
|
+
id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
|
|
1198
|
+
domain: ErrorDomain.STORAGE,
|
|
1199
|
+
category: ErrorCategory.USER,
|
|
1200
|
+
details: {
|
|
1201
|
+
traceId
|
|
1202
|
+
}
|
|
1203
|
+
},
|
|
1204
|
+
error
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
async updateAISpan({
|
|
1209
|
+
spanId,
|
|
1210
|
+
traceId,
|
|
1211
|
+
updates
|
|
1212
|
+
}) {
|
|
1213
|
+
try {
|
|
1214
|
+
const data = { ...updates };
|
|
1215
|
+
if (data.endedAt instanceof Date) {
|
|
1216
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1217
|
+
}
|
|
1218
|
+
if (data.startedAt instanceof Date) {
|
|
1219
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1220
|
+
}
|
|
1221
|
+
await this.operations.update({
|
|
1222
|
+
tableName: TABLE_AI_SPANS,
|
|
1223
|
+
keys: { spanId, traceId },
|
|
1224
|
+
data
|
|
1225
|
+
});
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
throw new MastraError(
|
|
1228
|
+
{
|
|
1229
|
+
id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
|
|
1230
|
+
domain: ErrorDomain.STORAGE,
|
|
1231
|
+
category: ErrorCategory.USER,
|
|
1232
|
+
details: {
|
|
1233
|
+
spanId,
|
|
1234
|
+
traceId
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
error
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
async getAITracesPaginated({
|
|
1242
|
+
filters,
|
|
1243
|
+
pagination
|
|
1244
|
+
}) {
|
|
1245
|
+
const page = pagination?.page ?? 0;
|
|
1246
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1247
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1248
|
+
const filtersWithDateRange = {
|
|
1249
|
+
...actualFilters,
|
|
1250
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
1251
|
+
parentSpanId: null
|
|
1252
|
+
// Only get root spans for traces
|
|
1253
|
+
};
|
|
1254
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
1255
|
+
let actualWhereClause = whereClause.sql;
|
|
1256
|
+
const params = { ...whereClause.params };
|
|
1257
|
+
let currentParamIndex = Object.keys(params).length + 1;
|
|
1258
|
+
if (entityId && entityType) {
|
|
1259
|
+
let name = "";
|
|
1260
|
+
if (entityType === "workflow") {
|
|
1261
|
+
name = `workflow run: '${entityId}'`;
|
|
1262
|
+
} else if (entityType === "agent") {
|
|
1263
|
+
name = `agent run: '${entityId}'`;
|
|
1264
|
+
} else {
|
|
1265
|
+
const error = new MastraError({
|
|
1266
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1267
|
+
domain: ErrorDomain.STORAGE,
|
|
1268
|
+
category: ErrorCategory.USER,
|
|
1269
|
+
details: {
|
|
1270
|
+
entityType
|
|
1271
|
+
},
|
|
1272
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1273
|
+
});
|
|
1274
|
+
throw error;
|
|
1275
|
+
}
|
|
1276
|
+
const entityParam = `p${currentParamIndex++}`;
|
|
1277
|
+
if (actualWhereClause) {
|
|
1278
|
+
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
1279
|
+
} else {
|
|
1280
|
+
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
1281
|
+
}
|
|
1282
|
+
params[entityParam] = name;
|
|
1283
|
+
}
|
|
1284
|
+
const tableName = getTableName({
|
|
1285
|
+
indexName: TABLE_AI_SPANS,
|
|
1286
|
+
schemaName: getSchemaName(this.schema)
|
|
1287
|
+
});
|
|
1288
|
+
try {
|
|
1289
|
+
const countRequest = this.pool.request();
|
|
1290
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1291
|
+
countRequest.input(key, value);
|
|
1292
|
+
});
|
|
1293
|
+
const countResult = await countRequest.query(
|
|
1294
|
+
`SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
|
|
1295
|
+
);
|
|
1296
|
+
const total = countResult.recordset[0]?.count ?? 0;
|
|
1297
|
+
if (total === 0) {
|
|
1298
|
+
return {
|
|
1299
|
+
pagination: {
|
|
1300
|
+
total: 0,
|
|
1301
|
+
page,
|
|
1302
|
+
perPage,
|
|
1303
|
+
hasMore: false
|
|
1304
|
+
},
|
|
1305
|
+
spans: []
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
const dataRequest = this.pool.request();
|
|
1309
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1310
|
+
dataRequest.input(key, value);
|
|
1311
|
+
});
|
|
1312
|
+
dataRequest.input("offset", page * perPage);
|
|
1313
|
+
dataRequest.input("limit", perPage);
|
|
1314
|
+
const dataResult = await dataRequest.query(
|
|
1315
|
+
`SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1316
|
+
);
|
|
1317
|
+
const spans = dataResult.recordset.map(
|
|
1318
|
+
(row) => transformFromSqlRow({
|
|
1319
|
+
tableName: TABLE_AI_SPANS,
|
|
1320
|
+
sqlRow: row
|
|
1321
|
+
})
|
|
1322
|
+
);
|
|
1323
|
+
return {
|
|
1324
|
+
pagination: {
|
|
1325
|
+
total,
|
|
1326
|
+
page,
|
|
1327
|
+
perPage,
|
|
1328
|
+
hasMore: (page + 1) * perPage < total
|
|
1329
|
+
},
|
|
1330
|
+
spans
|
|
1331
|
+
};
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
throw new MastraError(
|
|
1334
|
+
{
|
|
1335
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1336
|
+
domain: ErrorDomain.STORAGE,
|
|
1337
|
+
category: ErrorCategory.USER
|
|
1338
|
+
},
|
|
1339
|
+
error
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
async batchCreateAISpans(args) {
|
|
1344
|
+
if (!args.records || args.records.length === 0) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
try {
|
|
1348
|
+
await this.operations.batchInsert({
|
|
1349
|
+
tableName: TABLE_AI_SPANS,
|
|
1350
|
+
records: args.records.map((span) => ({
|
|
1351
|
+
...span,
|
|
1352
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
1353
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
1354
|
+
}))
|
|
1355
|
+
});
|
|
1356
|
+
} catch (error) {
|
|
1357
|
+
throw new MastraError(
|
|
1358
|
+
{
|
|
1359
|
+
id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
1360
|
+
domain: ErrorDomain.STORAGE,
|
|
1361
|
+
category: ErrorCategory.USER,
|
|
1362
|
+
details: {
|
|
1363
|
+
count: args.records.length
|
|
1364
|
+
}
|
|
1365
|
+
},
|
|
1366
|
+
error
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
async batchUpdateAISpans(args) {
|
|
1371
|
+
if (!args.records || args.records.length === 0) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
try {
|
|
1375
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
1376
|
+
const processedData = { ...data };
|
|
1377
|
+
if (processedData.endedAt instanceof Date) {
|
|
1378
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
1379
|
+
}
|
|
1380
|
+
if (processedData.startedAt instanceof Date) {
|
|
1381
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
1382
|
+
}
|
|
1383
|
+
return {
|
|
1384
|
+
keys: { spanId, traceId },
|
|
1385
|
+
data: processedData
|
|
1386
|
+
};
|
|
1387
|
+
});
|
|
1388
|
+
await this.operations.batchUpdate({
|
|
1389
|
+
tableName: TABLE_AI_SPANS,
|
|
1390
|
+
updates
|
|
1391
|
+
});
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
throw new MastraError(
|
|
1394
|
+
{
|
|
1395
|
+
id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
1396
|
+
domain: ErrorDomain.STORAGE,
|
|
1397
|
+
category: ErrorCategory.USER,
|
|
1398
|
+
details: {
|
|
1399
|
+
count: args.records.length
|
|
1400
|
+
}
|
|
1401
|
+
},
|
|
1402
|
+
error
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
async batchDeleteAITraces(args) {
|
|
1407
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
try {
|
|
1411
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
1412
|
+
await this.operations.batchDelete({
|
|
1413
|
+
tableName: TABLE_AI_SPANS,
|
|
1414
|
+
keys
|
|
1415
|
+
});
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
throw new MastraError(
|
|
1418
|
+
{
|
|
1419
|
+
id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
1420
|
+
domain: ErrorDomain.STORAGE,
|
|
1421
|
+
category: ErrorCategory.USER,
|
|
1422
|
+
details: {
|
|
1423
|
+
count: args.traceIds.length
|
|
1424
|
+
}
|
|
1425
|
+
},
|
|
1426
|
+
error
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
var StoreOperationsMSSQL = class extends StoreOperations {
|
|
1432
|
+
pool;
|
|
1433
|
+
schemaName;
|
|
1434
|
+
setupSchemaPromise = null;
|
|
1435
|
+
schemaSetupComplete = void 0;
|
|
1436
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
|
|
1437
|
+
switch (type) {
|
|
1438
|
+
case "text":
|
|
1439
|
+
if (useLargeStorage) {
|
|
1440
|
+
return "NVARCHAR(MAX)";
|
|
1441
|
+
}
|
|
1442
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
1443
|
+
case "timestamp":
|
|
1444
|
+
return "DATETIME2(7)";
|
|
1445
|
+
case "uuid":
|
|
1446
|
+
return "UNIQUEIDENTIFIER";
|
|
1447
|
+
case "jsonb":
|
|
1448
|
+
return "NVARCHAR(MAX)";
|
|
1449
|
+
case "integer":
|
|
1450
|
+
return "INT";
|
|
1451
|
+
case "bigint":
|
|
1452
|
+
return "BIGINT";
|
|
1453
|
+
case "float":
|
|
1454
|
+
return "FLOAT";
|
|
1455
|
+
case "boolean":
|
|
1456
|
+
return "BIT";
|
|
1457
|
+
default:
|
|
1458
|
+
throw new MastraError({
|
|
1459
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1460
|
+
domain: ErrorDomain.STORAGE,
|
|
1461
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
constructor({ pool, schemaName }) {
|
|
1466
|
+
super();
|
|
1467
|
+
this.pool = pool;
|
|
1468
|
+
this.schemaName = schemaName;
|
|
1469
|
+
}
|
|
1470
|
+
async hasColumn(table, column) {
|
|
1471
|
+
const schema = this.schemaName || "dbo";
|
|
1472
|
+
const request = this.pool.request();
|
|
1473
|
+
request.input("schema", schema);
|
|
1474
|
+
request.input("table", table);
|
|
1475
|
+
request.input("column", column);
|
|
1476
|
+
request.input("columnLower", column.toLowerCase());
|
|
1477
|
+
const result = await request.query(
|
|
1478
|
+
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1479
|
+
);
|
|
1480
|
+
return result.recordset.length > 0;
|
|
1481
|
+
}
|
|
1482
|
+
async setupSchema() {
|
|
1483
|
+
if (!this.schemaName || this.schemaSetupComplete) {
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
if (!this.setupSchemaPromise) {
|
|
1487
|
+
this.setupSchemaPromise = (async () => {
|
|
1488
|
+
try {
|
|
1489
|
+
const checkRequest = this.pool.request();
|
|
1490
|
+
checkRequest.input("schemaName", this.schemaName);
|
|
1491
|
+
const checkResult = await checkRequest.query(`
|
|
1492
|
+
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
1493
|
+
`);
|
|
1494
|
+
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1495
|
+
if (!schemaExists) {
|
|
1496
|
+
try {
|
|
1497
|
+
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
1498
|
+
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
1499
|
+
} catch (error) {
|
|
1500
|
+
this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
|
|
1501
|
+
throw new Error(
|
|
1502
|
+
`Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
this.schemaSetupComplete = true;
|
|
1507
|
+
this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
|
|
1508
|
+
} catch (error) {
|
|
1509
|
+
this.schemaSetupComplete = void 0;
|
|
1510
|
+
this.setupSchemaPromise = null;
|
|
1511
|
+
throw error;
|
|
1512
|
+
} finally {
|
|
1513
|
+
this.setupSchemaPromise = null;
|
|
1514
|
+
}
|
|
1515
|
+
})();
|
|
1516
|
+
}
|
|
1517
|
+
await this.setupSchemaPromise;
|
|
1518
|
+
}
|
|
1519
|
+
async insert({
|
|
1520
|
+
tableName,
|
|
1521
|
+
record,
|
|
1522
|
+
transaction
|
|
1523
|
+
}) {
|
|
1524
|
+
try {
|
|
1525
|
+
const columns = Object.keys(record);
|
|
1526
|
+
const parsedColumns = columns.map((col) => parseSqlIdentifier(col, "column name"));
|
|
1527
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
1528
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1529
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1530
|
+
columns.forEach((col, i) => {
|
|
1531
|
+
const value = record[col];
|
|
1532
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
1533
|
+
if (preparedValue instanceof Date) {
|
|
1534
|
+
request.input(`param${i}`, sql2.DateTime2, preparedValue);
|
|
1535
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
1536
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
1537
|
+
} else {
|
|
1538
|
+
request.input(`param${i}`, preparedValue);
|
|
1539
|
+
}
|
|
1540
|
+
});
|
|
1541
|
+
await request.query(insertSql);
|
|
1542
|
+
} catch (error) {
|
|
1543
|
+
throw new MastraError(
|
|
1544
|
+
{
|
|
1545
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_INSERT_FAILED",
|
|
1546
|
+
domain: ErrorDomain.STORAGE,
|
|
1547
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1548
|
+
details: {
|
|
1549
|
+
tableName
|
|
1550
|
+
}
|
|
1551
|
+
},
|
|
1552
|
+
error
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
async clearTable({ tableName }) {
|
|
1557
|
+
const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1558
|
+
try {
|
|
1559
|
+
try {
|
|
1560
|
+
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
1561
|
+
} catch (truncateError) {
|
|
1562
|
+
if (truncateError?.number === 4712) {
|
|
1563
|
+
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
1564
|
+
} else {
|
|
1565
|
+
throw truncateError;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
} catch (error) {
|
|
1569
|
+
throw new MastraError(
|
|
1570
|
+
{
|
|
1571
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CLEAR_TABLE_FAILED",
|
|
1192
1572
|
domain: ErrorDomain.STORAGE,
|
|
1193
1573
|
category: ErrorCategory.THIRD_PARTY,
|
|
1194
1574
|
details: {
|
|
@@ -1202,9 +1582,11 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1202
1582
|
getDefaultValue(type) {
|
|
1203
1583
|
switch (type) {
|
|
1204
1584
|
case "timestamp":
|
|
1205
|
-
return "DEFAULT
|
|
1585
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
1206
1586
|
case "jsonb":
|
|
1207
1587
|
return "DEFAULT N'{}'";
|
|
1588
|
+
case "boolean":
|
|
1589
|
+
return "DEFAULT 0";
|
|
1208
1590
|
default:
|
|
1209
1591
|
return super.getDefaultValue(type);
|
|
1210
1592
|
}
|
|
@@ -1215,13 +1597,29 @@ var StoreOperationsMSSQL = class extends StoreOperations {
|
|
|
1215
1597
|
}) {
|
|
1216
1598
|
try {
|
|
1217
1599
|
const uniqueConstraintColumns = tableName === TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
1600
|
+
const largeDataColumns = [
|
|
1601
|
+
"workingMemory",
|
|
1602
|
+
"snapshot",
|
|
1603
|
+
"metadata",
|
|
1604
|
+
"content",
|
|
1605
|
+
// messages.content - can be very long conversation content
|
|
1606
|
+
"input",
|
|
1607
|
+
// evals.input - test input data
|
|
1608
|
+
"output",
|
|
1609
|
+
// evals.output - test output data
|
|
1610
|
+
"instructions",
|
|
1611
|
+
// evals.instructions - evaluation instructions
|
|
1612
|
+
"other"
|
|
1613
|
+
// traces.other - additional trace data
|
|
1614
|
+
];
|
|
1218
1615
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1219
1616
|
const parsedName = parseSqlIdentifier(name, "column name");
|
|
1220
1617
|
const constraints = [];
|
|
1221
1618
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1222
1619
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1223
1620
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
1224
|
-
|
|
1621
|
+
const useLargeStorage = largeDataColumns.includes(name);
|
|
1622
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
|
|
1225
1623
|
}).join(",\n");
|
|
1226
1624
|
if (this.schemaName) {
|
|
1227
1625
|
await this.setupSchema();
|
|
@@ -1308,7 +1706,19 @@ ${columns}
|
|
|
1308
1706
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1309
1707
|
if (!columnExists) {
|
|
1310
1708
|
const columnDef = schema[columnName];
|
|
1311
|
-
const
|
|
1709
|
+
const largeDataColumns = [
|
|
1710
|
+
"workingMemory",
|
|
1711
|
+
"snapshot",
|
|
1712
|
+
"metadata",
|
|
1713
|
+
"content",
|
|
1714
|
+
"input",
|
|
1715
|
+
"output",
|
|
1716
|
+
"instructions",
|
|
1717
|
+
"other"
|
|
1718
|
+
];
|
|
1719
|
+
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
1720
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
1721
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
1312
1722
|
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1313
1723
|
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1314
1724
|
const parsedColumnName = parseSqlIdentifier(columnName, "column name");
|
|
@@ -1336,13 +1746,17 @@ ${columns}
|
|
|
1336
1746
|
try {
|
|
1337
1747
|
const keyEntries = Object.entries(keys).map(([key, value]) => [parseSqlIdentifier(key, "column name"), value]);
|
|
1338
1748
|
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}`;
|
|
1749
|
+
const sql5 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1341
1750
|
const request = this.pool.request();
|
|
1342
|
-
|
|
1343
|
-
|
|
1751
|
+
keyEntries.forEach(([key, value], i) => {
|
|
1752
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1753
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1754
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
1755
|
+
} else {
|
|
1756
|
+
request.input(`param${i}`, preparedValue);
|
|
1757
|
+
}
|
|
1344
1758
|
});
|
|
1345
|
-
const resultSet = await request.query(
|
|
1759
|
+
const resultSet = await request.query(sql5);
|
|
1346
1760
|
const result = resultSet.recordset[0] || null;
|
|
1347
1761
|
if (!result) {
|
|
1348
1762
|
return null;
|
|
@@ -1374,63 +1788,599 @@ ${columns}
|
|
|
1374
1788
|
try {
|
|
1375
1789
|
await transaction.begin();
|
|
1376
1790
|
for (const record of records) {
|
|
1377
|
-
await this.insert({ tableName, record });
|
|
1791
|
+
await this.insert({ tableName, record, transaction });
|
|
1792
|
+
}
|
|
1793
|
+
await transaction.commit();
|
|
1794
|
+
} catch (error) {
|
|
1795
|
+
await transaction.rollback();
|
|
1796
|
+
throw new MastraError(
|
|
1797
|
+
{
|
|
1798
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
|
|
1799
|
+
domain: ErrorDomain.STORAGE,
|
|
1800
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1801
|
+
details: {
|
|
1802
|
+
tableName,
|
|
1803
|
+
numberOfRecords: records.length
|
|
1804
|
+
}
|
|
1805
|
+
},
|
|
1806
|
+
error
|
|
1807
|
+
);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
async dropTable({ tableName }) {
|
|
1811
|
+
try {
|
|
1812
|
+
const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1813
|
+
await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
|
|
1814
|
+
} catch (error) {
|
|
1815
|
+
throw new MastraError(
|
|
1816
|
+
{
|
|
1817
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
|
|
1818
|
+
domain: ErrorDomain.STORAGE,
|
|
1819
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1820
|
+
details: {
|
|
1821
|
+
tableName
|
|
1822
|
+
}
|
|
1823
|
+
},
|
|
1824
|
+
error
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
1830
|
+
*/
|
|
1831
|
+
prepareValue(value, columnName, tableName) {
|
|
1832
|
+
if (value === null || value === void 0) {
|
|
1833
|
+
return value;
|
|
1834
|
+
}
|
|
1835
|
+
if (value instanceof Date) {
|
|
1836
|
+
return value;
|
|
1837
|
+
}
|
|
1838
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
1839
|
+
const columnSchema = schema?.[columnName];
|
|
1840
|
+
if (columnSchema?.type === "boolean") {
|
|
1841
|
+
return value ? 1 : 0;
|
|
1842
|
+
}
|
|
1843
|
+
if (columnSchema?.type === "jsonb") {
|
|
1844
|
+
return JSON.stringify(value);
|
|
1845
|
+
}
|
|
1846
|
+
if (typeof value === "object") {
|
|
1847
|
+
return JSON.stringify(value);
|
|
1848
|
+
}
|
|
1849
|
+
return value;
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
1853
|
+
*/
|
|
1854
|
+
getMssqlType(tableName, columnName) {
|
|
1855
|
+
const col = TABLE_SCHEMAS[tableName]?.[columnName];
|
|
1856
|
+
switch (col?.type) {
|
|
1857
|
+
case "text":
|
|
1858
|
+
return sql2.NVarChar;
|
|
1859
|
+
case "timestamp":
|
|
1860
|
+
return sql2.DateTime2;
|
|
1861
|
+
case "uuid":
|
|
1862
|
+
return sql2.UniqueIdentifier;
|
|
1863
|
+
case "jsonb":
|
|
1864
|
+
return sql2.NVarChar;
|
|
1865
|
+
case "integer":
|
|
1866
|
+
return sql2.Int;
|
|
1867
|
+
case "bigint":
|
|
1868
|
+
return sql2.BigInt;
|
|
1869
|
+
case "float":
|
|
1870
|
+
return sql2.Float;
|
|
1871
|
+
case "boolean":
|
|
1872
|
+
return sql2.Bit;
|
|
1873
|
+
default:
|
|
1874
|
+
return sql2.NVarChar;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* Update a single record in the database
|
|
1879
|
+
*/
|
|
1880
|
+
async update({
|
|
1881
|
+
tableName,
|
|
1882
|
+
keys,
|
|
1883
|
+
data,
|
|
1884
|
+
transaction
|
|
1885
|
+
}) {
|
|
1886
|
+
try {
|
|
1887
|
+
if (!data || Object.keys(data).length === 0) {
|
|
1888
|
+
throw new MastraError({
|
|
1889
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
|
|
1890
|
+
domain: ErrorDomain.STORAGE,
|
|
1891
|
+
category: ErrorCategory.USER,
|
|
1892
|
+
text: "Cannot update with empty data payload"
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1896
|
+
throw new MastraError({
|
|
1897
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
|
|
1898
|
+
domain: ErrorDomain.STORAGE,
|
|
1899
|
+
category: ErrorCategory.USER,
|
|
1900
|
+
text: "Cannot update without keys to identify records"
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
const setClauses = [];
|
|
1904
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1905
|
+
let paramIndex = 0;
|
|
1906
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1907
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1908
|
+
const paramName = `set${paramIndex++}`;
|
|
1909
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
1910
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1911
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1912
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1913
|
+
} else {
|
|
1914
|
+
request.input(paramName, preparedValue);
|
|
1915
|
+
}
|
|
1916
|
+
});
|
|
1917
|
+
const whereConditions = [];
|
|
1918
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
1919
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1920
|
+
const paramName = `where${paramIndex++}`;
|
|
1921
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1922
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1923
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1924
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1925
|
+
} else {
|
|
1926
|
+
request.input(paramName, preparedValue);
|
|
1927
|
+
}
|
|
1928
|
+
});
|
|
1929
|
+
const tableName_ = getTableName({
|
|
1930
|
+
indexName: tableName,
|
|
1931
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1932
|
+
});
|
|
1933
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
1934
|
+
await request.query(updateSql);
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
throw new MastraError(
|
|
1937
|
+
{
|
|
1938
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
|
|
1939
|
+
domain: ErrorDomain.STORAGE,
|
|
1940
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1941
|
+
details: {
|
|
1942
|
+
tableName
|
|
1943
|
+
}
|
|
1944
|
+
},
|
|
1945
|
+
error
|
|
1946
|
+
);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
/**
|
|
1950
|
+
* Update multiple records in a single batch transaction
|
|
1951
|
+
*/
|
|
1952
|
+
async batchUpdate({
|
|
1953
|
+
tableName,
|
|
1954
|
+
updates
|
|
1955
|
+
}) {
|
|
1956
|
+
const transaction = this.pool.transaction();
|
|
1957
|
+
try {
|
|
1958
|
+
await transaction.begin();
|
|
1959
|
+
for (const { keys, data } of updates) {
|
|
1960
|
+
await this.update({ tableName, keys, data, transaction });
|
|
1961
|
+
}
|
|
1962
|
+
await transaction.commit();
|
|
1963
|
+
} catch (error) {
|
|
1964
|
+
await transaction.rollback();
|
|
1965
|
+
throw new MastraError(
|
|
1966
|
+
{
|
|
1967
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
|
|
1968
|
+
domain: ErrorDomain.STORAGE,
|
|
1969
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1970
|
+
details: {
|
|
1971
|
+
tableName,
|
|
1972
|
+
numberOfRecords: updates.length
|
|
1973
|
+
}
|
|
1974
|
+
},
|
|
1975
|
+
error
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* Delete multiple records by keys
|
|
1981
|
+
*/
|
|
1982
|
+
async batchDelete({ tableName, keys }) {
|
|
1983
|
+
if (keys.length === 0) {
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
const tableName_ = getTableName({
|
|
1987
|
+
indexName: tableName,
|
|
1988
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1989
|
+
});
|
|
1990
|
+
const transaction = this.pool.transaction();
|
|
1991
|
+
try {
|
|
1992
|
+
await transaction.begin();
|
|
1993
|
+
for (const keySet of keys) {
|
|
1994
|
+
const conditions = [];
|
|
1995
|
+
const request = transaction.request();
|
|
1996
|
+
let paramIndex = 0;
|
|
1997
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
1998
|
+
const parsedKey = parseSqlIdentifier(key, "column name");
|
|
1999
|
+
const paramName = `p${paramIndex++}`;
|
|
2000
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
2001
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
2002
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
2003
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
2004
|
+
} else {
|
|
2005
|
+
request.input(paramName, preparedValue);
|
|
2006
|
+
}
|
|
2007
|
+
});
|
|
2008
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
2009
|
+
await request.query(deleteSql);
|
|
2010
|
+
}
|
|
2011
|
+
await transaction.commit();
|
|
2012
|
+
} catch (error) {
|
|
2013
|
+
await transaction.rollback();
|
|
2014
|
+
throw new MastraError(
|
|
2015
|
+
{
|
|
2016
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
|
|
2017
|
+
domain: ErrorDomain.STORAGE,
|
|
2018
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2019
|
+
details: {
|
|
2020
|
+
tableName,
|
|
2021
|
+
numberOfRecords: keys.length
|
|
2022
|
+
}
|
|
2023
|
+
},
|
|
2024
|
+
error
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
* Create a new index on a table
|
|
2030
|
+
*/
|
|
2031
|
+
async createIndex(options) {
|
|
2032
|
+
try {
|
|
2033
|
+
const { name, table, columns, unique = false, where } = options;
|
|
2034
|
+
const schemaName = this.schemaName || "dbo";
|
|
2035
|
+
const fullTableName = getTableName({
|
|
2036
|
+
indexName: table,
|
|
2037
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2038
|
+
});
|
|
2039
|
+
const indexNameSafe = parseSqlIdentifier(name, "index name");
|
|
2040
|
+
const checkRequest = this.pool.request();
|
|
2041
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2042
|
+
checkRequest.input("schemaName", schemaName);
|
|
2043
|
+
checkRequest.input("tableName", table);
|
|
2044
|
+
const indexExists = await checkRequest.query(`
|
|
2045
|
+
SELECT 1 as found
|
|
2046
|
+
FROM sys.indexes i
|
|
2047
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2048
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2049
|
+
WHERE i.name = @indexName
|
|
2050
|
+
AND s.name = @schemaName
|
|
2051
|
+
AND t.name = @tableName
|
|
2052
|
+
`);
|
|
2053
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
2057
|
+
const columnsStr = columns.map((col) => {
|
|
2058
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
2059
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
2060
|
+
if (!colName) {
|
|
2061
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
2062
|
+
}
|
|
2063
|
+
return `[${parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
2064
|
+
}
|
|
2065
|
+
return `[${parseSqlIdentifier(col, "column name")}]`;
|
|
2066
|
+
}).join(", ");
|
|
2067
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
2068
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
2069
|
+
await this.pool.request().query(createIndexSql);
|
|
2070
|
+
} catch (error) {
|
|
2071
|
+
throw new MastraError(
|
|
2072
|
+
{
|
|
2073
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
|
|
2074
|
+
domain: ErrorDomain.STORAGE,
|
|
2075
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2076
|
+
details: {
|
|
2077
|
+
indexName: options.name,
|
|
2078
|
+
tableName: options.table
|
|
2079
|
+
}
|
|
2080
|
+
},
|
|
2081
|
+
error
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
/**
|
|
2086
|
+
* Drop an existing index
|
|
2087
|
+
*/
|
|
2088
|
+
async dropIndex(indexName) {
|
|
2089
|
+
try {
|
|
2090
|
+
const schemaName = this.schemaName || "dbo";
|
|
2091
|
+
const indexNameSafe = parseSqlIdentifier(indexName, "index name");
|
|
2092
|
+
const checkRequest = this.pool.request();
|
|
2093
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2094
|
+
checkRequest.input("schemaName", schemaName);
|
|
2095
|
+
const result = await checkRequest.query(`
|
|
2096
|
+
SELECT t.name as table_name
|
|
2097
|
+
FROM sys.indexes i
|
|
2098
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2099
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2100
|
+
WHERE i.name = @indexName
|
|
2101
|
+
AND s.name = @schemaName
|
|
2102
|
+
`);
|
|
2103
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
if (result.recordset.length > 1) {
|
|
2107
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
2108
|
+
throw new MastraError({
|
|
2109
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
|
|
2110
|
+
domain: ErrorDomain.STORAGE,
|
|
2111
|
+
category: ErrorCategory.USER,
|
|
2112
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
const tableName = result.recordset[0].table_name;
|
|
2116
|
+
const fullTableName = getTableName({
|
|
2117
|
+
indexName: tableName,
|
|
2118
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2119
|
+
});
|
|
2120
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
2121
|
+
await this.pool.request().query(dropSql);
|
|
2122
|
+
} catch (error) {
|
|
2123
|
+
throw new MastraError(
|
|
2124
|
+
{
|
|
2125
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
|
|
2126
|
+
domain: ErrorDomain.STORAGE,
|
|
2127
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2128
|
+
details: {
|
|
2129
|
+
indexName
|
|
2130
|
+
}
|
|
2131
|
+
},
|
|
2132
|
+
error
|
|
2133
|
+
);
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* List indexes for a specific table or all tables
|
|
2138
|
+
*/
|
|
2139
|
+
async listIndexes(tableName) {
|
|
2140
|
+
try {
|
|
2141
|
+
const schemaName = this.schemaName || "dbo";
|
|
2142
|
+
let query;
|
|
2143
|
+
const request = this.pool.request();
|
|
2144
|
+
request.input("schemaName", schemaName);
|
|
2145
|
+
if (tableName) {
|
|
2146
|
+
query = `
|
|
2147
|
+
SELECT
|
|
2148
|
+
i.name as name,
|
|
2149
|
+
o.name as [table],
|
|
2150
|
+
i.is_unique as is_unique,
|
|
2151
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2152
|
+
FROM sys.indexes i
|
|
2153
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2154
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2155
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2156
|
+
WHERE sch.name = @schemaName
|
|
2157
|
+
AND o.name = @tableName
|
|
2158
|
+
AND i.name IS NOT NULL
|
|
2159
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2160
|
+
`;
|
|
2161
|
+
request.input("tableName", tableName);
|
|
2162
|
+
} else {
|
|
2163
|
+
query = `
|
|
2164
|
+
SELECT
|
|
2165
|
+
i.name as name,
|
|
2166
|
+
o.name as [table],
|
|
2167
|
+
i.is_unique as is_unique,
|
|
2168
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2169
|
+
FROM sys.indexes i
|
|
2170
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2171
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2172
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2173
|
+
WHERE sch.name = @schemaName
|
|
2174
|
+
AND i.name IS NOT NULL
|
|
2175
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2176
|
+
`;
|
|
2177
|
+
}
|
|
2178
|
+
const result = await request.query(query);
|
|
2179
|
+
const indexes = [];
|
|
2180
|
+
for (const row of result.recordset) {
|
|
2181
|
+
const colRequest = this.pool.request();
|
|
2182
|
+
colRequest.input("indexName", row.name);
|
|
2183
|
+
colRequest.input("schemaName", schemaName);
|
|
2184
|
+
const colResult = await colRequest.query(`
|
|
2185
|
+
SELECT c.name as column_name
|
|
2186
|
+
FROM sys.indexes i
|
|
2187
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2188
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2189
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2190
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2191
|
+
WHERE i.name = @indexName
|
|
2192
|
+
AND s.name = @schemaName
|
|
2193
|
+
ORDER BY ic.key_ordinal
|
|
2194
|
+
`);
|
|
2195
|
+
indexes.push({
|
|
2196
|
+
name: row.name,
|
|
2197
|
+
table: row.table,
|
|
2198
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2199
|
+
unique: row.is_unique || false,
|
|
2200
|
+
size: row.size || "0 MB",
|
|
2201
|
+
definition: ""
|
|
2202
|
+
// MSSQL doesn't store definition like PG
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
return indexes;
|
|
2206
|
+
} catch (error) {
|
|
2207
|
+
throw new MastraError(
|
|
2208
|
+
{
|
|
2209
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
|
|
2210
|
+
domain: ErrorDomain.STORAGE,
|
|
2211
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2212
|
+
details: tableName ? {
|
|
2213
|
+
tableName
|
|
2214
|
+
} : {}
|
|
2215
|
+
},
|
|
2216
|
+
error
|
|
2217
|
+
);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
/**
|
|
2221
|
+
* Get detailed statistics for a specific index
|
|
2222
|
+
*/
|
|
2223
|
+
async describeIndex(indexName) {
|
|
2224
|
+
try {
|
|
2225
|
+
const schemaName = this.schemaName || "dbo";
|
|
2226
|
+
const request = this.pool.request();
|
|
2227
|
+
request.input("indexName", indexName);
|
|
2228
|
+
request.input("schemaName", schemaName);
|
|
2229
|
+
const query = `
|
|
2230
|
+
SELECT
|
|
2231
|
+
i.name as name,
|
|
2232
|
+
o.name as [table],
|
|
2233
|
+
i.is_unique as is_unique,
|
|
2234
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
2235
|
+
i.type_desc as method,
|
|
2236
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
2237
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
2238
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
2239
|
+
FROM sys.indexes i
|
|
2240
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2241
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2242
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2243
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
2244
|
+
WHERE i.name = @indexName
|
|
2245
|
+
AND sch.name = @schemaName
|
|
2246
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
2247
|
+
`;
|
|
2248
|
+
const result = await request.query(query);
|
|
2249
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2250
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
1378
2251
|
}
|
|
1379
|
-
|
|
2252
|
+
const row = result.recordset[0];
|
|
2253
|
+
const colRequest = this.pool.request();
|
|
2254
|
+
colRequest.input("indexName", indexName);
|
|
2255
|
+
colRequest.input("schemaName", schemaName);
|
|
2256
|
+
const colResult = await colRequest.query(`
|
|
2257
|
+
SELECT c.name as column_name
|
|
2258
|
+
FROM sys.indexes i
|
|
2259
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2260
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2261
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2262
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2263
|
+
WHERE i.name = @indexName
|
|
2264
|
+
AND s.name = @schemaName
|
|
2265
|
+
ORDER BY ic.key_ordinal
|
|
2266
|
+
`);
|
|
2267
|
+
return {
|
|
2268
|
+
name: row.name,
|
|
2269
|
+
table: row.table,
|
|
2270
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2271
|
+
unique: row.is_unique || false,
|
|
2272
|
+
size: row.size || "0 MB",
|
|
2273
|
+
definition: "",
|
|
2274
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
2275
|
+
scans: Number(row.scans) || 0,
|
|
2276
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
2277
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
2278
|
+
};
|
|
1380
2279
|
} catch (error) {
|
|
1381
|
-
await transaction.rollback();
|
|
1382
2280
|
throw new MastraError(
|
|
1383
2281
|
{
|
|
1384
|
-
id: "
|
|
2282
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
|
|
1385
2283
|
domain: ErrorDomain.STORAGE,
|
|
1386
2284
|
category: ErrorCategory.THIRD_PARTY,
|
|
1387
2285
|
details: {
|
|
1388
|
-
|
|
1389
|
-
numberOfRecords: records.length
|
|
2286
|
+
indexName
|
|
1390
2287
|
}
|
|
1391
2288
|
},
|
|
1392
2289
|
error
|
|
1393
2290
|
);
|
|
1394
2291
|
}
|
|
1395
2292
|
}
|
|
1396
|
-
|
|
2293
|
+
/**
|
|
2294
|
+
* Returns definitions for automatic performance indexes
|
|
2295
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2296
|
+
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
2297
|
+
*/
|
|
2298
|
+
getAutomaticIndexDefinitions() {
|
|
2299
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2300
|
+
return [
|
|
2301
|
+
// Composite indexes for optimal filtering + sorting performance
|
|
2302
|
+
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
2303
|
+
{
|
|
2304
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
2305
|
+
table: TABLE_THREADS,
|
|
2306
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
2310
|
+
table: TABLE_MESSAGES,
|
|
2311
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
2312
|
+
},
|
|
2313
|
+
{
|
|
2314
|
+
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
2315
|
+
table: TABLE_TRACES,
|
|
2316
|
+
columns: ["name", "seq_id DESC"]
|
|
2317
|
+
},
|
|
2318
|
+
{
|
|
2319
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2320
|
+
table: TABLE_SCORERS,
|
|
2321
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2322
|
+
},
|
|
2323
|
+
// AI Spans indexes for optimal trace querying
|
|
2324
|
+
{
|
|
2325
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2326
|
+
table: TABLE_AI_SPANS,
|
|
2327
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2328
|
+
},
|
|
2329
|
+
{
|
|
2330
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2331
|
+
table: TABLE_AI_SPANS,
|
|
2332
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2333
|
+
},
|
|
2334
|
+
{
|
|
2335
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2336
|
+
table: TABLE_AI_SPANS,
|
|
2337
|
+
columns: ["name"]
|
|
2338
|
+
},
|
|
2339
|
+
{
|
|
2340
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2341
|
+
table: TABLE_AI_SPANS,
|
|
2342
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2343
|
+
}
|
|
2344
|
+
];
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* Creates automatic indexes for optimal query performance
|
|
2348
|
+
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
2349
|
+
*/
|
|
2350
|
+
async createAutomaticIndexes() {
|
|
1397
2351
|
try {
|
|
1398
|
-
const
|
|
1399
|
-
|
|
2352
|
+
const indexes = this.getAutomaticIndexDefinitions();
|
|
2353
|
+
for (const indexOptions of indexes) {
|
|
2354
|
+
try {
|
|
2355
|
+
await this.createIndex(indexOptions);
|
|
2356
|
+
} catch (error) {
|
|
2357
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
1400
2360
|
} catch (error) {
|
|
1401
2361
|
throw new MastraError(
|
|
1402
2362
|
{
|
|
1403
|
-
id: "
|
|
2363
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
1404
2364
|
domain: ErrorDomain.STORAGE,
|
|
1405
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1406
|
-
details: {
|
|
1407
|
-
tableName
|
|
1408
|
-
}
|
|
2365
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1409
2366
|
},
|
|
1410
2367
|
error
|
|
1411
2368
|
);
|
|
1412
2369
|
}
|
|
1413
2370
|
}
|
|
1414
2371
|
};
|
|
1415
|
-
function parseJSON(jsonString) {
|
|
1416
|
-
try {
|
|
1417
|
-
return JSON.parse(jsonString);
|
|
1418
|
-
} catch {
|
|
1419
|
-
return jsonString;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
2372
|
function transformScoreRow(row) {
|
|
1423
2373
|
return {
|
|
1424
2374
|
...row,
|
|
1425
|
-
input:
|
|
1426
|
-
scorer:
|
|
1427
|
-
preprocessStepResult:
|
|
1428
|
-
analyzeStepResult:
|
|
1429
|
-
metadata:
|
|
1430
|
-
output:
|
|
1431
|
-
additionalContext:
|
|
1432
|
-
|
|
1433
|
-
entity:
|
|
2375
|
+
input: safelyParseJSON(row.input),
|
|
2376
|
+
scorer: safelyParseJSON(row.scorer),
|
|
2377
|
+
preprocessStepResult: safelyParseJSON(row.preprocessStepResult),
|
|
2378
|
+
analyzeStepResult: safelyParseJSON(row.analyzeStepResult),
|
|
2379
|
+
metadata: safelyParseJSON(row.metadata),
|
|
2380
|
+
output: safelyParseJSON(row.output),
|
|
2381
|
+
additionalContext: safelyParseJSON(row.additionalContext),
|
|
2382
|
+
requestContext: safelyParseJSON(row.requestContext),
|
|
2383
|
+
entity: safelyParseJSON(row.entity),
|
|
1434
2384
|
createdAt: row.createdAt,
|
|
1435
2385
|
updatedAt: row.updatedAt
|
|
1436
2386
|
};
|
|
@@ -1473,8 +2423,21 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1473
2423
|
}
|
|
1474
2424
|
}
|
|
1475
2425
|
async saveScore(score) {
|
|
2426
|
+
let validatedScore;
|
|
1476
2427
|
try {
|
|
1477
|
-
|
|
2428
|
+
validatedScore = saveScorePayloadSchema.parse(score);
|
|
2429
|
+
} catch (error) {
|
|
2430
|
+
throw new MastraError(
|
|
2431
|
+
{
|
|
2432
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_SAVE_SCORE_VALIDATION_FAILED",
|
|
2433
|
+
domain: ErrorDomain.STORAGE,
|
|
2434
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2435
|
+
},
|
|
2436
|
+
error
|
|
2437
|
+
);
|
|
2438
|
+
}
|
|
2439
|
+
try {
|
|
2440
|
+
const scoreId = randomUUID();
|
|
1478
2441
|
const {
|
|
1479
2442
|
scorer,
|
|
1480
2443
|
preprocessStepResult,
|
|
@@ -1483,24 +2446,24 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1483
2446
|
input,
|
|
1484
2447
|
output,
|
|
1485
2448
|
additionalContext,
|
|
1486
|
-
|
|
2449
|
+
requestContext,
|
|
1487
2450
|
entity,
|
|
1488
2451
|
...rest
|
|
1489
|
-
} =
|
|
2452
|
+
} = validatedScore;
|
|
1490
2453
|
await this.operations.insert({
|
|
1491
2454
|
tableName: TABLE_SCORERS,
|
|
1492
2455
|
record: {
|
|
1493
2456
|
id: scoreId,
|
|
1494
2457
|
...rest,
|
|
1495
|
-
input:
|
|
1496
|
-
output:
|
|
1497
|
-
preprocessStepResult: preprocessStepResult
|
|
1498
|
-
analyzeStepResult: analyzeStepResult
|
|
1499
|
-
metadata: metadata
|
|
1500
|
-
additionalContext: additionalContext
|
|
1501
|
-
|
|
1502
|
-
entity: entity
|
|
1503
|
-
scorer: scorer
|
|
2458
|
+
input: input || "",
|
|
2459
|
+
output: output || "",
|
|
2460
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2461
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2462
|
+
metadata: metadata || null,
|
|
2463
|
+
additionalContext: additionalContext || null,
|
|
2464
|
+
requestContext: requestContext || null,
|
|
2465
|
+
entity: entity || null,
|
|
2466
|
+
scorer: scorer || null,
|
|
1504
2467
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1505
2468
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1506
2469
|
}
|
|
@@ -1520,14 +2483,37 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1520
2483
|
}
|
|
1521
2484
|
async getScoresByScorerId({
|
|
1522
2485
|
scorerId,
|
|
1523
|
-
pagination
|
|
2486
|
+
pagination,
|
|
2487
|
+
entityId,
|
|
2488
|
+
entityType,
|
|
2489
|
+
source
|
|
1524
2490
|
}) {
|
|
1525
2491
|
try {
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
2492
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2493
|
+
const params = { p1: scorerId };
|
|
2494
|
+
let paramIndex = 2;
|
|
2495
|
+
if (entityId) {
|
|
2496
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2497
|
+
params[`p${paramIndex}`] = entityId;
|
|
2498
|
+
paramIndex++;
|
|
2499
|
+
}
|
|
2500
|
+
if (entityType) {
|
|
2501
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2502
|
+
params[`p${paramIndex}`] = entityType;
|
|
2503
|
+
paramIndex++;
|
|
2504
|
+
}
|
|
2505
|
+
if (source) {
|
|
2506
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2507
|
+
params[`p${paramIndex}`] = source;
|
|
2508
|
+
paramIndex++;
|
|
2509
|
+
}
|
|
2510
|
+
const whereClause = conditions.join(" AND ");
|
|
2511
|
+
const tableName = getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
|
|
2512
|
+
const countRequest = this.pool.request();
|
|
2513
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2514
|
+
countRequest.input(key, value);
|
|
2515
|
+
});
|
|
2516
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1531
2517
|
const total = totalResult.recordset[0]?.count || 0;
|
|
1532
2518
|
if (total === 0) {
|
|
1533
2519
|
return {
|
|
@@ -1541,12 +2527,13 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1541
2527
|
};
|
|
1542
2528
|
}
|
|
1543
2529
|
const dataRequest = this.pool.request();
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
2530
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2531
|
+
dataRequest.input(key, value);
|
|
2532
|
+
});
|
|
2533
|
+
dataRequest.input("perPage", pagination.perPage);
|
|
2534
|
+
dataRequest.input("offset", pagination.page * pagination.perPage);
|
|
2535
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2536
|
+
const result = await dataRequest.query(dataQuery);
|
|
1550
2537
|
return {
|
|
1551
2538
|
pagination: {
|
|
1552
2539
|
total: Number(total),
|
|
@@ -1671,8 +2658,62 @@ var ScoresMSSQL = class extends ScoresStorage {
|
|
|
1671
2658
|
);
|
|
1672
2659
|
}
|
|
1673
2660
|
}
|
|
2661
|
+
async getScoresBySpan({
|
|
2662
|
+
traceId,
|
|
2663
|
+
spanId,
|
|
2664
|
+
pagination
|
|
2665
|
+
}) {
|
|
2666
|
+
try {
|
|
2667
|
+
const request = this.pool.request();
|
|
2668
|
+
request.input("p1", traceId);
|
|
2669
|
+
request.input("p2", spanId);
|
|
2670
|
+
const totalResult = await request.query(
|
|
2671
|
+
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: TABLE_SCORERS, schemaName: getSchemaName(this.schema) })} WHERE [traceId] = @p1 AND [spanId] = @p2`
|
|
2672
|
+
);
|
|
2673
|
+
const total = totalResult.recordset[0]?.count || 0;
|
|
2674
|
+
if (total === 0) {
|
|
2675
|
+
return {
|
|
2676
|
+
pagination: {
|
|
2677
|
+
total: 0,
|
|
2678
|
+
page: pagination.page,
|
|
2679
|
+
perPage: pagination.perPage,
|
|
2680
|
+
hasMore: false
|
|
2681
|
+
},
|
|
2682
|
+
scores: []
|
|
2683
|
+
};
|
|
2684
|
+
}
|
|
2685
|
+
const limit = pagination.perPage + 1;
|
|
2686
|
+
const dataRequest = this.pool.request();
|
|
2687
|
+
dataRequest.input("p1", traceId);
|
|
2688
|
+
dataRequest.input("p2", spanId);
|
|
2689
|
+
dataRequest.input("p3", limit);
|
|
2690
|
+
dataRequest.input("p4", pagination.page * pagination.perPage);
|
|
2691
|
+
const result = await dataRequest.query(
|
|
2692
|
+
`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`
|
|
2693
|
+
);
|
|
2694
|
+
return {
|
|
2695
|
+
pagination: {
|
|
2696
|
+
total: Number(total),
|
|
2697
|
+
page: pagination.page,
|
|
2698
|
+
perPage: pagination.perPage,
|
|
2699
|
+
hasMore: result.recordset.length > pagination.perPage
|
|
2700
|
+
},
|
|
2701
|
+
scores: result.recordset.slice(0, pagination.perPage).map((row) => transformScoreRow(row))
|
|
2702
|
+
};
|
|
2703
|
+
} catch (error) {
|
|
2704
|
+
throw new MastraError(
|
|
2705
|
+
{
|
|
2706
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
2707
|
+
domain: ErrorDomain.STORAGE,
|
|
2708
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2709
|
+
details: { traceId, spanId }
|
|
2710
|
+
},
|
|
2711
|
+
error
|
|
2712
|
+
);
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
1674
2715
|
};
|
|
1675
|
-
var
|
|
2716
|
+
var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
1676
2717
|
pool;
|
|
1677
2718
|
operations;
|
|
1678
2719
|
schema;
|
|
@@ -1686,210 +2727,168 @@ var TracesMSSQL = class extends TracesStorage {
|
|
|
1686
2727
|
this.operations = operations;
|
|
1687
2728
|
this.schema = schema;
|
|
1688
2729
|
}
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
if (
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
const result = await this.getTracesPaginated(args);
|
|
1698
|
-
return result.traces;
|
|
1699
|
-
}
|
|
1700
|
-
async getTracesPaginated(args) {
|
|
1701
|
-
const { name, scope, page = 0, perPage: perPageInput, attributes, filters, dateRange } = args;
|
|
1702
|
-
const fromDate = dateRange?.start;
|
|
1703
|
-
const toDate = dateRange?.end;
|
|
1704
|
-
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1705
|
-
const currentOffset = page * perPage;
|
|
1706
|
-
const paramMap = {};
|
|
1707
|
-
const conditions = [];
|
|
1708
|
-
let paramIndex = 1;
|
|
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();
|
|
2730
|
+
parseWorkflowRun(row) {
|
|
2731
|
+
let parsedSnapshot = row.snapshot;
|
|
2732
|
+
if (typeof parsedSnapshot === "string") {
|
|
2733
|
+
try {
|
|
2734
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2735
|
+
} catch (e) {
|
|
2736
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
2737
|
+
}
|
|
1744
2738
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
2739
|
+
return {
|
|
2740
|
+
workflowName: row.workflow_name,
|
|
2741
|
+
runId: row.run_id,
|
|
2742
|
+
snapshot: parsedSnapshot,
|
|
2743
|
+
createdAt: row.createdAt,
|
|
2744
|
+
updatedAt: row.updatedAt,
|
|
2745
|
+
resourceId: row.resourceId
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
async updateWorkflowResults({
|
|
2749
|
+
workflowName,
|
|
2750
|
+
runId,
|
|
2751
|
+
stepId,
|
|
2752
|
+
result,
|
|
2753
|
+
requestContext
|
|
2754
|
+
}) {
|
|
2755
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2756
|
+
const transaction = this.pool.transaction();
|
|
1748
2757
|
try {
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
2758
|
+
await transaction.begin();
|
|
2759
|
+
const selectRequest = new sql2.Request(transaction);
|
|
2760
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2761
|
+
selectRequest.input("run_id", runId);
|
|
2762
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2763
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2764
|
+
);
|
|
2765
|
+
let snapshot;
|
|
2766
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2767
|
+
snapshot = {
|
|
2768
|
+
context: {},
|
|
2769
|
+
activePaths: [],
|
|
2770
|
+
timestamp: Date.now(),
|
|
2771
|
+
suspendedPaths: {},
|
|
2772
|
+
resumeLabels: {},
|
|
2773
|
+
serializedStepGraph: [],
|
|
2774
|
+
value: {},
|
|
2775
|
+
waitingPaths: {},
|
|
2776
|
+
status: "pending",
|
|
2777
|
+
runId,
|
|
2778
|
+
requestContext: {}
|
|
2779
|
+
};
|
|
2780
|
+
} else {
|
|
2781
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2782
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2783
|
+
}
|
|
2784
|
+
snapshot.context[stepId] = result;
|
|
2785
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2786
|
+
const upsertReq = new sql2.Request(transaction);
|
|
2787
|
+
upsertReq.input("workflow_name", workflowName);
|
|
2788
|
+
upsertReq.input("run_id", runId);
|
|
2789
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
2790
|
+
upsertReq.input("createdAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2791
|
+
upsertReq.input("updatedAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2792
|
+
await upsertReq.query(
|
|
2793
|
+
`MERGE ${table} AS target
|
|
2794
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
2795
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
2796
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
2797
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
2798
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
2799
|
+
);
|
|
2800
|
+
await transaction.commit();
|
|
2801
|
+
return snapshot.context;
|
|
1759
2802
|
} catch (error) {
|
|
2803
|
+
try {
|
|
2804
|
+
await transaction.rollback();
|
|
2805
|
+
} catch {
|
|
2806
|
+
}
|
|
1760
2807
|
throw new MastraError(
|
|
1761
2808
|
{
|
|
1762
|
-
id: "
|
|
2809
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
|
|
1763
2810
|
domain: ErrorDomain.STORAGE,
|
|
1764
2811
|
category: ErrorCategory.THIRD_PARTY,
|
|
1765
2812
|
details: {
|
|
1766
|
-
|
|
1767
|
-
|
|
2813
|
+
workflowName,
|
|
2814
|
+
runId,
|
|
2815
|
+
stepId
|
|
1768
2816
|
}
|
|
1769
2817
|
},
|
|
1770
2818
|
error
|
|
1771
2819
|
);
|
|
1772
2820
|
}
|
|
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);
|
|
2821
|
+
}
|
|
2822
|
+
async updateWorkflowState({
|
|
2823
|
+
workflowName,
|
|
2824
|
+
runId,
|
|
2825
|
+
opts
|
|
2826
|
+
}) {
|
|
2827
|
+
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2828
|
+
const transaction = this.pool.transaction();
|
|
1793
2829
|
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
|
-
|
|
2830
|
+
await transaction.begin();
|
|
2831
|
+
const selectRequest = new sql2.Request(transaction);
|
|
2832
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2833
|
+
selectRequest.input("run_id", runId);
|
|
2834
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2835
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2836
|
+
);
|
|
2837
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2838
|
+
await transaction.rollback();
|
|
2839
|
+
return void 0;
|
|
2840
|
+
}
|
|
2841
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2842
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2843
|
+
if (!snapshot || !snapshot?.context) {
|
|
2844
|
+
await transaction.rollback();
|
|
2845
|
+
throw new MastraError(
|
|
2846
|
+
{
|
|
2847
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
|
|
2848
|
+
domain: ErrorDomain.STORAGE,
|
|
2849
|
+
category: ErrorCategory.SYSTEM,
|
|
2850
|
+
details: {
|
|
2851
|
+
workflowName,
|
|
2852
|
+
runId
|
|
2853
|
+
}
|
|
2854
|
+
},
|
|
2855
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
2856
|
+
);
|
|
2857
|
+
}
|
|
2858
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
2859
|
+
const updateRequest = new sql2.Request(transaction);
|
|
2860
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
2861
|
+
updateRequest.input("workflow_name", workflowName);
|
|
2862
|
+
updateRequest.input("run_id", runId);
|
|
2863
|
+
updateRequest.input("updatedAt", sql2.DateTime2, /* @__PURE__ */ new Date());
|
|
2864
|
+
await updateRequest.query(
|
|
2865
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2866
|
+
);
|
|
2867
|
+
await transaction.commit();
|
|
2868
|
+
return updatedSnapshot;
|
|
1819
2869
|
} catch (error) {
|
|
2870
|
+
try {
|
|
2871
|
+
await transaction.rollback();
|
|
2872
|
+
} catch {
|
|
2873
|
+
}
|
|
1820
2874
|
throw new MastraError(
|
|
1821
2875
|
{
|
|
1822
|
-
id: "
|
|
2876
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
|
|
1823
2877
|
domain: ErrorDomain.STORAGE,
|
|
1824
2878
|
category: ErrorCategory.THIRD_PARTY,
|
|
1825
2879
|
details: {
|
|
1826
|
-
|
|
1827
|
-
|
|
2880
|
+
workflowName,
|
|
2881
|
+
runId
|
|
1828
2882
|
}
|
|
1829
2883
|
},
|
|
1830
2884
|
error
|
|
1831
2885
|
);
|
|
1832
2886
|
}
|
|
1833
2887
|
}
|
|
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
2888
|
async persistWorkflowSnapshot({
|
|
1891
2889
|
workflowName,
|
|
1892
2890
|
runId,
|
|
2891
|
+
resourceId,
|
|
1893
2892
|
snapshot
|
|
1894
2893
|
}) {
|
|
1895
2894
|
const table = getTableName({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
@@ -1898,6 +2897,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1898
2897
|
const request = this.pool.request();
|
|
1899
2898
|
request.input("workflow_name", workflowName);
|
|
1900
2899
|
request.input("run_id", runId);
|
|
2900
|
+
request.input("resourceId", resourceId);
|
|
1901
2901
|
request.input("snapshot", JSON.stringify(snapshot));
|
|
1902
2902
|
request.input("createdAt", sql2.DateTime2, new Date(now));
|
|
1903
2903
|
request.input("updatedAt", sql2.DateTime2, new Date(now));
|
|
@@ -1905,10 +2905,11 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1905
2905
|
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
1906
2906
|
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
1907
2907
|
WHEN MATCHED THEN UPDATE SET
|
|
2908
|
+
resourceId = @resourceId,
|
|
1908
2909
|
snapshot = @snapshot,
|
|
1909
2910
|
[updatedAt] = @updatedAt
|
|
1910
|
-
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
1911
|
-
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`;
|
|
2911
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, resourceId, snapshot, [createdAt], [updatedAt])
|
|
2912
|
+
VALUES (@workflow_name, @run_id, @resourceId, @snapshot, @createdAt, @updatedAt);`;
|
|
1912
2913
|
await request.query(mergeSql);
|
|
1913
2914
|
} catch (error) {
|
|
1914
2915
|
throw new MastraError(
|
|
@@ -1980,7 +2981,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1980
2981
|
if (!result.recordset || result.recordset.length === 0) {
|
|
1981
2982
|
return null;
|
|
1982
2983
|
}
|
|
1983
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
2984
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
1984
2985
|
} catch (error) {
|
|
1985
2986
|
throw new MastraError(
|
|
1986
2987
|
{
|
|
@@ -1996,7 +2997,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
1996
2997
|
);
|
|
1997
2998
|
}
|
|
1998
2999
|
}
|
|
1999
|
-
async
|
|
3000
|
+
async listWorkflowRuns({
|
|
2000
3001
|
workflowName,
|
|
2001
3002
|
fromDate,
|
|
2002
3003
|
toDate,
|
|
@@ -2017,7 +3018,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2017
3018
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2018
3019
|
paramMap["resourceId"] = resourceId;
|
|
2019
3020
|
} else {
|
|
2020
|
-
|
|
3021
|
+
this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2021
3022
|
}
|
|
2022
3023
|
}
|
|
2023
3024
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2051,7 +3052,7 @@ var WorkflowsMSSQL = class extends WorkflowsStorage {
|
|
|
2051
3052
|
request.input("offset", offset);
|
|
2052
3053
|
}
|
|
2053
3054
|
const result = await request.query(query);
|
|
2054
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
3055
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2055
3056
|
return { runs, total: total || runs.length };
|
|
2056
3057
|
} catch (error) {
|
|
2057
3058
|
throw new MastraError(
|
|
@@ -2099,19 +3100,17 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2099
3100
|
port: config.port,
|
|
2100
3101
|
options: config.options || { encrypt: true, trustServerCertificate: true }
|
|
2101
3102
|
});
|
|
2102
|
-
const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
|
|
2103
3103
|
const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
|
|
2104
3104
|
const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2105
|
-
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2106
3105
|
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2107
3106
|
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
3107
|
+
const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2108
3108
|
this.stores = {
|
|
2109
3109
|
operations,
|
|
2110
3110
|
scores,
|
|
2111
|
-
traces,
|
|
2112
3111
|
workflows,
|
|
2113
|
-
|
|
2114
|
-
|
|
3112
|
+
memory,
|
|
3113
|
+
observability
|
|
2115
3114
|
};
|
|
2116
3115
|
} catch (e) {
|
|
2117
3116
|
throw new MastraError(
|
|
@@ -2131,6 +3130,11 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2131
3130
|
try {
|
|
2132
3131
|
await this.isConnected;
|
|
2133
3132
|
await super.init();
|
|
3133
|
+
try {
|
|
3134
|
+
await this.stores.operations.createAutomaticIndexes();
|
|
3135
|
+
} catch (indexError) {
|
|
3136
|
+
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
3137
|
+
}
|
|
2134
3138
|
} catch (error) {
|
|
2135
3139
|
this.isConnected = null;
|
|
2136
3140
|
throw new MastraError(
|
|
@@ -2157,28 +3161,12 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2157
3161
|
resourceWorkingMemory: true,
|
|
2158
3162
|
hasColumn: true,
|
|
2159
3163
|
createTable: true,
|
|
2160
|
-
deleteMessages: true
|
|
3164
|
+
deleteMessages: true,
|
|
3165
|
+
getScoresBySpan: true,
|
|
3166
|
+
aiTracing: true,
|
|
3167
|
+
indexManagement: true
|
|
2161
3168
|
};
|
|
2162
3169
|
}
|
|
2163
|
-
/** @deprecated use getEvals instead */
|
|
2164
|
-
async getEvalsByAgentName(agentName, type) {
|
|
2165
|
-
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2166
|
-
}
|
|
2167
|
-
async getEvals(options = {}) {
|
|
2168
|
-
return this.stores.legacyEvals.getEvals(options);
|
|
2169
|
-
}
|
|
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
3170
|
async createTable({
|
|
2183
3171
|
tableName,
|
|
2184
3172
|
schema
|
|
@@ -2238,12 +3226,6 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2238
3226
|
async getMessages(args) {
|
|
2239
3227
|
return this.stores.memory.getMessages(args);
|
|
2240
3228
|
}
|
|
2241
|
-
async getMessagesById({
|
|
2242
|
-
messageIds,
|
|
2243
|
-
format
|
|
2244
|
-
}) {
|
|
2245
|
-
return this.stores.memory.getMessagesById({ messageIds, format });
|
|
2246
|
-
}
|
|
2247
3229
|
async getMessagesPaginated(args) {
|
|
2248
3230
|
return this.stores.memory.getMessagesPaginated(args);
|
|
2249
3231
|
}
|
|
@@ -2279,9 +3261,9 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2279
3261
|
runId,
|
|
2280
3262
|
stepId,
|
|
2281
3263
|
result,
|
|
2282
|
-
|
|
3264
|
+
requestContext
|
|
2283
3265
|
}) {
|
|
2284
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result,
|
|
3266
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2285
3267
|
}
|
|
2286
3268
|
async updateWorkflowState({
|
|
2287
3269
|
workflowName,
|
|
@@ -2293,9 +3275,10 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2293
3275
|
async persistWorkflowSnapshot({
|
|
2294
3276
|
workflowName,
|
|
2295
3277
|
runId,
|
|
3278
|
+
resourceId,
|
|
2296
3279
|
snapshot
|
|
2297
3280
|
}) {
|
|
2298
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
3281
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2299
3282
|
}
|
|
2300
3283
|
async loadWorkflowSnapshot({
|
|
2301
3284
|
workflowName,
|
|
@@ -2303,7 +3286,7 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2303
3286
|
}) {
|
|
2304
3287
|
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2305
3288
|
}
|
|
2306
|
-
async
|
|
3289
|
+
async listWorkflowRuns({
|
|
2307
3290
|
workflowName,
|
|
2308
3291
|
fromDate,
|
|
2309
3292
|
toDate,
|
|
@@ -2311,7 +3294,7 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2311
3294
|
offset,
|
|
2312
3295
|
resourceId
|
|
2313
3296
|
} = {}) {
|
|
2314
|
-
return this.stores.workflows.
|
|
3297
|
+
return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
2315
3298
|
}
|
|
2316
3299
|
async getWorkflowRunById({
|
|
2317
3300
|
runId,
|
|
@@ -2322,6 +3305,60 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2322
3305
|
async close() {
|
|
2323
3306
|
await this.pool.close();
|
|
2324
3307
|
}
|
|
3308
|
+
/**
|
|
3309
|
+
* Index Management
|
|
3310
|
+
*/
|
|
3311
|
+
async createIndex(options) {
|
|
3312
|
+
return this.stores.operations.createIndex(options);
|
|
3313
|
+
}
|
|
3314
|
+
async listIndexes(tableName) {
|
|
3315
|
+
return this.stores.operations.listIndexes(tableName);
|
|
3316
|
+
}
|
|
3317
|
+
async describeIndex(indexName) {
|
|
3318
|
+
return this.stores.operations.describeIndex(indexName);
|
|
3319
|
+
}
|
|
3320
|
+
async dropIndex(indexName) {
|
|
3321
|
+
return this.stores.operations.dropIndex(indexName);
|
|
3322
|
+
}
|
|
3323
|
+
/**
|
|
3324
|
+
* AI Tracing / Observability
|
|
3325
|
+
*/
|
|
3326
|
+
getObservabilityStore() {
|
|
3327
|
+
if (!this.stores.observability) {
|
|
3328
|
+
throw new MastraError({
|
|
3329
|
+
id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
3330
|
+
domain: ErrorDomain.STORAGE,
|
|
3331
|
+
category: ErrorCategory.SYSTEM,
|
|
3332
|
+
text: "Observability storage is not initialized"
|
|
3333
|
+
});
|
|
3334
|
+
}
|
|
3335
|
+
return this.stores.observability;
|
|
3336
|
+
}
|
|
3337
|
+
async createAISpan(span) {
|
|
3338
|
+
return this.getObservabilityStore().createAISpan(span);
|
|
3339
|
+
}
|
|
3340
|
+
async updateAISpan({
|
|
3341
|
+
spanId,
|
|
3342
|
+
traceId,
|
|
3343
|
+
updates
|
|
3344
|
+
}) {
|
|
3345
|
+
return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
|
|
3346
|
+
}
|
|
3347
|
+
async getAITrace(traceId) {
|
|
3348
|
+
return this.getObservabilityStore().getAITrace(traceId);
|
|
3349
|
+
}
|
|
3350
|
+
async getAITracesPaginated(args) {
|
|
3351
|
+
return this.getObservabilityStore().getAITracesPaginated(args);
|
|
3352
|
+
}
|
|
3353
|
+
async batchCreateAISpans(args) {
|
|
3354
|
+
return this.getObservabilityStore().batchCreateAISpans(args);
|
|
3355
|
+
}
|
|
3356
|
+
async batchUpdateAISpans(args) {
|
|
3357
|
+
return this.getObservabilityStore().batchUpdateAISpans(args);
|
|
3358
|
+
}
|
|
3359
|
+
async batchDeleteAITraces(args) {
|
|
3360
|
+
return this.getObservabilityStore().batchDeleteAITraces(args);
|
|
3361
|
+
}
|
|
2325
3362
|
/**
|
|
2326
3363
|
* Scorers
|
|
2327
3364
|
*/
|
|
@@ -2330,9 +3367,18 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2330
3367
|
}
|
|
2331
3368
|
async getScoresByScorerId({
|
|
2332
3369
|
scorerId: _scorerId,
|
|
2333
|
-
pagination: _pagination
|
|
3370
|
+
pagination: _pagination,
|
|
3371
|
+
entityId: _entityId,
|
|
3372
|
+
entityType: _entityType,
|
|
3373
|
+
source: _source
|
|
2334
3374
|
}) {
|
|
2335
|
-
return this.stores.scores.getScoresByScorerId({
|
|
3375
|
+
return this.stores.scores.getScoresByScorerId({
|
|
3376
|
+
scorerId: _scorerId,
|
|
3377
|
+
pagination: _pagination,
|
|
3378
|
+
entityId: _entityId,
|
|
3379
|
+
entityType: _entityType,
|
|
3380
|
+
source: _source
|
|
3381
|
+
});
|
|
2336
3382
|
}
|
|
2337
3383
|
async saveScore(_score) {
|
|
2338
3384
|
return this.stores.scores.saveScore(_score);
|
|
@@ -2354,6 +3400,13 @@ var MSSQLStore = class extends MastraStorage {
|
|
|
2354
3400
|
pagination: _pagination
|
|
2355
3401
|
});
|
|
2356
3402
|
}
|
|
3403
|
+
async getScoresBySpan({
|
|
3404
|
+
traceId,
|
|
3405
|
+
spanId,
|
|
3406
|
+
pagination: _pagination
|
|
3407
|
+
}) {
|
|
3408
|
+
return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination: _pagination });
|
|
3409
|
+
}
|
|
2357
3410
|
};
|
|
2358
3411
|
|
|
2359
3412
|
export { MSSQLStore };
|