@mastra/mssql 0.0.0-rag-chunk-extract-llm-option-20250926183645 → 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 +128 -3
- package/README.md +315 -36
- package/dist/index.cjs +1541 -568
- 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 +1555 -582
- 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 +3 -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 +6 -11
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +46 -40
- 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.cjs
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
var error = require('@mastra/core/error');
|
|
4
4
|
var storage = require('@mastra/core/storage');
|
|
5
5
|
var sql2 = require('mssql');
|
|
6
|
-
var utils = require('@mastra/core/utils');
|
|
7
6
|
var agent = require('@mastra/core/agent');
|
|
7
|
+
var utils = require('@mastra/core/utils');
|
|
8
|
+
var crypto = require('crypto');
|
|
8
9
|
var scores = require('@mastra/core/scores');
|
|
9
10
|
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -21,154 +22,71 @@ function getTableName({ indexName, schemaName }) {
|
|
|
21
22
|
const quotedSchemaName = schemaName;
|
|
22
23
|
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (row.test_info) {
|
|
29
|
-
try {
|
|
30
|
-
testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
|
|
31
|
-
} catch {
|
|
32
|
-
}
|
|
25
|
+
function buildDateRangeFilter(dateRange, fieldName) {
|
|
26
|
+
const filters = {};
|
|
27
|
+
if (dateRange?.start) {
|
|
28
|
+
filters[`${fieldName}_gte`] = dateRange.start;
|
|
33
29
|
}
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
resultValue = typeof row.result === "string" ? JSON.parse(row.result) : row.result;
|
|
37
|
-
} catch {
|
|
38
|
-
}
|
|
30
|
+
if (dateRange?.end) {
|
|
31
|
+
filters[`${fieldName}_lte`] = dateRange.end;
|
|
39
32
|
}
|
|
33
|
+
return filters;
|
|
34
|
+
}
|
|
35
|
+
function prepareWhereClause(filters, _schema) {
|
|
36
|
+
const conditions = [];
|
|
37
|
+
const params = {};
|
|
38
|
+
let paramIndex = 1;
|
|
39
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
40
|
+
if (value === void 0) return;
|
|
41
|
+
const paramName = `p${paramIndex++}`;
|
|
42
|
+
if (key.endsWith("_gte")) {
|
|
43
|
+
const fieldName = key.slice(0, -4);
|
|
44
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] >= @${paramName}`);
|
|
45
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
46
|
+
} else if (key.endsWith("_lte")) {
|
|
47
|
+
const fieldName = key.slice(0, -4);
|
|
48
|
+
conditions.push(`[${utils.parseSqlIdentifier(fieldName, "field name")}] <= @${paramName}`);
|
|
49
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
50
|
+
} else if (value === null) {
|
|
51
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] IS NULL`);
|
|
52
|
+
} else {
|
|
53
|
+
conditions.push(`[${utils.parseSqlIdentifier(key, "field name")}] = @${paramName}`);
|
|
54
|
+
params[paramName] = value instanceof Date ? value.toISOString() : value;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
40
57
|
return {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
output: row.output,
|
|
44
|
-
result: resultValue,
|
|
45
|
-
metricName: row.metric_name,
|
|
46
|
-
instructions: row.instructions,
|
|
47
|
-
testInfo: testInfoValue,
|
|
48
|
-
globalRunId: row.global_run_id,
|
|
49
|
-
runId: row.run_id,
|
|
50
|
-
createdAt: row.created_at
|
|
58
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
59
|
+
params
|
|
51
60
|
};
|
|
52
61
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
query += " AND test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL";
|
|
67
|
-
} else if (type === "live") {
|
|
68
|
-
query += " AND (test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)";
|
|
69
|
-
}
|
|
70
|
-
query += " ORDER BY created_at DESC";
|
|
71
|
-
const request = this.pool.request();
|
|
72
|
-
request.input("p1", agentName);
|
|
73
|
-
const result = await request.query(query);
|
|
74
|
-
const rows = result.recordset;
|
|
75
|
-
return typeof transformEvalRow === "function" ? rows?.map((row) => transformEvalRow(row)) ?? [] : rows ?? [];
|
|
76
|
-
} catch (error) {
|
|
77
|
-
if (error && error.number === 208 && error.message && error.message.includes("Invalid object name")) {
|
|
78
|
-
return [];
|
|
79
|
-
}
|
|
80
|
-
console.error("Failed to get evals for the specified agent: " + error?.message);
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async getEvals(options = {}) {
|
|
85
|
-
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
86
|
-
const fromDate = dateRange?.start;
|
|
87
|
-
const toDate = dateRange?.end;
|
|
88
|
-
const where = [];
|
|
89
|
-
const params = {};
|
|
90
|
-
if (agentName) {
|
|
91
|
-
where.push("agent_name = @agentName");
|
|
92
|
-
params["agentName"] = agentName;
|
|
93
|
-
}
|
|
94
|
-
if (type === "test") {
|
|
95
|
-
where.push("test_info IS NOT NULL AND JSON_VALUE(test_info, '$.testPath') IS NOT NULL");
|
|
96
|
-
} else if (type === "live") {
|
|
97
|
-
where.push("(test_info IS NULL OR JSON_VALUE(test_info, '$.testPath') IS NULL)");
|
|
98
|
-
}
|
|
99
|
-
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
100
|
-
where.push(`[created_at] >= @fromDate`);
|
|
101
|
-
params[`fromDate`] = fromDate.toISOString();
|
|
102
|
-
}
|
|
103
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
104
|
-
where.push(`[created_at] <= @toDate`);
|
|
105
|
-
params[`toDate`] = toDate.toISOString();
|
|
106
|
-
}
|
|
107
|
-
const whereClause = where.length > 0 ? `WHERE ${where.join(" AND ")}` : "";
|
|
108
|
-
const tableName = getTableName({ indexName: storage.TABLE_EVALS, schemaName: getSchemaName(this.schema) });
|
|
109
|
-
const offset = page * perPage;
|
|
110
|
-
const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
|
|
111
|
-
const dataQuery = `SELECT * FROM ${tableName} ${whereClause} ORDER BY seq_id DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
112
|
-
try {
|
|
113
|
-
const countReq = this.pool.request();
|
|
114
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
115
|
-
if (value instanceof Date) {
|
|
116
|
-
countReq.input(key, sql2__default.default.DateTime, value);
|
|
117
|
-
} else {
|
|
118
|
-
countReq.input(key, value);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
const countResult = await countReq.query(countQuery);
|
|
122
|
-
const total = countResult.recordset[0]?.total || 0;
|
|
123
|
-
if (total === 0) {
|
|
124
|
-
return {
|
|
125
|
-
evals: [],
|
|
126
|
-
total: 0,
|
|
127
|
-
page,
|
|
128
|
-
perPage,
|
|
129
|
-
hasMore: false
|
|
130
|
-
};
|
|
62
|
+
function transformFromSqlRow({
|
|
63
|
+
tableName,
|
|
64
|
+
sqlRow
|
|
65
|
+
}) {
|
|
66
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
67
|
+
const result = {};
|
|
68
|
+
Object.entries(sqlRow).forEach(([key, value]) => {
|
|
69
|
+
const columnSchema = schema?.[key];
|
|
70
|
+
if (columnSchema?.type === "jsonb" && typeof value === "string") {
|
|
71
|
+
try {
|
|
72
|
+
result[key] = JSON.parse(value);
|
|
73
|
+
} catch {
|
|
74
|
+
result[key] = value;
|
|
131
75
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
req.input("offset", offset);
|
|
141
|
-
req.input("perPage", perPage);
|
|
142
|
-
const result = await req.query(dataQuery);
|
|
143
|
-
const rows = result.recordset;
|
|
144
|
-
return {
|
|
145
|
-
evals: rows?.map((row) => transformEvalRow(row)) ?? [],
|
|
146
|
-
total,
|
|
147
|
-
page,
|
|
148
|
-
perPage,
|
|
149
|
-
hasMore: offset + (rows?.length ?? 0) < total
|
|
150
|
-
};
|
|
151
|
-
} catch (error$1) {
|
|
152
|
-
const mastraError = new error.MastraError(
|
|
153
|
-
{
|
|
154
|
-
id: "MASTRA_STORAGE_MSSQL_STORE_GET_EVALS_FAILED",
|
|
155
|
-
domain: error.ErrorDomain.STORAGE,
|
|
156
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
157
|
-
details: {
|
|
158
|
-
agentName: agentName || "all",
|
|
159
|
-
type: type || "all",
|
|
160
|
-
page,
|
|
161
|
-
perPage
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
error$1
|
|
165
|
-
);
|
|
166
|
-
this.logger?.error?.(mastraError.toString());
|
|
167
|
-
this.logger?.trackException(mastraError);
|
|
168
|
-
throw mastraError;
|
|
76
|
+
} else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
|
|
77
|
+
result[key] = new Date(value);
|
|
78
|
+
} else if (columnSchema?.type === "timestamp" && value instanceof Date) {
|
|
79
|
+
result[key] = value;
|
|
80
|
+
} else if (columnSchema?.type === "boolean") {
|
|
81
|
+
result[key] = Boolean(value);
|
|
82
|
+
} else {
|
|
83
|
+
result[key] = value;
|
|
169
84
|
}
|
|
170
|
-
}
|
|
171
|
-
|
|
85
|
+
});
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/storage/domains/memory/index.ts
|
|
172
90
|
var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
173
91
|
pool;
|
|
174
92
|
schema;
|
|
@@ -200,7 +118,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
200
118
|
}
|
|
201
119
|
async getThreadById({ threadId }) {
|
|
202
120
|
try {
|
|
203
|
-
const
|
|
121
|
+
const sql5 = `SELECT
|
|
204
122
|
id,
|
|
205
123
|
[resourceId],
|
|
206
124
|
title,
|
|
@@ -211,7 +129,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
211
129
|
WHERE id = @threadId`;
|
|
212
130
|
const request = this.pool.request();
|
|
213
131
|
request.input("threadId", threadId);
|
|
214
|
-
const resultSet = await request.query(
|
|
132
|
+
const resultSet = await request.query(sql5);
|
|
215
133
|
const thread = resultSet.recordset[0] || null;
|
|
216
134
|
if (!thread) {
|
|
217
135
|
return null;
|
|
@@ -257,7 +175,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
257
175
|
};
|
|
258
176
|
}
|
|
259
177
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
260
|
-
const
|
|
178
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
179
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir} OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
261
180
|
const dataRequest = this.pool.request();
|
|
262
181
|
dataRequest.input("resourceId", resourceId);
|
|
263
182
|
dataRequest.input("perPage", perPage);
|
|
@@ -314,7 +233,12 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
314
233
|
req.input("id", thread.id);
|
|
315
234
|
req.input("resourceId", thread.resourceId);
|
|
316
235
|
req.input("title", thread.title);
|
|
317
|
-
|
|
236
|
+
const metadata = thread.metadata ? JSON.stringify(thread.metadata) : null;
|
|
237
|
+
if (metadata === null) {
|
|
238
|
+
req.input("metadata", sql2__default.default.NVarChar, null);
|
|
239
|
+
} else {
|
|
240
|
+
req.input("metadata", metadata);
|
|
241
|
+
}
|
|
318
242
|
req.input("createdAt", sql2__default.default.DateTime2, thread.createdAt);
|
|
319
243
|
req.input("updatedAt", sql2__default.default.DateTime2, thread.updatedAt);
|
|
320
244
|
await req.query(mergeSql);
|
|
@@ -341,7 +265,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
341
265
|
try {
|
|
342
266
|
const baseQuery = `FROM ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} WHERE [resourceId] = @resourceId`;
|
|
343
267
|
const orderByField = orderBy === "createdAt" ? "[createdAt]" : "[updatedAt]";
|
|
344
|
-
const
|
|
268
|
+
const dir = (sortDirection || "DESC").toUpperCase() === "ASC" ? "ASC" : "DESC";
|
|
269
|
+
const dataQuery = `SELECT id, [resourceId], title, metadata, [createdAt], [updatedAt] ${baseQuery} ORDER BY ${orderByField} ${dir}`;
|
|
345
270
|
const request = this.pool.request();
|
|
346
271
|
request.input("resourceId", resourceId);
|
|
347
272
|
const resultSet = await request.query(dataQuery);
|
|
@@ -384,7 +309,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
384
309
|
};
|
|
385
310
|
try {
|
|
386
311
|
const table = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
387
|
-
const
|
|
312
|
+
const sql5 = `UPDATE ${table}
|
|
388
313
|
SET title = @title,
|
|
389
314
|
metadata = @metadata,
|
|
390
315
|
[updatedAt] = @updatedAt
|
|
@@ -395,7 +320,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
395
320
|
req.input("title", title);
|
|
396
321
|
req.input("metadata", JSON.stringify(mergedMetadata));
|
|
397
322
|
req.input("updatedAt", /* @__PURE__ */ new Date());
|
|
398
|
-
const result = await req.query(
|
|
323
|
+
const result = await req.query(sql5);
|
|
399
324
|
let thread = result.recordset && result.recordset[0];
|
|
400
325
|
if (thread && "seq_id" in thread) {
|
|
401
326
|
const { seq_id, ...rest } = thread;
|
|
@@ -465,8 +390,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
465
390
|
}
|
|
466
391
|
async _getIncludedMessages({
|
|
467
392
|
threadId,
|
|
468
|
-
selectBy
|
|
469
|
-
orderByStatement
|
|
393
|
+
selectBy
|
|
470
394
|
}) {
|
|
471
395
|
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
472
396
|
const include = selectBy?.include;
|
|
@@ -494,7 +418,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
494
418
|
m.[resourceId],
|
|
495
419
|
m.seq_id
|
|
496
420
|
FROM (
|
|
497
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
421
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
498
422
|
FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
499
423
|
WHERE [thread_id] = ${pThreadId}
|
|
500
424
|
) AS m
|
|
@@ -502,15 +426,17 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
502
426
|
OR EXISTS (
|
|
503
427
|
SELECT 1
|
|
504
428
|
FROM (
|
|
505
|
-
SELECT *, ROW_NUMBER() OVER (
|
|
429
|
+
SELECT *, ROW_NUMBER() OVER (ORDER BY [createdAt] ASC) as row_num
|
|
506
430
|
FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })}
|
|
507
431
|
WHERE [thread_id] = ${pThreadId}
|
|
508
432
|
) AS target
|
|
509
433
|
WHERE target.id = ${pId}
|
|
510
434
|
AND (
|
|
511
|
-
|
|
435
|
+
-- Get previous messages (messages that come BEFORE the target)
|
|
436
|
+
(m.row_num < target.row_num AND m.row_num >= target.row_num - ${pPrev})
|
|
512
437
|
OR
|
|
513
|
-
|
|
438
|
+
-- Get next messages (messages that come AFTER the target)
|
|
439
|
+
(m.row_num > target.row_num AND m.row_num <= target.row_num + ${pNext})
|
|
514
440
|
)
|
|
515
441
|
)
|
|
516
442
|
`
|
|
@@ -549,7 +475,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
549
475
|
let rows = [];
|
|
550
476
|
const include = selectBy?.include || [];
|
|
551
477
|
if (include?.length) {
|
|
552
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy
|
|
478
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
553
479
|
if (includeMessages) {
|
|
554
480
|
rows.push(...includeMessages);
|
|
555
481
|
}
|
|
@@ -590,14 +516,11 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
590
516
|
error$1
|
|
591
517
|
);
|
|
592
518
|
this.logger?.error?.(mastraError.toString());
|
|
593
|
-
this.logger?.trackException(mastraError);
|
|
519
|
+
this.logger?.trackException?.(mastraError);
|
|
594
520
|
return [];
|
|
595
521
|
}
|
|
596
522
|
}
|
|
597
|
-
async
|
|
598
|
-
messageIds,
|
|
599
|
-
format
|
|
600
|
-
}) {
|
|
523
|
+
async listMessagesById({ messageIds }) {
|
|
601
524
|
if (messageIds.length === 0) return [];
|
|
602
525
|
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
603
526
|
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
@@ -615,8 +538,8 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
615
538
|
return timeDiff;
|
|
616
539
|
});
|
|
617
540
|
rows = rows.map(({ seq_id, ...rest }) => rest);
|
|
618
|
-
|
|
619
|
-
return
|
|
541
|
+
const messages = this._parseAndFormatMessages(rows, `v2`);
|
|
542
|
+
return messages;
|
|
620
543
|
} catch (error$1) {
|
|
621
544
|
const mastraError = new error.MastraError(
|
|
622
545
|
{
|
|
@@ -630,10 +553,139 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
630
553
|
error$1
|
|
631
554
|
);
|
|
632
555
|
this.logger?.error?.(mastraError.toString());
|
|
633
|
-
this.logger?.trackException(mastraError);
|
|
556
|
+
this.logger?.trackException?.(mastraError);
|
|
634
557
|
return [];
|
|
635
558
|
}
|
|
636
559
|
}
|
|
560
|
+
async listMessages(args) {
|
|
561
|
+
const { threadId, resourceId, include, filter, limit, offset = 0, orderBy } = args;
|
|
562
|
+
if (!threadId.trim()) {
|
|
563
|
+
throw new error.MastraError(
|
|
564
|
+
{
|
|
565
|
+
id: "STORAGE_MSSQL_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
566
|
+
domain: error.ErrorDomain.STORAGE,
|
|
567
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
568
|
+
details: { threadId }
|
|
569
|
+
},
|
|
570
|
+
new Error("threadId must be a non-empty string")
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
try {
|
|
574
|
+
let perPage = 40;
|
|
575
|
+
if (limit !== void 0) {
|
|
576
|
+
if (limit === false) {
|
|
577
|
+
perPage = Number.MAX_SAFE_INTEGER;
|
|
578
|
+
} else if (limit === 0) {
|
|
579
|
+
perPage = 0;
|
|
580
|
+
} else if (typeof limit === "number" && limit > 0) {
|
|
581
|
+
perPage = limit;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
const page = perPage === 0 ? 0 : Math.floor(offset / perPage);
|
|
585
|
+
const sortField = orderBy?.field || "createdAt";
|
|
586
|
+
const sortDirection = orderBy?.direction || "DESC";
|
|
587
|
+
const orderByStatement = `ORDER BY [${sortField}] ${sortDirection}`;
|
|
588
|
+
const selectStatement = `SELECT seq_id, id, content, role, type, [createdAt], thread_id AS threadId, resourceId`;
|
|
589
|
+
const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
590
|
+
const conditions = ["[thread_id] = @threadId"];
|
|
591
|
+
const request = this.pool.request();
|
|
592
|
+
request.input("threadId", threadId);
|
|
593
|
+
if (resourceId) {
|
|
594
|
+
conditions.push("[resourceId] = @resourceId");
|
|
595
|
+
request.input("resourceId", resourceId);
|
|
596
|
+
}
|
|
597
|
+
if (filter?.dateRange?.start) {
|
|
598
|
+
conditions.push("[createdAt] >= @fromDate");
|
|
599
|
+
request.input("fromDate", filter.dateRange.start);
|
|
600
|
+
}
|
|
601
|
+
if (filter?.dateRange?.end) {
|
|
602
|
+
conditions.push("[createdAt] <= @toDate");
|
|
603
|
+
request.input("toDate", filter.dateRange.end);
|
|
604
|
+
}
|
|
605
|
+
const whereClause = `WHERE ${conditions.join(" AND ")}`;
|
|
606
|
+
const countQuery = `SELECT COUNT(*) as total FROM ${tableName} ${whereClause}`;
|
|
607
|
+
const countResult = await request.query(countQuery);
|
|
608
|
+
const total = parseInt(countResult.recordset[0]?.total, 10) || 0;
|
|
609
|
+
const dataQuery = `${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
610
|
+
request.input("offset", offset);
|
|
611
|
+
if (perPage > 2147483647) {
|
|
612
|
+
request.input("limit", sql2__default.default.BigInt, perPage);
|
|
613
|
+
} else {
|
|
614
|
+
request.input("limit", perPage);
|
|
615
|
+
}
|
|
616
|
+
const rowsResult = await request.query(dataQuery);
|
|
617
|
+
const rows = rowsResult.recordset || [];
|
|
618
|
+
const messages = [...rows];
|
|
619
|
+
if (total === 0 && messages.length === 0) {
|
|
620
|
+
return {
|
|
621
|
+
messages: [],
|
|
622
|
+
total: 0,
|
|
623
|
+
page,
|
|
624
|
+
perPage,
|
|
625
|
+
hasMore: false
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
629
|
+
if (include && include.length > 0) {
|
|
630
|
+
const selectBy = { include };
|
|
631
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
632
|
+
if (includeMessages) {
|
|
633
|
+
for (const includeMsg of includeMessages) {
|
|
634
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
635
|
+
messages.push(includeMsg);
|
|
636
|
+
messageIds.add(includeMsg.id);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
const parsed = this._parseAndFormatMessages(messages, "v2");
|
|
642
|
+
let finalMessages = parsed;
|
|
643
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
644
|
+
const aValue = sortField === "createdAt" ? new Date(a.createdAt).getTime() : a[sortField];
|
|
645
|
+
const bValue = sortField === "createdAt" ? new Date(b.createdAt).getTime() : b[sortField];
|
|
646
|
+
return sortDirection === "ASC" ? aValue - bValue : bValue - aValue;
|
|
647
|
+
});
|
|
648
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
649
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
650
|
+
const hasMore = limit === false ? false : allThreadMessagesReturned ? false : offset + rows.length < total;
|
|
651
|
+
return {
|
|
652
|
+
messages: finalMessages,
|
|
653
|
+
total,
|
|
654
|
+
page,
|
|
655
|
+
perPage,
|
|
656
|
+
hasMore
|
|
657
|
+
};
|
|
658
|
+
} catch (error$1) {
|
|
659
|
+
const errorPerPage = limit === false ? Number.MAX_SAFE_INTEGER : limit === 0 ? 0 : limit || 40;
|
|
660
|
+
const mastraError = new error.MastraError(
|
|
661
|
+
{
|
|
662
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LIST_MESSAGES_FAILED",
|
|
663
|
+
domain: error.ErrorDomain.STORAGE,
|
|
664
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
665
|
+
details: {
|
|
666
|
+
threadId,
|
|
667
|
+
resourceId: resourceId ?? ""
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
error$1
|
|
671
|
+
);
|
|
672
|
+
this.logger?.error?.(mastraError.toString());
|
|
673
|
+
this.logger?.trackException?.(mastraError);
|
|
674
|
+
return {
|
|
675
|
+
messages: [],
|
|
676
|
+
total: 0,
|
|
677
|
+
page: errorPerPage === 0 ? 0 : Math.floor(offset / errorPerPage),
|
|
678
|
+
perPage: errorPerPage,
|
|
679
|
+
hasMore: false
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
async listThreadsByResourceId(args) {
|
|
684
|
+
const { resourceId, limit, offset, orderBy, sortDirection } = args;
|
|
685
|
+
const page = Math.floor(offset / limit);
|
|
686
|
+
const perPage = limit;
|
|
687
|
+
return this.getThreadsByResourceIdPaginated({ resourceId, page, perPage, orderBy, sortDirection });
|
|
688
|
+
}
|
|
637
689
|
async getMessagesPaginated(args) {
|
|
638
690
|
const { threadId, resourceId, format, selectBy } = args;
|
|
639
691
|
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
@@ -645,7 +697,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
645
697
|
const orderByStatement = `ORDER BY [seq_id] DESC`;
|
|
646
698
|
let messages = [];
|
|
647
699
|
if (selectBy?.include?.length) {
|
|
648
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy
|
|
700
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
649
701
|
if (includeMessages) messages.push(...includeMessages);
|
|
650
702
|
}
|
|
651
703
|
const perPage = perPageInput !== void 0 ? perPageInput : storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
@@ -692,7 +744,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
692
744
|
const parsed = this._parseAndFormatMessages(messages, format);
|
|
693
745
|
return {
|
|
694
746
|
messages: parsed,
|
|
695
|
-
total
|
|
747
|
+
total,
|
|
696
748
|
page,
|
|
697
749
|
perPage,
|
|
698
750
|
hasMore: currentOffset + rows.length < total
|
|
@@ -712,7 +764,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
712
764
|
error$1
|
|
713
765
|
);
|
|
714
766
|
this.logger?.error?.(mastraError.toString());
|
|
715
|
-
this.logger?.trackException(mastraError);
|
|
767
|
+
this.logger?.trackException?.(mastraError);
|
|
716
768
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
717
769
|
}
|
|
718
770
|
}
|
|
@@ -979,8 +1031,10 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
979
1031
|
return null;
|
|
980
1032
|
}
|
|
981
1033
|
return {
|
|
982
|
-
|
|
983
|
-
|
|
1034
|
+
id: result.id,
|
|
1035
|
+
createdAt: result.createdAt,
|
|
1036
|
+
updatedAt: result.updatedAt,
|
|
1037
|
+
workingMemory: result.workingMemory,
|
|
984
1038
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
985
1039
|
};
|
|
986
1040
|
} catch (error$1) {
|
|
@@ -994,7 +1048,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
994
1048
|
error$1
|
|
995
1049
|
);
|
|
996
1050
|
this.logger?.error?.(mastraError.toString());
|
|
997
|
-
this.logger?.trackException(mastraError);
|
|
1051
|
+
this.logger?.trackException?.(mastraError);
|
|
998
1052
|
throw mastraError;
|
|
999
1053
|
}
|
|
1000
1054
|
}
|
|
@@ -1003,7 +1057,7 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1003
1057
|
tableName: storage.TABLE_RESOURCES,
|
|
1004
1058
|
record: {
|
|
1005
1059
|
...resource,
|
|
1006
|
-
metadata:
|
|
1060
|
+
metadata: resource.metadata
|
|
1007
1061
|
}
|
|
1008
1062
|
});
|
|
1009
1063
|
return resource;
|
|
@@ -1061,132 +1115,457 @@ var MemoryMSSQL = class extends storage.MemoryStorage {
|
|
|
1061
1115
|
error$1
|
|
1062
1116
|
);
|
|
1063
1117
|
this.logger?.error?.(mastraError.toString());
|
|
1064
|
-
this.logger?.trackException(mastraError);
|
|
1118
|
+
this.logger?.trackException?.(mastraError);
|
|
1065
1119
|
throw mastraError;
|
|
1066
1120
|
}
|
|
1067
1121
|
}
|
|
1068
1122
|
};
|
|
1069
|
-
var
|
|
1123
|
+
var ObservabilityMSSQL = class extends storage.ObservabilityStorage {
|
|
1070
1124
|
pool;
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
case "timestamp":
|
|
1079
|
-
return "DATETIME2(7)";
|
|
1080
|
-
case "uuid":
|
|
1081
|
-
return "UNIQUEIDENTIFIER";
|
|
1082
|
-
case "jsonb":
|
|
1083
|
-
return "NVARCHAR(MAX)";
|
|
1084
|
-
case "integer":
|
|
1085
|
-
return "INT";
|
|
1086
|
-
case "bigint":
|
|
1087
|
-
return "BIGINT";
|
|
1088
|
-
case "float":
|
|
1089
|
-
return "FLOAT";
|
|
1090
|
-
default:
|
|
1091
|
-
throw new error.MastraError({
|
|
1092
|
-
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1093
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1094
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
constructor({ pool, schemaName }) {
|
|
1125
|
+
operations;
|
|
1126
|
+
schema;
|
|
1127
|
+
constructor({
|
|
1128
|
+
pool,
|
|
1129
|
+
operations,
|
|
1130
|
+
schema
|
|
1131
|
+
}) {
|
|
1099
1132
|
super();
|
|
1100
1133
|
this.pool = pool;
|
|
1101
|
-
this.
|
|
1134
|
+
this.operations = operations;
|
|
1135
|
+
this.schema = schema;
|
|
1102
1136
|
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
request.input("column", column);
|
|
1109
|
-
request.input("columnLower", column.toLowerCase());
|
|
1110
|
-
const result = await request.query(
|
|
1111
|
-
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1112
|
-
);
|
|
1113
|
-
return result.recordset.length > 0;
|
|
1137
|
+
get aiTracingStrategy() {
|
|
1138
|
+
return {
|
|
1139
|
+
preferred: "batch-with-updates",
|
|
1140
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
1141
|
+
};
|
|
1114
1142
|
}
|
|
1115
|
-
async
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
}
|
|
1143
|
+
async createAISpan(span) {
|
|
1144
|
+
try {
|
|
1145
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
1146
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
1147
|
+
const record = {
|
|
1148
|
+
...span,
|
|
1149
|
+
startedAt,
|
|
1150
|
+
endedAt
|
|
1151
|
+
// Note: createdAt/updatedAt will be set by default values
|
|
1152
|
+
};
|
|
1153
|
+
return this.operations.insert({ tableName: storage.TABLE_AI_SPANS, record });
|
|
1154
|
+
} catch (error$1) {
|
|
1155
|
+
throw new error.MastraError(
|
|
1156
|
+
{
|
|
1157
|
+
id: "MSSQL_STORE_CREATE_AI_SPAN_FAILED",
|
|
1158
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1159
|
+
category: error.ErrorCategory.USER,
|
|
1160
|
+
details: {
|
|
1161
|
+
spanId: span.spanId,
|
|
1162
|
+
traceId: span.traceId,
|
|
1163
|
+
spanType: span.spanType,
|
|
1164
|
+
spanName: span.name
|
|
1138
1165
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
this.schemaSetupComplete = void 0;
|
|
1143
|
-
this.setupSchemaPromise = null;
|
|
1144
|
-
throw error;
|
|
1145
|
-
} finally {
|
|
1146
|
-
this.setupSchemaPromise = null;
|
|
1147
|
-
}
|
|
1148
|
-
})();
|
|
1166
|
+
},
|
|
1167
|
+
error$1
|
|
1168
|
+
);
|
|
1149
1169
|
}
|
|
1150
|
-
await this.setupSchemaPromise;
|
|
1151
1170
|
}
|
|
1152
|
-
async
|
|
1171
|
+
async getAITrace(traceId) {
|
|
1153
1172
|
try {
|
|
1154
|
-
const
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${columns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1158
|
-
const request = this.pool.request();
|
|
1159
|
-
values.forEach((value, i) => {
|
|
1160
|
-
if (value instanceof Date) {
|
|
1161
|
-
request.input(`param${i}`, sql2__default.default.DateTime2, value);
|
|
1162
|
-
} else if (typeof value === "object" && value !== null) {
|
|
1163
|
-
request.input(`param${i}`, JSON.stringify(value));
|
|
1164
|
-
} else {
|
|
1165
|
-
request.input(`param${i}`, value);
|
|
1166
|
-
}
|
|
1173
|
+
const tableName = getTableName({
|
|
1174
|
+
indexName: storage.TABLE_AI_SPANS,
|
|
1175
|
+
schemaName: getSchemaName(this.schema)
|
|
1167
1176
|
});
|
|
1168
|
-
|
|
1177
|
+
const request = this.pool.request();
|
|
1178
|
+
request.input("traceId", traceId);
|
|
1179
|
+
const result = await request.query(
|
|
1180
|
+
`SELECT
|
|
1181
|
+
[traceId], [spanId], [parentSpanId], [name], [scope], [spanType],
|
|
1182
|
+
[attributes], [metadata], [links], [input], [output], [error], [isEvent],
|
|
1183
|
+
[startedAt], [endedAt], [createdAt], [updatedAt]
|
|
1184
|
+
FROM ${tableName}
|
|
1185
|
+
WHERE [traceId] = @traceId
|
|
1186
|
+
ORDER BY [startedAt] DESC`
|
|
1187
|
+
);
|
|
1188
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
return {
|
|
1192
|
+
traceId,
|
|
1193
|
+
spans: result.recordset.map(
|
|
1194
|
+
(span) => transformFromSqlRow({
|
|
1195
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1196
|
+
sqlRow: span
|
|
1197
|
+
})
|
|
1198
|
+
)
|
|
1199
|
+
};
|
|
1169
1200
|
} catch (error$1) {
|
|
1170
1201
|
throw new error.MastraError(
|
|
1171
1202
|
{
|
|
1172
|
-
id: "
|
|
1203
|
+
id: "MSSQL_STORE_GET_AI_TRACE_FAILED",
|
|
1173
1204
|
domain: error.ErrorDomain.STORAGE,
|
|
1174
|
-
category: error.ErrorCategory.
|
|
1205
|
+
category: error.ErrorCategory.USER,
|
|
1175
1206
|
details: {
|
|
1176
|
-
|
|
1207
|
+
traceId
|
|
1177
1208
|
}
|
|
1178
1209
|
},
|
|
1179
1210
|
error$1
|
|
1180
1211
|
);
|
|
1181
1212
|
}
|
|
1182
1213
|
}
|
|
1183
|
-
async
|
|
1184
|
-
|
|
1214
|
+
async updateAISpan({
|
|
1215
|
+
spanId,
|
|
1216
|
+
traceId,
|
|
1217
|
+
updates
|
|
1218
|
+
}) {
|
|
1219
|
+
try {
|
|
1220
|
+
const data = { ...updates };
|
|
1221
|
+
if (data.endedAt instanceof Date) {
|
|
1222
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1223
|
+
}
|
|
1224
|
+
if (data.startedAt instanceof Date) {
|
|
1225
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1226
|
+
}
|
|
1227
|
+
await this.operations.update({
|
|
1228
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1229
|
+
keys: { spanId, traceId },
|
|
1230
|
+
data
|
|
1231
|
+
});
|
|
1232
|
+
} catch (error$1) {
|
|
1233
|
+
throw new error.MastraError(
|
|
1234
|
+
{
|
|
1235
|
+
id: "MSSQL_STORE_UPDATE_AI_SPAN_FAILED",
|
|
1236
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1237
|
+
category: error.ErrorCategory.USER,
|
|
1238
|
+
details: {
|
|
1239
|
+
spanId,
|
|
1240
|
+
traceId
|
|
1241
|
+
}
|
|
1242
|
+
},
|
|
1243
|
+
error$1
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
async getAITracesPaginated({
|
|
1248
|
+
filters,
|
|
1249
|
+
pagination
|
|
1250
|
+
}) {
|
|
1251
|
+
const page = pagination?.page ?? 0;
|
|
1252
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1253
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1254
|
+
const filtersWithDateRange = {
|
|
1255
|
+
...actualFilters,
|
|
1256
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
1257
|
+
parentSpanId: null
|
|
1258
|
+
// Only get root spans for traces
|
|
1259
|
+
};
|
|
1260
|
+
const whereClause = prepareWhereClause(filtersWithDateRange);
|
|
1261
|
+
let actualWhereClause = whereClause.sql;
|
|
1262
|
+
const params = { ...whereClause.params };
|
|
1263
|
+
let currentParamIndex = Object.keys(params).length + 1;
|
|
1264
|
+
if (entityId && entityType) {
|
|
1265
|
+
let name = "";
|
|
1266
|
+
if (entityType === "workflow") {
|
|
1267
|
+
name = `workflow run: '${entityId}'`;
|
|
1268
|
+
} else if (entityType === "agent") {
|
|
1269
|
+
name = `agent run: '${entityId}'`;
|
|
1270
|
+
} else {
|
|
1271
|
+
const error$1 = new error.MastraError({
|
|
1272
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1273
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1274
|
+
category: error.ErrorCategory.USER,
|
|
1275
|
+
details: {
|
|
1276
|
+
entityType
|
|
1277
|
+
},
|
|
1278
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1279
|
+
});
|
|
1280
|
+
throw error$1;
|
|
1281
|
+
}
|
|
1282
|
+
const entityParam = `p${currentParamIndex++}`;
|
|
1283
|
+
if (actualWhereClause) {
|
|
1284
|
+
actualWhereClause += ` AND [name] = @${entityParam}`;
|
|
1285
|
+
} else {
|
|
1286
|
+
actualWhereClause = ` WHERE [name] = @${entityParam}`;
|
|
1287
|
+
}
|
|
1288
|
+
params[entityParam] = name;
|
|
1289
|
+
}
|
|
1290
|
+
const tableName = getTableName({
|
|
1291
|
+
indexName: storage.TABLE_AI_SPANS,
|
|
1292
|
+
schemaName: getSchemaName(this.schema)
|
|
1293
|
+
});
|
|
1294
|
+
try {
|
|
1295
|
+
const countRequest = this.pool.request();
|
|
1296
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1297
|
+
countRequest.input(key, value);
|
|
1298
|
+
});
|
|
1299
|
+
const countResult = await countRequest.query(
|
|
1300
|
+
`SELECT COUNT(*) as count FROM ${tableName}${actualWhereClause}`
|
|
1301
|
+
);
|
|
1302
|
+
const total = countResult.recordset[0]?.count ?? 0;
|
|
1303
|
+
if (total === 0) {
|
|
1304
|
+
return {
|
|
1305
|
+
pagination: {
|
|
1306
|
+
total: 0,
|
|
1307
|
+
page,
|
|
1308
|
+
perPage,
|
|
1309
|
+
hasMore: false
|
|
1310
|
+
},
|
|
1311
|
+
spans: []
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
const dataRequest = this.pool.request();
|
|
1315
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
1316
|
+
dataRequest.input(key, value);
|
|
1317
|
+
});
|
|
1318
|
+
dataRequest.input("offset", page * perPage);
|
|
1319
|
+
dataRequest.input("limit", perPage);
|
|
1320
|
+
const dataResult = await dataRequest.query(
|
|
1321
|
+
`SELECT * FROM ${tableName}${actualWhereClause} ORDER BY [startedAt] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`
|
|
1322
|
+
);
|
|
1323
|
+
const spans = dataResult.recordset.map(
|
|
1324
|
+
(row) => transformFromSqlRow({
|
|
1325
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1326
|
+
sqlRow: row
|
|
1327
|
+
})
|
|
1328
|
+
);
|
|
1329
|
+
return {
|
|
1330
|
+
pagination: {
|
|
1331
|
+
total,
|
|
1332
|
+
page,
|
|
1333
|
+
perPage,
|
|
1334
|
+
hasMore: (page + 1) * perPage < total
|
|
1335
|
+
},
|
|
1336
|
+
spans
|
|
1337
|
+
};
|
|
1338
|
+
} catch (error$1) {
|
|
1339
|
+
throw new error.MastraError(
|
|
1340
|
+
{
|
|
1341
|
+
id: "MSSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1342
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1343
|
+
category: error.ErrorCategory.USER
|
|
1344
|
+
},
|
|
1345
|
+
error$1
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
async batchCreateAISpans(args) {
|
|
1350
|
+
if (!args.records || args.records.length === 0) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
try {
|
|
1354
|
+
await this.operations.batchInsert({
|
|
1355
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1356
|
+
records: args.records.map((span) => ({
|
|
1357
|
+
...span,
|
|
1358
|
+
startedAt: span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt,
|
|
1359
|
+
endedAt: span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt
|
|
1360
|
+
}))
|
|
1361
|
+
});
|
|
1362
|
+
} catch (error$1) {
|
|
1363
|
+
throw new error.MastraError(
|
|
1364
|
+
{
|
|
1365
|
+
id: "MSSQL_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
1366
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1367
|
+
category: error.ErrorCategory.USER,
|
|
1368
|
+
details: {
|
|
1369
|
+
count: args.records.length
|
|
1370
|
+
}
|
|
1371
|
+
},
|
|
1372
|
+
error$1
|
|
1373
|
+
);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
async batchUpdateAISpans(args) {
|
|
1377
|
+
if (!args.records || args.records.length === 0) {
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
try {
|
|
1381
|
+
const updates = args.records.map(({ traceId, spanId, updates: data }) => {
|
|
1382
|
+
const processedData = { ...data };
|
|
1383
|
+
if (processedData.endedAt instanceof Date) {
|
|
1384
|
+
processedData.endedAt = processedData.endedAt.toISOString();
|
|
1385
|
+
}
|
|
1386
|
+
if (processedData.startedAt instanceof Date) {
|
|
1387
|
+
processedData.startedAt = processedData.startedAt.toISOString();
|
|
1388
|
+
}
|
|
1389
|
+
return {
|
|
1390
|
+
keys: { spanId, traceId },
|
|
1391
|
+
data: processedData
|
|
1392
|
+
};
|
|
1393
|
+
});
|
|
1394
|
+
await this.operations.batchUpdate({
|
|
1395
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1396
|
+
updates
|
|
1397
|
+
});
|
|
1398
|
+
} catch (error$1) {
|
|
1399
|
+
throw new error.MastraError(
|
|
1400
|
+
{
|
|
1401
|
+
id: "MSSQL_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
1402
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1403
|
+
category: error.ErrorCategory.USER,
|
|
1404
|
+
details: {
|
|
1405
|
+
count: args.records.length
|
|
1406
|
+
}
|
|
1407
|
+
},
|
|
1408
|
+
error$1
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
async batchDeleteAITraces(args) {
|
|
1413
|
+
if (!args.traceIds || args.traceIds.length === 0) {
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
try {
|
|
1417
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
1418
|
+
await this.operations.batchDelete({
|
|
1419
|
+
tableName: storage.TABLE_AI_SPANS,
|
|
1420
|
+
keys
|
|
1421
|
+
});
|
|
1422
|
+
} catch (error$1) {
|
|
1423
|
+
throw new error.MastraError(
|
|
1424
|
+
{
|
|
1425
|
+
id: "MSSQL_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
1426
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1427
|
+
category: error.ErrorCategory.USER,
|
|
1428
|
+
details: {
|
|
1429
|
+
count: args.traceIds.length
|
|
1430
|
+
}
|
|
1431
|
+
},
|
|
1432
|
+
error$1
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
1438
|
+
pool;
|
|
1439
|
+
schemaName;
|
|
1440
|
+
setupSchemaPromise = null;
|
|
1441
|
+
schemaSetupComplete = void 0;
|
|
1442
|
+
getSqlType(type, isPrimaryKey = false, useLargeStorage = false) {
|
|
1443
|
+
switch (type) {
|
|
1444
|
+
case "text":
|
|
1445
|
+
if (useLargeStorage) {
|
|
1446
|
+
return "NVARCHAR(MAX)";
|
|
1447
|
+
}
|
|
1448
|
+
return isPrimaryKey ? "NVARCHAR(255)" : "NVARCHAR(400)";
|
|
1449
|
+
case "timestamp":
|
|
1450
|
+
return "DATETIME2(7)";
|
|
1451
|
+
case "uuid":
|
|
1452
|
+
return "UNIQUEIDENTIFIER";
|
|
1453
|
+
case "jsonb":
|
|
1454
|
+
return "NVARCHAR(MAX)";
|
|
1455
|
+
case "integer":
|
|
1456
|
+
return "INT";
|
|
1457
|
+
case "bigint":
|
|
1458
|
+
return "BIGINT";
|
|
1459
|
+
case "float":
|
|
1460
|
+
return "FLOAT";
|
|
1461
|
+
case "boolean":
|
|
1462
|
+
return "BIT";
|
|
1463
|
+
default:
|
|
1464
|
+
throw new error.MastraError({
|
|
1465
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_TYPE_NOT_SUPPORTED",
|
|
1466
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1467
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
constructor({ pool, schemaName }) {
|
|
1472
|
+
super();
|
|
1473
|
+
this.pool = pool;
|
|
1474
|
+
this.schemaName = schemaName;
|
|
1475
|
+
}
|
|
1476
|
+
async hasColumn(table, column) {
|
|
1477
|
+
const schema = this.schemaName || "dbo";
|
|
1478
|
+
const request = this.pool.request();
|
|
1479
|
+
request.input("schema", schema);
|
|
1480
|
+
request.input("table", table);
|
|
1481
|
+
request.input("column", column);
|
|
1482
|
+
request.input("columnLower", column.toLowerCase());
|
|
1483
|
+
const result = await request.query(
|
|
1484
|
+
`SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema AND TABLE_NAME = @table AND (COLUMN_NAME = @column OR COLUMN_NAME = @columnLower)`
|
|
1485
|
+
);
|
|
1486
|
+
return result.recordset.length > 0;
|
|
1487
|
+
}
|
|
1488
|
+
async setupSchema() {
|
|
1489
|
+
if (!this.schemaName || this.schemaSetupComplete) {
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
if (!this.setupSchemaPromise) {
|
|
1493
|
+
this.setupSchemaPromise = (async () => {
|
|
1494
|
+
try {
|
|
1495
|
+
const checkRequest = this.pool.request();
|
|
1496
|
+
checkRequest.input("schemaName", this.schemaName);
|
|
1497
|
+
const checkResult = await checkRequest.query(`
|
|
1498
|
+
SELECT 1 AS found FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @schemaName
|
|
1499
|
+
`);
|
|
1500
|
+
const schemaExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1501
|
+
if (!schemaExists) {
|
|
1502
|
+
try {
|
|
1503
|
+
await this.pool.request().query(`CREATE SCHEMA [${this.schemaName}]`);
|
|
1504
|
+
this.logger?.info?.(`Schema "${this.schemaName}" created successfully`);
|
|
1505
|
+
} catch (error) {
|
|
1506
|
+
this.logger?.error?.(`Failed to create schema "${this.schemaName}"`, { error });
|
|
1507
|
+
throw new Error(
|
|
1508
|
+
`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.`
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
this.schemaSetupComplete = true;
|
|
1513
|
+
this.logger?.debug?.(`Schema "${this.schemaName}" is ready for use`);
|
|
1514
|
+
} catch (error) {
|
|
1515
|
+
this.schemaSetupComplete = void 0;
|
|
1516
|
+
this.setupSchemaPromise = null;
|
|
1517
|
+
throw error;
|
|
1518
|
+
} finally {
|
|
1519
|
+
this.setupSchemaPromise = null;
|
|
1520
|
+
}
|
|
1521
|
+
})();
|
|
1522
|
+
}
|
|
1523
|
+
await this.setupSchemaPromise;
|
|
1524
|
+
}
|
|
1525
|
+
async insert({
|
|
1526
|
+
tableName,
|
|
1527
|
+
record,
|
|
1528
|
+
transaction
|
|
1529
|
+
}) {
|
|
1530
|
+
try {
|
|
1531
|
+
const columns = Object.keys(record);
|
|
1532
|
+
const parsedColumns = columns.map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1533
|
+
const paramNames = columns.map((_, i) => `@param${i}`);
|
|
1534
|
+
const insertSql = `INSERT INTO ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (${parsedColumns.map((c) => `[${c}]`).join(", ")}) VALUES (${paramNames.join(", ")})`;
|
|
1535
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1536
|
+
columns.forEach((col, i) => {
|
|
1537
|
+
const value = record[col];
|
|
1538
|
+
const preparedValue = this.prepareValue(value, col, tableName);
|
|
1539
|
+
if (preparedValue instanceof Date) {
|
|
1540
|
+
request.input(`param${i}`, sql2__default.default.DateTime2, preparedValue);
|
|
1541
|
+
} else if (preparedValue === null || preparedValue === void 0) {
|
|
1542
|
+
request.input(`param${i}`, this.getMssqlType(tableName, col), null);
|
|
1543
|
+
} else {
|
|
1544
|
+
request.input(`param${i}`, preparedValue);
|
|
1545
|
+
}
|
|
1546
|
+
});
|
|
1547
|
+
await request.query(insertSql);
|
|
1548
|
+
} catch (error$1) {
|
|
1549
|
+
throw new error.MastraError(
|
|
1550
|
+
{
|
|
1551
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_INSERT_FAILED",
|
|
1552
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1553
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1554
|
+
details: {
|
|
1555
|
+
tableName
|
|
1556
|
+
}
|
|
1557
|
+
},
|
|
1558
|
+
error$1
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
async clearTable({ tableName }) {
|
|
1563
|
+
const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1185
1564
|
try {
|
|
1186
1565
|
try {
|
|
1187
1566
|
await this.pool.request().query(`TRUNCATE TABLE ${fullTableName}`);
|
|
1188
1567
|
} catch (truncateError) {
|
|
1189
|
-
if (truncateError
|
|
1568
|
+
if (truncateError?.number === 4712) {
|
|
1190
1569
|
await this.pool.request().query(`DELETE FROM ${fullTableName}`);
|
|
1191
1570
|
} else {
|
|
1192
1571
|
throw truncateError;
|
|
@@ -1209,9 +1588,11 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1209
1588
|
getDefaultValue(type) {
|
|
1210
1589
|
switch (type) {
|
|
1211
1590
|
case "timestamp":
|
|
1212
|
-
return "DEFAULT
|
|
1591
|
+
return "DEFAULT SYSUTCDATETIME()";
|
|
1213
1592
|
case "jsonb":
|
|
1214
1593
|
return "DEFAULT N'{}'";
|
|
1594
|
+
case "boolean":
|
|
1595
|
+
return "DEFAULT 0";
|
|
1215
1596
|
default:
|
|
1216
1597
|
return super.getDefaultValue(type);
|
|
1217
1598
|
}
|
|
@@ -1222,13 +1603,29 @@ var StoreOperationsMSSQL = class extends storage.StoreOperations {
|
|
|
1222
1603
|
}) {
|
|
1223
1604
|
try {
|
|
1224
1605
|
const uniqueConstraintColumns = tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? ["workflow_name", "run_id"] : [];
|
|
1606
|
+
const largeDataColumns = [
|
|
1607
|
+
"workingMemory",
|
|
1608
|
+
"snapshot",
|
|
1609
|
+
"metadata",
|
|
1610
|
+
"content",
|
|
1611
|
+
// messages.content - can be very long conversation content
|
|
1612
|
+
"input",
|
|
1613
|
+
// evals.input - test input data
|
|
1614
|
+
"output",
|
|
1615
|
+
// evals.output - test output data
|
|
1616
|
+
"instructions",
|
|
1617
|
+
// evals.instructions - evaluation instructions
|
|
1618
|
+
"other"
|
|
1619
|
+
// traces.other - additional trace data
|
|
1620
|
+
];
|
|
1225
1621
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1226
1622
|
const parsedName = utils.parseSqlIdentifier(name, "column name");
|
|
1227
1623
|
const constraints = [];
|
|
1228
1624
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1229
1625
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1230
1626
|
const isIndexed = !!def.primaryKey || uniqueConstraintColumns.includes(name);
|
|
1231
|
-
|
|
1627
|
+
const useLargeStorage = largeDataColumns.includes(name);
|
|
1628
|
+
return `[${parsedName}] ${this.getSqlType(def.type, isIndexed, useLargeStorage)} ${constraints.join(" ")}`.trim();
|
|
1232
1629
|
}).join(",\n");
|
|
1233
1630
|
if (this.schemaName) {
|
|
1234
1631
|
await this.setupSchema();
|
|
@@ -1315,7 +1712,19 @@ ${columns}
|
|
|
1315
1712
|
const columnExists = Array.isArray(checkResult.recordset) && checkResult.recordset.length > 0;
|
|
1316
1713
|
if (!columnExists) {
|
|
1317
1714
|
const columnDef = schema[columnName];
|
|
1318
|
-
const
|
|
1715
|
+
const largeDataColumns = [
|
|
1716
|
+
"workingMemory",
|
|
1717
|
+
"snapshot",
|
|
1718
|
+
"metadata",
|
|
1719
|
+
"content",
|
|
1720
|
+
"input",
|
|
1721
|
+
"output",
|
|
1722
|
+
"instructions",
|
|
1723
|
+
"other"
|
|
1724
|
+
];
|
|
1725
|
+
const useLargeStorage = largeDataColumns.includes(columnName);
|
|
1726
|
+
const isIndexed = !!columnDef.primaryKey;
|
|
1727
|
+
const sqlType = this.getSqlType(columnDef.type, isIndexed, useLargeStorage);
|
|
1319
1728
|
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1320
1729
|
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1321
1730
|
const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
|
|
@@ -1324,120 +1733,660 @@ ${columns}
|
|
|
1324
1733
|
this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
|
|
1325
1734
|
}
|
|
1326
1735
|
}
|
|
1327
|
-
}
|
|
1736
|
+
}
|
|
1737
|
+
} catch (error$1) {
|
|
1738
|
+
throw new error.MastraError(
|
|
1739
|
+
{
|
|
1740
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_ALTER_TABLE_FAILED",
|
|
1741
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1742
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1743
|
+
details: {
|
|
1744
|
+
tableName
|
|
1745
|
+
}
|
|
1746
|
+
},
|
|
1747
|
+
error$1
|
|
1748
|
+
);
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
async load({ tableName, keys }) {
|
|
1752
|
+
try {
|
|
1753
|
+
const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
|
|
1754
|
+
const conditions = keyEntries.map(([key], i) => `[${key}] = @param${i}`).join(" AND ");
|
|
1755
|
+
const sql5 = `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`;
|
|
1756
|
+
const request = this.pool.request();
|
|
1757
|
+
keyEntries.forEach(([key, value], i) => {
|
|
1758
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1759
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1760
|
+
request.input(`param${i}`, this.getMssqlType(tableName, key), null);
|
|
1761
|
+
} else {
|
|
1762
|
+
request.input(`param${i}`, preparedValue);
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1765
|
+
const resultSet = await request.query(sql5);
|
|
1766
|
+
const result = resultSet.recordset[0] || null;
|
|
1767
|
+
if (!result) {
|
|
1768
|
+
return null;
|
|
1769
|
+
}
|
|
1770
|
+
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
1771
|
+
const snapshot = result;
|
|
1772
|
+
if (typeof snapshot.snapshot === "string") {
|
|
1773
|
+
snapshot.snapshot = JSON.parse(snapshot.snapshot);
|
|
1774
|
+
}
|
|
1775
|
+
return snapshot;
|
|
1776
|
+
}
|
|
1777
|
+
return result;
|
|
1778
|
+
} catch (error$1) {
|
|
1779
|
+
throw new error.MastraError(
|
|
1780
|
+
{
|
|
1781
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_LOAD_FAILED",
|
|
1782
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1783
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1784
|
+
details: {
|
|
1785
|
+
tableName
|
|
1786
|
+
}
|
|
1787
|
+
},
|
|
1788
|
+
error$1
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
async batchInsert({ tableName, records }) {
|
|
1793
|
+
const transaction = this.pool.transaction();
|
|
1794
|
+
try {
|
|
1795
|
+
await transaction.begin();
|
|
1796
|
+
for (const record of records) {
|
|
1797
|
+
await this.insert({ tableName, record, transaction });
|
|
1798
|
+
}
|
|
1799
|
+
await transaction.commit();
|
|
1800
|
+
} catch (error$1) {
|
|
1801
|
+
await transaction.rollback();
|
|
1802
|
+
throw new error.MastraError(
|
|
1803
|
+
{
|
|
1804
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_INSERT_FAILED",
|
|
1805
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1806
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1807
|
+
details: {
|
|
1808
|
+
tableName,
|
|
1809
|
+
numberOfRecords: records.length
|
|
1810
|
+
}
|
|
1811
|
+
},
|
|
1812
|
+
error$1
|
|
1813
|
+
);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
async dropTable({ tableName }) {
|
|
1817
|
+
try {
|
|
1818
|
+
const tableNameWithSchema = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1819
|
+
await this.pool.request().query(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
|
|
1820
|
+
} catch (error$1) {
|
|
1821
|
+
throw new error.MastraError(
|
|
1822
|
+
{
|
|
1823
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_DROP_TABLE_FAILED",
|
|
1824
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1825
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1826
|
+
details: {
|
|
1827
|
+
tableName
|
|
1828
|
+
}
|
|
1829
|
+
},
|
|
1830
|
+
error$1
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Prepares a value for database operations, handling Date objects and JSON serialization
|
|
1836
|
+
*/
|
|
1837
|
+
prepareValue(value, columnName, tableName) {
|
|
1838
|
+
if (value === null || value === void 0) {
|
|
1839
|
+
return value;
|
|
1840
|
+
}
|
|
1841
|
+
if (value instanceof Date) {
|
|
1842
|
+
return value;
|
|
1843
|
+
}
|
|
1844
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
1845
|
+
const columnSchema = schema?.[columnName];
|
|
1846
|
+
if (columnSchema?.type === "boolean") {
|
|
1847
|
+
return value ? 1 : 0;
|
|
1848
|
+
}
|
|
1849
|
+
if (columnSchema?.type === "jsonb") {
|
|
1850
|
+
return JSON.stringify(value);
|
|
1851
|
+
}
|
|
1852
|
+
if (typeof value === "object") {
|
|
1853
|
+
return JSON.stringify(value);
|
|
1854
|
+
}
|
|
1855
|
+
return value;
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Maps TABLE_SCHEMAS types to mssql param types (used when value is null)
|
|
1859
|
+
*/
|
|
1860
|
+
getMssqlType(tableName, columnName) {
|
|
1861
|
+
const col = storage.TABLE_SCHEMAS[tableName]?.[columnName];
|
|
1862
|
+
switch (col?.type) {
|
|
1863
|
+
case "text":
|
|
1864
|
+
return sql2__default.default.NVarChar;
|
|
1865
|
+
case "timestamp":
|
|
1866
|
+
return sql2__default.default.DateTime2;
|
|
1867
|
+
case "uuid":
|
|
1868
|
+
return sql2__default.default.UniqueIdentifier;
|
|
1869
|
+
case "jsonb":
|
|
1870
|
+
return sql2__default.default.NVarChar;
|
|
1871
|
+
case "integer":
|
|
1872
|
+
return sql2__default.default.Int;
|
|
1873
|
+
case "bigint":
|
|
1874
|
+
return sql2__default.default.BigInt;
|
|
1875
|
+
case "float":
|
|
1876
|
+
return sql2__default.default.Float;
|
|
1877
|
+
case "boolean":
|
|
1878
|
+
return sql2__default.default.Bit;
|
|
1879
|
+
default:
|
|
1880
|
+
return sql2__default.default.NVarChar;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* Update a single record in the database
|
|
1885
|
+
*/
|
|
1886
|
+
async update({
|
|
1887
|
+
tableName,
|
|
1888
|
+
keys,
|
|
1889
|
+
data,
|
|
1890
|
+
transaction
|
|
1891
|
+
}) {
|
|
1892
|
+
try {
|
|
1893
|
+
if (!data || Object.keys(data).length === 0) {
|
|
1894
|
+
throw new error.MastraError({
|
|
1895
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_DATA",
|
|
1896
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1897
|
+
category: error.ErrorCategory.USER,
|
|
1898
|
+
text: "Cannot update with empty data payload"
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
1902
|
+
throw new error.MastraError({
|
|
1903
|
+
id: "MASTRA_STORAGE_MSSQL_UPDATE_EMPTY_KEYS",
|
|
1904
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1905
|
+
category: error.ErrorCategory.USER,
|
|
1906
|
+
text: "Cannot update without keys to identify records"
|
|
1907
|
+
});
|
|
1908
|
+
}
|
|
1909
|
+
const setClauses = [];
|
|
1910
|
+
const request = transaction ? transaction.request() : this.pool.request();
|
|
1911
|
+
let paramIndex = 0;
|
|
1912
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
1913
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
1914
|
+
const paramName = `set${paramIndex++}`;
|
|
1915
|
+
setClauses.push(`[${parsedKey}] = @${paramName}`);
|
|
1916
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1917
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1918
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1919
|
+
} else {
|
|
1920
|
+
request.input(paramName, preparedValue);
|
|
1921
|
+
}
|
|
1922
|
+
});
|
|
1923
|
+
const whereConditions = [];
|
|
1924
|
+
Object.entries(keys).forEach(([key, value]) => {
|
|
1925
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
1926
|
+
const paramName = `where${paramIndex++}`;
|
|
1927
|
+
whereConditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1928
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
1929
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
1930
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
1931
|
+
} else {
|
|
1932
|
+
request.input(paramName, preparedValue);
|
|
1933
|
+
}
|
|
1934
|
+
});
|
|
1935
|
+
const tableName_ = getTableName({
|
|
1936
|
+
indexName: tableName,
|
|
1937
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1938
|
+
});
|
|
1939
|
+
const updateSql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
|
|
1940
|
+
await request.query(updateSql);
|
|
1941
|
+
} catch (error$1) {
|
|
1942
|
+
throw new error.MastraError(
|
|
1943
|
+
{
|
|
1944
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_FAILED",
|
|
1945
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1946
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1947
|
+
details: {
|
|
1948
|
+
tableName
|
|
1949
|
+
}
|
|
1950
|
+
},
|
|
1951
|
+
error$1
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
/**
|
|
1956
|
+
* Update multiple records in a single batch transaction
|
|
1957
|
+
*/
|
|
1958
|
+
async batchUpdate({
|
|
1959
|
+
tableName,
|
|
1960
|
+
updates
|
|
1961
|
+
}) {
|
|
1962
|
+
const transaction = this.pool.transaction();
|
|
1963
|
+
try {
|
|
1964
|
+
await transaction.begin();
|
|
1965
|
+
for (const { keys, data } of updates) {
|
|
1966
|
+
await this.update({ tableName, keys, data, transaction });
|
|
1967
|
+
}
|
|
1968
|
+
await transaction.commit();
|
|
1969
|
+
} catch (error$1) {
|
|
1970
|
+
await transaction.rollback();
|
|
1971
|
+
throw new error.MastraError(
|
|
1972
|
+
{
|
|
1973
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_UPDATE_FAILED",
|
|
1974
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1975
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1976
|
+
details: {
|
|
1977
|
+
tableName,
|
|
1978
|
+
numberOfRecords: updates.length
|
|
1979
|
+
}
|
|
1980
|
+
},
|
|
1981
|
+
error$1
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
/**
|
|
1986
|
+
* Delete multiple records by keys
|
|
1987
|
+
*/
|
|
1988
|
+
async batchDelete({ tableName, keys }) {
|
|
1989
|
+
if (keys.length === 0) {
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
const tableName_ = getTableName({
|
|
1993
|
+
indexName: tableName,
|
|
1994
|
+
schemaName: getSchemaName(this.schemaName)
|
|
1995
|
+
});
|
|
1996
|
+
const transaction = this.pool.transaction();
|
|
1997
|
+
try {
|
|
1998
|
+
await transaction.begin();
|
|
1999
|
+
for (const keySet of keys) {
|
|
2000
|
+
const conditions = [];
|
|
2001
|
+
const request = transaction.request();
|
|
2002
|
+
let paramIndex = 0;
|
|
2003
|
+
Object.entries(keySet).forEach(([key, value]) => {
|
|
2004
|
+
const parsedKey = utils.parseSqlIdentifier(key, "column name");
|
|
2005
|
+
const paramName = `p${paramIndex++}`;
|
|
2006
|
+
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
2007
|
+
const preparedValue = this.prepareValue(value, key, tableName);
|
|
2008
|
+
if (preparedValue === null || preparedValue === void 0) {
|
|
2009
|
+
request.input(paramName, this.getMssqlType(tableName, key), null);
|
|
2010
|
+
} else {
|
|
2011
|
+
request.input(paramName, preparedValue);
|
|
2012
|
+
}
|
|
2013
|
+
});
|
|
2014
|
+
const deleteSql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
|
|
2015
|
+
await request.query(deleteSql);
|
|
2016
|
+
}
|
|
2017
|
+
await transaction.commit();
|
|
2018
|
+
} catch (error$1) {
|
|
2019
|
+
await transaction.rollback();
|
|
2020
|
+
throw new error.MastraError(
|
|
2021
|
+
{
|
|
2022
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_BATCH_DELETE_FAILED",
|
|
2023
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2024
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2025
|
+
details: {
|
|
2026
|
+
tableName,
|
|
2027
|
+
numberOfRecords: keys.length
|
|
2028
|
+
}
|
|
2029
|
+
},
|
|
2030
|
+
error$1
|
|
2031
|
+
);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
/**
|
|
2035
|
+
* Create a new index on a table
|
|
2036
|
+
*/
|
|
2037
|
+
async createIndex(options) {
|
|
2038
|
+
try {
|
|
2039
|
+
const { name, table, columns, unique = false, where } = options;
|
|
2040
|
+
const schemaName = this.schemaName || "dbo";
|
|
2041
|
+
const fullTableName = getTableName({
|
|
2042
|
+
indexName: table,
|
|
2043
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2044
|
+
});
|
|
2045
|
+
const indexNameSafe = utils.parseSqlIdentifier(name, "index name");
|
|
2046
|
+
const checkRequest = this.pool.request();
|
|
2047
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2048
|
+
checkRequest.input("schemaName", schemaName);
|
|
2049
|
+
checkRequest.input("tableName", table);
|
|
2050
|
+
const indexExists = await checkRequest.query(`
|
|
2051
|
+
SELECT 1 as found
|
|
2052
|
+
FROM sys.indexes i
|
|
2053
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2054
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2055
|
+
WHERE i.name = @indexName
|
|
2056
|
+
AND s.name = @schemaName
|
|
2057
|
+
AND t.name = @tableName
|
|
2058
|
+
`);
|
|
2059
|
+
if (indexExists.recordset && indexExists.recordset.length > 0) {
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
const uniqueStr = unique ? "UNIQUE " : "";
|
|
2063
|
+
const columnsStr = columns.map((col) => {
|
|
2064
|
+
if (col.includes(" DESC") || col.includes(" ASC")) {
|
|
2065
|
+
const [colName, ...modifiers] = col.split(" ");
|
|
2066
|
+
if (!colName) {
|
|
2067
|
+
throw new Error(`Invalid column specification: ${col}`);
|
|
2068
|
+
}
|
|
2069
|
+
return `[${utils.parseSqlIdentifier(colName, "column name")}] ${modifiers.join(" ")}`;
|
|
2070
|
+
}
|
|
2071
|
+
return `[${utils.parseSqlIdentifier(col, "column name")}]`;
|
|
2072
|
+
}).join(", ");
|
|
2073
|
+
const whereStr = where ? ` WHERE ${where}` : "";
|
|
2074
|
+
const createIndexSql = `CREATE ${uniqueStr}INDEX [${indexNameSafe}] ON ${fullTableName} (${columnsStr})${whereStr}`;
|
|
2075
|
+
await this.pool.request().query(createIndexSql);
|
|
1328
2076
|
} catch (error$1) {
|
|
1329
2077
|
throw new error.MastraError(
|
|
1330
2078
|
{
|
|
1331
|
-
id: "
|
|
2079
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_CREATE_FAILED",
|
|
1332
2080
|
domain: error.ErrorDomain.STORAGE,
|
|
1333
2081
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1334
2082
|
details: {
|
|
1335
|
-
|
|
2083
|
+
indexName: options.name,
|
|
2084
|
+
tableName: options.table
|
|
1336
2085
|
}
|
|
1337
2086
|
},
|
|
1338
2087
|
error$1
|
|
1339
2088
|
);
|
|
1340
2089
|
}
|
|
1341
2090
|
}
|
|
1342
|
-
|
|
2091
|
+
/**
|
|
2092
|
+
* Drop an existing index
|
|
2093
|
+
*/
|
|
2094
|
+
async dropIndex(indexName) {
|
|
1343
2095
|
try {
|
|
1344
|
-
const
|
|
1345
|
-
const
|
|
1346
|
-
const
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
2096
|
+
const schemaName = this.schemaName || "dbo";
|
|
2097
|
+
const indexNameSafe = utils.parseSqlIdentifier(indexName, "index name");
|
|
2098
|
+
const checkRequest = this.pool.request();
|
|
2099
|
+
checkRequest.input("indexName", indexNameSafe);
|
|
2100
|
+
checkRequest.input("schemaName", schemaName);
|
|
2101
|
+
const result = await checkRequest.query(`
|
|
2102
|
+
SELECT t.name as table_name
|
|
2103
|
+
FROM sys.indexes i
|
|
2104
|
+
INNER JOIN sys.tables t ON i.object_id = t.object_id
|
|
2105
|
+
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
2106
|
+
WHERE i.name = @indexName
|
|
2107
|
+
AND s.name = @schemaName
|
|
2108
|
+
`);
|
|
2109
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2110
|
+
return;
|
|
1356
2111
|
}
|
|
1357
|
-
if (
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
2112
|
+
if (result.recordset.length > 1) {
|
|
2113
|
+
const tables = result.recordset.map((r) => r.table_name).join(", ");
|
|
2114
|
+
throw new error.MastraError({
|
|
2115
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_AMBIGUOUS",
|
|
2116
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2117
|
+
category: error.ErrorCategory.USER,
|
|
2118
|
+
text: `Index "${indexNameSafe}" exists on multiple tables (${tables}) in schema "${schemaName}". Please drop indexes manually or ensure unique index names.`
|
|
2119
|
+
});
|
|
1363
2120
|
}
|
|
1364
|
-
|
|
2121
|
+
const tableName = result.recordset[0].table_name;
|
|
2122
|
+
const fullTableName = getTableName({
|
|
2123
|
+
indexName: tableName,
|
|
2124
|
+
schemaName: getSchemaName(this.schemaName)
|
|
2125
|
+
});
|
|
2126
|
+
const dropSql = `DROP INDEX [${indexNameSafe}] ON ${fullTableName}`;
|
|
2127
|
+
await this.pool.request().query(dropSql);
|
|
1365
2128
|
} catch (error$1) {
|
|
1366
2129
|
throw new error.MastraError(
|
|
1367
2130
|
{
|
|
1368
|
-
id: "
|
|
2131
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DROP_FAILED",
|
|
1369
2132
|
domain: error.ErrorDomain.STORAGE,
|
|
1370
2133
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1371
2134
|
details: {
|
|
1372
|
-
|
|
2135
|
+
indexName
|
|
1373
2136
|
}
|
|
1374
2137
|
},
|
|
1375
2138
|
error$1
|
|
1376
2139
|
);
|
|
1377
2140
|
}
|
|
1378
2141
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
2142
|
+
/**
|
|
2143
|
+
* List indexes for a specific table or all tables
|
|
2144
|
+
*/
|
|
2145
|
+
async listIndexes(tableName) {
|
|
1381
2146
|
try {
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
2147
|
+
const schemaName = this.schemaName || "dbo";
|
|
2148
|
+
let query;
|
|
2149
|
+
const request = this.pool.request();
|
|
2150
|
+
request.input("schemaName", schemaName);
|
|
2151
|
+
if (tableName) {
|
|
2152
|
+
query = `
|
|
2153
|
+
SELECT
|
|
2154
|
+
i.name as name,
|
|
2155
|
+
o.name as [table],
|
|
2156
|
+
i.is_unique as is_unique,
|
|
2157
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2158
|
+
FROM sys.indexes i
|
|
2159
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2160
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2161
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2162
|
+
WHERE sch.name = @schemaName
|
|
2163
|
+
AND o.name = @tableName
|
|
2164
|
+
AND i.name IS NOT NULL
|
|
2165
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2166
|
+
`;
|
|
2167
|
+
request.input("tableName", tableName);
|
|
2168
|
+
} else {
|
|
2169
|
+
query = `
|
|
2170
|
+
SELECT
|
|
2171
|
+
i.name as name,
|
|
2172
|
+
o.name as [table],
|
|
2173
|
+
i.is_unique as is_unique,
|
|
2174
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size
|
|
2175
|
+
FROM sys.indexes i
|
|
2176
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2177
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2178
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2179
|
+
WHERE sch.name = @schemaName
|
|
2180
|
+
AND i.name IS NOT NULL
|
|
2181
|
+
GROUP BY i.name, o.name, i.is_unique
|
|
2182
|
+
`;
|
|
1385
2183
|
}
|
|
1386
|
-
await
|
|
2184
|
+
const result = await request.query(query);
|
|
2185
|
+
const indexes = [];
|
|
2186
|
+
for (const row of result.recordset) {
|
|
2187
|
+
const colRequest = this.pool.request();
|
|
2188
|
+
colRequest.input("indexName", row.name);
|
|
2189
|
+
colRequest.input("schemaName", schemaName);
|
|
2190
|
+
const colResult = await colRequest.query(`
|
|
2191
|
+
SELECT c.name as column_name
|
|
2192
|
+
FROM sys.indexes i
|
|
2193
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2194
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2195
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2196
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2197
|
+
WHERE i.name = @indexName
|
|
2198
|
+
AND s.name = @schemaName
|
|
2199
|
+
ORDER BY ic.key_ordinal
|
|
2200
|
+
`);
|
|
2201
|
+
indexes.push({
|
|
2202
|
+
name: row.name,
|
|
2203
|
+
table: row.table,
|
|
2204
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2205
|
+
unique: row.is_unique || false,
|
|
2206
|
+
size: row.size || "0 MB",
|
|
2207
|
+
definition: ""
|
|
2208
|
+
// MSSQL doesn't store definition like PG
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
return indexes;
|
|
1387
2212
|
} catch (error$1) {
|
|
1388
|
-
await transaction.rollback();
|
|
1389
2213
|
throw new error.MastraError(
|
|
1390
2214
|
{
|
|
1391
|
-
id: "
|
|
2215
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_LIST_FAILED",
|
|
1392
2216
|
domain: error.ErrorDomain.STORAGE,
|
|
1393
2217
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1394
|
-
details: {
|
|
1395
|
-
tableName
|
|
1396
|
-
|
|
1397
|
-
}
|
|
2218
|
+
details: tableName ? {
|
|
2219
|
+
tableName
|
|
2220
|
+
} : {}
|
|
1398
2221
|
},
|
|
1399
2222
|
error$1
|
|
1400
2223
|
);
|
|
1401
2224
|
}
|
|
1402
2225
|
}
|
|
1403
|
-
|
|
2226
|
+
/**
|
|
2227
|
+
* Get detailed statistics for a specific index
|
|
2228
|
+
*/
|
|
2229
|
+
async describeIndex(indexName) {
|
|
1404
2230
|
try {
|
|
1405
|
-
const
|
|
1406
|
-
|
|
2231
|
+
const schemaName = this.schemaName || "dbo";
|
|
2232
|
+
const request = this.pool.request();
|
|
2233
|
+
request.input("indexName", indexName);
|
|
2234
|
+
request.input("schemaName", schemaName);
|
|
2235
|
+
const query = `
|
|
2236
|
+
SELECT
|
|
2237
|
+
i.name as name,
|
|
2238
|
+
o.name as [table],
|
|
2239
|
+
i.is_unique as is_unique,
|
|
2240
|
+
CAST(SUM(s.used_page_count) * 8 / 1024.0 AS VARCHAR(50)) + ' MB' as size,
|
|
2241
|
+
i.type_desc as method,
|
|
2242
|
+
ISNULL(us.user_scans, 0) as scans,
|
|
2243
|
+
ISNULL(us.user_seeks + us.user_scans, 0) as tuples_read,
|
|
2244
|
+
ISNULL(us.user_lookups, 0) as tuples_fetched
|
|
2245
|
+
FROM sys.indexes i
|
|
2246
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2247
|
+
INNER JOIN sys.schemas sch ON o.schema_id = sch.schema_id
|
|
2248
|
+
LEFT JOIN sys.dm_db_partition_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
|
|
2249
|
+
LEFT JOIN sys.dm_db_index_usage_stats us ON i.object_id = us.object_id AND i.index_id = us.index_id
|
|
2250
|
+
WHERE i.name = @indexName
|
|
2251
|
+
AND sch.name = @schemaName
|
|
2252
|
+
GROUP BY i.name, o.name, i.is_unique, i.type_desc, us.user_seeks, us.user_scans, us.user_lookups
|
|
2253
|
+
`;
|
|
2254
|
+
const result = await request.query(query);
|
|
2255
|
+
if (!result.recordset || result.recordset.length === 0) {
|
|
2256
|
+
throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
|
|
2257
|
+
}
|
|
2258
|
+
const row = result.recordset[0];
|
|
2259
|
+
const colRequest = this.pool.request();
|
|
2260
|
+
colRequest.input("indexName", indexName);
|
|
2261
|
+
colRequest.input("schemaName", schemaName);
|
|
2262
|
+
const colResult = await colRequest.query(`
|
|
2263
|
+
SELECT c.name as column_name
|
|
2264
|
+
FROM sys.indexes i
|
|
2265
|
+
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
2266
|
+
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
2267
|
+
INNER JOIN sys.objects o ON i.object_id = o.object_id
|
|
2268
|
+
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
2269
|
+
WHERE i.name = @indexName
|
|
2270
|
+
AND s.name = @schemaName
|
|
2271
|
+
ORDER BY ic.key_ordinal
|
|
2272
|
+
`);
|
|
2273
|
+
return {
|
|
2274
|
+
name: row.name,
|
|
2275
|
+
table: row.table,
|
|
2276
|
+
columns: colResult.recordset.map((c) => c.column_name),
|
|
2277
|
+
unique: row.is_unique || false,
|
|
2278
|
+
size: row.size || "0 MB",
|
|
2279
|
+
definition: "",
|
|
2280
|
+
method: row.method?.toLowerCase() || "nonclustered",
|
|
2281
|
+
scans: Number(row.scans) || 0,
|
|
2282
|
+
tuples_read: Number(row.tuples_read) || 0,
|
|
2283
|
+
tuples_fetched: Number(row.tuples_fetched) || 0
|
|
2284
|
+
};
|
|
1407
2285
|
} catch (error$1) {
|
|
1408
2286
|
throw new error.MastraError(
|
|
1409
2287
|
{
|
|
1410
|
-
id: "
|
|
2288
|
+
id: "MASTRA_STORAGE_MSSQL_INDEX_DESCRIBE_FAILED",
|
|
1411
2289
|
domain: error.ErrorDomain.STORAGE,
|
|
1412
2290
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1413
2291
|
details: {
|
|
1414
|
-
|
|
2292
|
+
indexName
|
|
1415
2293
|
}
|
|
1416
2294
|
},
|
|
1417
2295
|
error$1
|
|
1418
2296
|
);
|
|
1419
2297
|
}
|
|
1420
2298
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
2299
|
+
/**
|
|
2300
|
+
* Returns definitions for automatic performance indexes
|
|
2301
|
+
* IMPORTANT: Uses seq_id DESC instead of createdAt DESC for MSSQL due to millisecond accuracy limitations
|
|
2302
|
+
* NOTE: Using NVARCHAR(400) for text columns (800 bytes) leaves room for composite indexes
|
|
2303
|
+
*/
|
|
2304
|
+
getAutomaticIndexDefinitions() {
|
|
2305
|
+
const schemaPrefix = this.schemaName ? `${this.schemaName}_` : "";
|
|
2306
|
+
return [
|
|
2307
|
+
// Composite indexes for optimal filtering + sorting performance
|
|
2308
|
+
// NVARCHAR(400) = 800 bytes, plus BIGINT (8 bytes) = 808 bytes total (under 900-byte limit)
|
|
2309
|
+
{
|
|
2310
|
+
name: `${schemaPrefix}mastra_threads_resourceid_seqid_idx`,
|
|
2311
|
+
table: storage.TABLE_THREADS,
|
|
2312
|
+
columns: ["resourceId", "seq_id DESC"]
|
|
2313
|
+
},
|
|
2314
|
+
{
|
|
2315
|
+
name: `${schemaPrefix}mastra_messages_thread_id_seqid_idx`,
|
|
2316
|
+
table: storage.TABLE_MESSAGES,
|
|
2317
|
+
columns: ["thread_id", "seq_id DESC"]
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
name: `${schemaPrefix}mastra_traces_name_seqid_idx`,
|
|
2321
|
+
table: storage.TABLE_TRACES,
|
|
2322
|
+
columns: ["name", "seq_id DESC"]
|
|
2323
|
+
},
|
|
2324
|
+
{
|
|
2325
|
+
name: `${schemaPrefix}mastra_scores_trace_id_span_id_seqid_idx`,
|
|
2326
|
+
table: storage.TABLE_SCORERS,
|
|
2327
|
+
columns: ["traceId", "spanId", "seq_id DESC"]
|
|
2328
|
+
},
|
|
2329
|
+
// AI Spans indexes for optimal trace querying
|
|
2330
|
+
{
|
|
2331
|
+
name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
|
|
2332
|
+
table: storage.TABLE_AI_SPANS,
|
|
2333
|
+
columns: ["traceId", "startedAt DESC"]
|
|
2334
|
+
},
|
|
2335
|
+
{
|
|
2336
|
+
name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
|
|
2337
|
+
table: storage.TABLE_AI_SPANS,
|
|
2338
|
+
columns: ["parentSpanId", "startedAt DESC"]
|
|
2339
|
+
},
|
|
2340
|
+
{
|
|
2341
|
+
name: `${schemaPrefix}mastra_ai_spans_name_idx`,
|
|
2342
|
+
table: storage.TABLE_AI_SPANS,
|
|
2343
|
+
columns: ["name"]
|
|
2344
|
+
},
|
|
2345
|
+
{
|
|
2346
|
+
name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
|
|
2347
|
+
table: storage.TABLE_AI_SPANS,
|
|
2348
|
+
columns: ["spanType", "startedAt DESC"]
|
|
2349
|
+
}
|
|
2350
|
+
];
|
|
1427
2351
|
}
|
|
1428
|
-
|
|
2352
|
+
/**
|
|
2353
|
+
* Creates automatic indexes for optimal query performance
|
|
2354
|
+
* Uses getAutomaticIndexDefinitions() to determine which indexes to create
|
|
2355
|
+
*/
|
|
2356
|
+
async createAutomaticIndexes() {
|
|
2357
|
+
try {
|
|
2358
|
+
const indexes = this.getAutomaticIndexDefinitions();
|
|
2359
|
+
for (const indexOptions of indexes) {
|
|
2360
|
+
try {
|
|
2361
|
+
await this.createIndex(indexOptions);
|
|
2362
|
+
} catch (error) {
|
|
2363
|
+
this.logger?.warn?.(`Failed to create index ${indexOptions.name}:`, error);
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
} catch (error$1) {
|
|
2367
|
+
throw new error.MastraError(
|
|
2368
|
+
{
|
|
2369
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_CREATE_PERFORMANCE_INDEXES_FAILED",
|
|
2370
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2371
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2372
|
+
},
|
|
2373
|
+
error$1
|
|
2374
|
+
);
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
};
|
|
1429
2378
|
function transformScoreRow(row) {
|
|
1430
2379
|
return {
|
|
1431
2380
|
...row,
|
|
1432
|
-
input:
|
|
1433
|
-
scorer:
|
|
1434
|
-
preprocessStepResult:
|
|
1435
|
-
analyzeStepResult:
|
|
1436
|
-
metadata:
|
|
1437
|
-
output:
|
|
1438
|
-
additionalContext:
|
|
1439
|
-
|
|
1440
|
-
entity:
|
|
2381
|
+
input: storage.safelyParseJSON(row.input),
|
|
2382
|
+
scorer: storage.safelyParseJSON(row.scorer),
|
|
2383
|
+
preprocessStepResult: storage.safelyParseJSON(row.preprocessStepResult),
|
|
2384
|
+
analyzeStepResult: storage.safelyParseJSON(row.analyzeStepResult),
|
|
2385
|
+
metadata: storage.safelyParseJSON(row.metadata),
|
|
2386
|
+
output: storage.safelyParseJSON(row.output),
|
|
2387
|
+
additionalContext: storage.safelyParseJSON(row.additionalContext),
|
|
2388
|
+
requestContext: storage.safelyParseJSON(row.requestContext),
|
|
2389
|
+
entity: storage.safelyParseJSON(row.entity),
|
|
1441
2390
|
createdAt: row.createdAt,
|
|
1442
2391
|
updatedAt: row.updatedAt
|
|
1443
2392
|
};
|
|
@@ -1503,7 +2452,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1503
2452
|
input,
|
|
1504
2453
|
output,
|
|
1505
2454
|
additionalContext,
|
|
1506
|
-
|
|
2455
|
+
requestContext,
|
|
1507
2456
|
entity,
|
|
1508
2457
|
...rest
|
|
1509
2458
|
} = validatedScore;
|
|
@@ -1512,15 +2461,15 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1512
2461
|
record: {
|
|
1513
2462
|
id: scoreId,
|
|
1514
2463
|
...rest,
|
|
1515
|
-
input:
|
|
1516
|
-
output:
|
|
1517
|
-
preprocessStepResult: preprocessStepResult
|
|
1518
|
-
analyzeStepResult: analyzeStepResult
|
|
1519
|
-
metadata: metadata
|
|
1520
|
-
additionalContext: additionalContext
|
|
1521
|
-
|
|
1522
|
-
entity: entity
|
|
1523
|
-
scorer: scorer
|
|
2464
|
+
input: input || "",
|
|
2465
|
+
output: output || "",
|
|
2466
|
+
preprocessStepResult: preprocessStepResult || null,
|
|
2467
|
+
analyzeStepResult: analyzeStepResult || null,
|
|
2468
|
+
metadata: metadata || null,
|
|
2469
|
+
additionalContext: additionalContext || null,
|
|
2470
|
+
requestContext: requestContext || null,
|
|
2471
|
+
entity: entity || null,
|
|
2472
|
+
scorer: scorer || null,
|
|
1524
2473
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1525
2474
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1526
2475
|
}
|
|
@@ -1540,14 +2489,37 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1540
2489
|
}
|
|
1541
2490
|
async getScoresByScorerId({
|
|
1542
2491
|
scorerId,
|
|
1543
|
-
pagination
|
|
2492
|
+
pagination,
|
|
2493
|
+
entityId,
|
|
2494
|
+
entityType,
|
|
2495
|
+
source
|
|
1544
2496
|
}) {
|
|
1545
2497
|
try {
|
|
1546
|
-
const
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
2498
|
+
const conditions = ["[scorerId] = @p1"];
|
|
2499
|
+
const params = { p1: scorerId };
|
|
2500
|
+
let paramIndex = 2;
|
|
2501
|
+
if (entityId) {
|
|
2502
|
+
conditions.push(`[entityId] = @p${paramIndex}`);
|
|
2503
|
+
params[`p${paramIndex}`] = entityId;
|
|
2504
|
+
paramIndex++;
|
|
2505
|
+
}
|
|
2506
|
+
if (entityType) {
|
|
2507
|
+
conditions.push(`[entityType] = @p${paramIndex}`);
|
|
2508
|
+
params[`p${paramIndex}`] = entityType;
|
|
2509
|
+
paramIndex++;
|
|
2510
|
+
}
|
|
2511
|
+
if (source) {
|
|
2512
|
+
conditions.push(`[source] = @p${paramIndex}`);
|
|
2513
|
+
params[`p${paramIndex}`] = source;
|
|
2514
|
+
paramIndex++;
|
|
2515
|
+
}
|
|
2516
|
+
const whereClause = conditions.join(" AND ");
|
|
2517
|
+
const tableName = getTableName({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName(this.schema) });
|
|
2518
|
+
const countRequest = this.pool.request();
|
|
2519
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2520
|
+
countRequest.input(key, value);
|
|
2521
|
+
});
|
|
2522
|
+
const totalResult = await countRequest.query(`SELECT COUNT(*) as count FROM ${tableName} WHERE ${whereClause}`);
|
|
1551
2523
|
const total = totalResult.recordset[0]?.count || 0;
|
|
1552
2524
|
if (total === 0) {
|
|
1553
2525
|
return {
|
|
@@ -1561,12 +2533,13 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1561
2533
|
};
|
|
1562
2534
|
}
|
|
1563
2535
|
const dataRequest = this.pool.request();
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
2536
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2537
|
+
dataRequest.input(key, value);
|
|
2538
|
+
});
|
|
2539
|
+
dataRequest.input("perPage", pagination.perPage);
|
|
2540
|
+
dataRequest.input("offset", pagination.page * pagination.perPage);
|
|
2541
|
+
const dataQuery = `SELECT * FROM ${tableName} WHERE ${whereClause} ORDER BY [createdAt] DESC OFFSET @offset ROWS FETCH NEXT @perPage ROWS ONLY`;
|
|
2542
|
+
const result = await dataRequest.query(dataQuery);
|
|
1570
2543
|
return {
|
|
1571
2544
|
pagination: {
|
|
1572
2545
|
total: Number(total),
|
|
@@ -1746,7 +2719,7 @@ var ScoresMSSQL = class extends storage.ScoresStorage {
|
|
|
1746
2719
|
}
|
|
1747
2720
|
}
|
|
1748
2721
|
};
|
|
1749
|
-
var
|
|
2722
|
+
var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
1750
2723
|
pool;
|
|
1751
2724
|
operations;
|
|
1752
2725
|
schema;
|
|
@@ -1760,207 +2733,164 @@ var TracesMSSQL = class extends storage.TracesStorage {
|
|
|
1760
2733
|
this.operations = operations;
|
|
1761
2734
|
this.schema = schema;
|
|
1762
2735
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
if (
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
const result = await this.getTracesPaginated(args);
|
|
1772
|
-
return result.traces;
|
|
1773
|
-
}
|
|
1774
|
-
async getTracesPaginated(args) {
|
|
1775
|
-
const { name, scope, page = 0, perPage: perPageInput, attributes, filters, dateRange } = args;
|
|
1776
|
-
const fromDate = dateRange?.start;
|
|
1777
|
-
const toDate = dateRange?.end;
|
|
1778
|
-
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1779
|
-
const currentOffset = page * perPage;
|
|
1780
|
-
const paramMap = {};
|
|
1781
|
-
const conditions = [];
|
|
1782
|
-
let paramIndex = 1;
|
|
1783
|
-
if (name) {
|
|
1784
|
-
const paramName = `p${paramIndex++}`;
|
|
1785
|
-
conditions.push(`[name] LIKE @${paramName}`);
|
|
1786
|
-
paramMap[paramName] = `${name}%`;
|
|
1787
|
-
}
|
|
1788
|
-
if (scope) {
|
|
1789
|
-
const paramName = `p${paramIndex++}`;
|
|
1790
|
-
conditions.push(`[scope] = @${paramName}`);
|
|
1791
|
-
paramMap[paramName] = scope;
|
|
1792
|
-
}
|
|
1793
|
-
if (attributes) {
|
|
1794
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
1795
|
-
const parsedKey = utils.parseFieldKey(key);
|
|
1796
|
-
const paramName = `p${paramIndex++}`;
|
|
1797
|
-
conditions.push(`JSON_VALUE([attributes], '$.${parsedKey}') = @${paramName}`);
|
|
1798
|
-
paramMap[paramName] = value;
|
|
1799
|
-
});
|
|
1800
|
-
}
|
|
1801
|
-
if (filters) {
|
|
1802
|
-
Object.entries(filters).forEach(([key, value]) => {
|
|
1803
|
-
const parsedKey = utils.parseFieldKey(key);
|
|
1804
|
-
const paramName = `p${paramIndex++}`;
|
|
1805
|
-
conditions.push(`[${parsedKey}] = @${paramName}`);
|
|
1806
|
-
paramMap[paramName] = value;
|
|
1807
|
-
});
|
|
1808
|
-
}
|
|
1809
|
-
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
1810
|
-
const paramName = `p${paramIndex++}`;
|
|
1811
|
-
conditions.push(`[createdAt] >= @${paramName}`);
|
|
1812
|
-
paramMap[paramName] = fromDate.toISOString();
|
|
1813
|
-
}
|
|
1814
|
-
if (toDate instanceof Date && !isNaN(toDate.getTime())) {
|
|
1815
|
-
const paramName = `p${paramIndex++}`;
|
|
1816
|
-
conditions.push(`[createdAt] <= @${paramName}`);
|
|
1817
|
-
paramMap[paramName] = toDate.toISOString();
|
|
2736
|
+
parseWorkflowRun(row) {
|
|
2737
|
+
let parsedSnapshot = row.snapshot;
|
|
2738
|
+
if (typeof parsedSnapshot === "string") {
|
|
2739
|
+
try {
|
|
2740
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2741
|
+
} catch (e) {
|
|
2742
|
+
this.logger?.warn?.(`Failed to parse snapshot for workflow ${row.workflow_name}:`, e);
|
|
2743
|
+
}
|
|
1818
2744
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
2745
|
+
return {
|
|
2746
|
+
workflowName: row.workflow_name,
|
|
2747
|
+
runId: row.run_id,
|
|
2748
|
+
snapshot: parsedSnapshot,
|
|
2749
|
+
createdAt: row.createdAt,
|
|
2750
|
+
updatedAt: row.updatedAt,
|
|
2751
|
+
resourceId: row.resourceId
|
|
2752
|
+
};
|
|
2753
|
+
}
|
|
2754
|
+
async updateWorkflowResults({
|
|
2755
|
+
workflowName,
|
|
2756
|
+
runId,
|
|
2757
|
+
stepId,
|
|
2758
|
+
result,
|
|
2759
|
+
requestContext
|
|
2760
|
+
}) {
|
|
2761
|
+
const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2762
|
+
const transaction = this.pool.transaction();
|
|
1822
2763
|
try {
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
2764
|
+
await transaction.begin();
|
|
2765
|
+
const selectRequest = new sql2__default.default.Request(transaction);
|
|
2766
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2767
|
+
selectRequest.input("run_id", runId);
|
|
2768
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2769
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2770
|
+
);
|
|
2771
|
+
let snapshot;
|
|
2772
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2773
|
+
snapshot = {
|
|
2774
|
+
context: {},
|
|
2775
|
+
activePaths: [],
|
|
2776
|
+
timestamp: Date.now(),
|
|
2777
|
+
suspendedPaths: {},
|
|
2778
|
+
resumeLabels: {},
|
|
2779
|
+
serializedStepGraph: [],
|
|
2780
|
+
value: {},
|
|
2781
|
+
waitingPaths: {},
|
|
2782
|
+
status: "pending",
|
|
2783
|
+
runId,
|
|
2784
|
+
requestContext: {}
|
|
2785
|
+
};
|
|
2786
|
+
} else {
|
|
2787
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2788
|
+
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2789
|
+
}
|
|
2790
|
+
snapshot.context[stepId] = result;
|
|
2791
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2792
|
+
const upsertReq = new sql2__default.default.Request(transaction);
|
|
2793
|
+
upsertReq.input("workflow_name", workflowName);
|
|
2794
|
+
upsertReq.input("run_id", runId);
|
|
2795
|
+
upsertReq.input("snapshot", JSON.stringify(snapshot));
|
|
2796
|
+
upsertReq.input("createdAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
2797
|
+
upsertReq.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
2798
|
+
await upsertReq.query(
|
|
2799
|
+
`MERGE ${table} AS target
|
|
2800
|
+
USING (SELECT @workflow_name AS workflow_name, @run_id AS run_id) AS src
|
|
2801
|
+
ON target.workflow_name = src.workflow_name AND target.run_id = src.run_id
|
|
2802
|
+
WHEN MATCHED THEN UPDATE SET snapshot = @snapshot, [updatedAt] = @updatedAt
|
|
2803
|
+
WHEN NOT MATCHED THEN INSERT (workflow_name, run_id, snapshot, [createdAt], [updatedAt])
|
|
2804
|
+
VALUES (@workflow_name, @run_id, @snapshot, @createdAt, @updatedAt);`
|
|
2805
|
+
);
|
|
2806
|
+
await transaction.commit();
|
|
2807
|
+
return snapshot.context;
|
|
1833
2808
|
} catch (error$1) {
|
|
2809
|
+
try {
|
|
2810
|
+
await transaction.rollback();
|
|
2811
|
+
} catch {
|
|
2812
|
+
}
|
|
1834
2813
|
throw new error.MastraError(
|
|
1835
2814
|
{
|
|
1836
|
-
id: "
|
|
2815
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_RESULTS_FAILED",
|
|
1837
2816
|
domain: error.ErrorDomain.STORAGE,
|
|
1838
2817
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1839
2818
|
details: {
|
|
1840
|
-
|
|
1841
|
-
|
|
2819
|
+
workflowName,
|
|
2820
|
+
runId,
|
|
2821
|
+
stepId
|
|
1842
2822
|
}
|
|
1843
2823
|
},
|
|
1844
2824
|
error$1
|
|
1845
2825
|
);
|
|
1846
2826
|
}
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
}
|
|
1856
|
-
const dataQuery = `SELECT * FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause} ORDER BY [seq_id] DESC OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
|
1857
|
-
const dataRequest = this.pool.request();
|
|
1858
|
-
Object.entries(paramMap).forEach(([key, value]) => {
|
|
1859
|
-
if (value instanceof Date) {
|
|
1860
|
-
dataRequest.input(key, sql2__default.default.DateTime, value);
|
|
1861
|
-
} else {
|
|
1862
|
-
dataRequest.input(key, value);
|
|
1863
|
-
}
|
|
1864
|
-
});
|
|
1865
|
-
dataRequest.input("offset", currentOffset);
|
|
1866
|
-
dataRequest.input("limit", perPage);
|
|
2827
|
+
}
|
|
2828
|
+
async updateWorkflowState({
|
|
2829
|
+
workflowName,
|
|
2830
|
+
runId,
|
|
2831
|
+
opts
|
|
2832
|
+
}) {
|
|
2833
|
+
const table = getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName(this.schema) });
|
|
2834
|
+
const transaction = this.pool.transaction();
|
|
1867
2835
|
try {
|
|
1868
|
-
|
|
1869
|
-
const
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
2836
|
+
await transaction.begin();
|
|
2837
|
+
const selectRequest = new sql2__default.default.Request(transaction);
|
|
2838
|
+
selectRequest.input("workflow_name", workflowName);
|
|
2839
|
+
selectRequest.input("run_id", runId);
|
|
2840
|
+
const existingSnapshotResult = await selectRequest.query(
|
|
2841
|
+
`SELECT snapshot FROM ${table} WITH (UPDLOCK, HOLDLOCK) WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2842
|
+
);
|
|
2843
|
+
if (!existingSnapshotResult.recordset || existingSnapshotResult.recordset.length === 0) {
|
|
2844
|
+
await transaction.rollback();
|
|
2845
|
+
return void 0;
|
|
2846
|
+
}
|
|
2847
|
+
const existingSnapshot = existingSnapshotResult.recordset[0].snapshot;
|
|
2848
|
+
const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2849
|
+
if (!snapshot || !snapshot?.context) {
|
|
2850
|
+
await transaction.rollback();
|
|
2851
|
+
throw new error.MastraError(
|
|
2852
|
+
{
|
|
2853
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_SNAPSHOT_NOT_FOUND",
|
|
2854
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2855
|
+
category: error.ErrorCategory.SYSTEM,
|
|
2856
|
+
details: {
|
|
2857
|
+
workflowName,
|
|
2858
|
+
runId
|
|
2859
|
+
}
|
|
2860
|
+
},
|
|
2861
|
+
new Error(`Snapshot not found for runId ${runId}`)
|
|
2862
|
+
);
|
|
2863
|
+
}
|
|
2864
|
+
const updatedSnapshot = { ...snapshot, ...opts };
|
|
2865
|
+
const updateRequest = new sql2__default.default.Request(transaction);
|
|
2866
|
+
updateRequest.input("snapshot", JSON.stringify(updatedSnapshot));
|
|
2867
|
+
updateRequest.input("workflow_name", workflowName);
|
|
2868
|
+
updateRequest.input("run_id", runId);
|
|
2869
|
+
updateRequest.input("updatedAt", sql2__default.default.DateTime2, /* @__PURE__ */ new Date());
|
|
2870
|
+
await updateRequest.query(
|
|
2871
|
+
`UPDATE ${table} SET snapshot = @snapshot, [updatedAt] = @updatedAt WHERE workflow_name = @workflow_name AND run_id = @run_id`
|
|
2872
|
+
);
|
|
2873
|
+
await transaction.commit();
|
|
2874
|
+
return updatedSnapshot;
|
|
1893
2875
|
} catch (error$1) {
|
|
2876
|
+
try {
|
|
2877
|
+
await transaction.rollback();
|
|
2878
|
+
} catch {
|
|
2879
|
+
}
|
|
1894
2880
|
throw new error.MastraError(
|
|
1895
2881
|
{
|
|
1896
|
-
id: "
|
|
2882
|
+
id: "MASTRA_STORAGE_MSSQL_STORE_UPDATE_WORKFLOW_STATE_FAILED",
|
|
1897
2883
|
domain: error.ErrorDomain.STORAGE,
|
|
1898
2884
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1899
2885
|
details: {
|
|
1900
|
-
|
|
1901
|
-
|
|
2886
|
+
workflowName,
|
|
2887
|
+
runId
|
|
1902
2888
|
}
|
|
1903
2889
|
},
|
|
1904
2890
|
error$1
|
|
1905
2891
|
);
|
|
1906
2892
|
}
|
|
1907
2893
|
}
|
|
1908
|
-
async batchTraceInsert({ records }) {
|
|
1909
|
-
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1910
|
-
await this.operations.batchInsert({
|
|
1911
|
-
tableName: storage.TABLE_TRACES,
|
|
1912
|
-
records
|
|
1913
|
-
});
|
|
1914
|
-
}
|
|
1915
|
-
};
|
|
1916
|
-
function parseWorkflowRun(row) {
|
|
1917
|
-
let parsedSnapshot = row.snapshot;
|
|
1918
|
-
if (typeof parsedSnapshot === "string") {
|
|
1919
|
-
try {
|
|
1920
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1921
|
-
} catch (e) {
|
|
1922
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
return {
|
|
1926
|
-
workflowName: row.workflow_name,
|
|
1927
|
-
runId: row.run_id,
|
|
1928
|
-
snapshot: parsedSnapshot,
|
|
1929
|
-
createdAt: row.createdAt,
|
|
1930
|
-
updatedAt: row.updatedAt,
|
|
1931
|
-
resourceId: row.resourceId
|
|
1932
|
-
};
|
|
1933
|
-
}
|
|
1934
|
-
var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
1935
|
-
pool;
|
|
1936
|
-
operations;
|
|
1937
|
-
schema;
|
|
1938
|
-
constructor({
|
|
1939
|
-
pool,
|
|
1940
|
-
operations,
|
|
1941
|
-
schema
|
|
1942
|
-
}) {
|
|
1943
|
-
super();
|
|
1944
|
-
this.pool = pool;
|
|
1945
|
-
this.operations = operations;
|
|
1946
|
-
this.schema = schema;
|
|
1947
|
-
}
|
|
1948
|
-
updateWorkflowResults({
|
|
1949
|
-
// workflowName,
|
|
1950
|
-
// runId,
|
|
1951
|
-
// stepId,
|
|
1952
|
-
// result,
|
|
1953
|
-
// runtimeContext,
|
|
1954
|
-
}) {
|
|
1955
|
-
throw new Error("Method not implemented.");
|
|
1956
|
-
}
|
|
1957
|
-
updateWorkflowState({
|
|
1958
|
-
// workflowName,
|
|
1959
|
-
// runId,
|
|
1960
|
-
// opts,
|
|
1961
|
-
}) {
|
|
1962
|
-
throw new Error("Method not implemented.");
|
|
1963
|
-
}
|
|
1964
2894
|
async persistWorkflowSnapshot({
|
|
1965
2895
|
workflowName,
|
|
1966
2896
|
runId,
|
|
@@ -2057,7 +2987,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2057
2987
|
if (!result.recordset || result.recordset.length === 0) {
|
|
2058
2988
|
return null;
|
|
2059
2989
|
}
|
|
2060
|
-
return parseWorkflowRun(result.recordset[0]);
|
|
2990
|
+
return this.parseWorkflowRun(result.recordset[0]);
|
|
2061
2991
|
} catch (error$1) {
|
|
2062
2992
|
throw new error.MastraError(
|
|
2063
2993
|
{
|
|
@@ -2073,7 +3003,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2073
3003
|
);
|
|
2074
3004
|
}
|
|
2075
3005
|
}
|
|
2076
|
-
async
|
|
3006
|
+
async listWorkflowRuns({
|
|
2077
3007
|
workflowName,
|
|
2078
3008
|
fromDate,
|
|
2079
3009
|
toDate,
|
|
@@ -2094,7 +3024,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2094
3024
|
conditions.push(`[resourceId] = @resourceId`);
|
|
2095
3025
|
paramMap["resourceId"] = resourceId;
|
|
2096
3026
|
} else {
|
|
2097
|
-
|
|
3027
|
+
this.logger?.warn?.(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2098
3028
|
}
|
|
2099
3029
|
}
|
|
2100
3030
|
if (fromDate instanceof Date && !isNaN(fromDate.getTime())) {
|
|
@@ -2128,7 +3058,7 @@ var WorkflowsMSSQL = class extends storage.WorkflowsStorage {
|
|
|
2128
3058
|
request.input("offset", offset);
|
|
2129
3059
|
}
|
|
2130
3060
|
const result = await request.query(query);
|
|
2131
|
-
const runs = (result.recordset || []).map((row) => parseWorkflowRun(row));
|
|
3061
|
+
const runs = (result.recordset || []).map((row) => this.parseWorkflowRun(row));
|
|
2132
3062
|
return { runs, total: total || runs.length };
|
|
2133
3063
|
} catch (error$1) {
|
|
2134
3064
|
throw new error.MastraError(
|
|
@@ -2176,19 +3106,17 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2176
3106
|
port: config.port,
|
|
2177
3107
|
options: config.options || { encrypt: true, trustServerCertificate: true }
|
|
2178
3108
|
});
|
|
2179
|
-
const legacyEvals = new LegacyEvalsMSSQL({ pool: this.pool, schema: this.schema });
|
|
2180
3109
|
const operations = new StoreOperationsMSSQL({ pool: this.pool, schemaName: this.schema });
|
|
2181
3110
|
const scores = new ScoresMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2182
|
-
const traces = new TracesMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2183
3111
|
const workflows = new WorkflowsMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2184
3112
|
const memory = new MemoryMSSQL({ pool: this.pool, schema: this.schema, operations });
|
|
3113
|
+
const observability = new ObservabilityMSSQL({ pool: this.pool, operations, schema: this.schema });
|
|
2185
3114
|
this.stores = {
|
|
2186
3115
|
operations,
|
|
2187
3116
|
scores,
|
|
2188
|
-
traces,
|
|
2189
3117
|
workflows,
|
|
2190
|
-
|
|
2191
|
-
|
|
3118
|
+
memory,
|
|
3119
|
+
observability
|
|
2192
3120
|
};
|
|
2193
3121
|
} catch (e) {
|
|
2194
3122
|
throw new error.MastraError(
|
|
@@ -2208,6 +3136,11 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2208
3136
|
try {
|
|
2209
3137
|
await this.isConnected;
|
|
2210
3138
|
await super.init();
|
|
3139
|
+
try {
|
|
3140
|
+
await this.stores.operations.createAutomaticIndexes();
|
|
3141
|
+
} catch (indexError) {
|
|
3142
|
+
this.logger?.warn?.("Failed to create indexes:", indexError);
|
|
3143
|
+
}
|
|
2211
3144
|
} catch (error$1) {
|
|
2212
3145
|
this.isConnected = null;
|
|
2213
3146
|
throw new error.MastraError(
|
|
@@ -2235,28 +3168,11 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2235
3168
|
hasColumn: true,
|
|
2236
3169
|
createTable: true,
|
|
2237
3170
|
deleteMessages: true,
|
|
2238
|
-
getScoresBySpan: true
|
|
3171
|
+
getScoresBySpan: true,
|
|
3172
|
+
aiTracing: true,
|
|
3173
|
+
indexManagement: true
|
|
2239
3174
|
};
|
|
2240
3175
|
}
|
|
2241
|
-
/** @deprecated use getEvals instead */
|
|
2242
|
-
async getEvalsByAgentName(agentName, type) {
|
|
2243
|
-
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2244
|
-
}
|
|
2245
|
-
async getEvals(options = {}) {
|
|
2246
|
-
return this.stores.legacyEvals.getEvals(options);
|
|
2247
|
-
}
|
|
2248
|
-
/**
|
|
2249
|
-
* @deprecated use getTracesPaginated instead
|
|
2250
|
-
*/
|
|
2251
|
-
async getTraces(args) {
|
|
2252
|
-
return this.stores.traces.getTraces(args);
|
|
2253
|
-
}
|
|
2254
|
-
async getTracesPaginated(args) {
|
|
2255
|
-
return this.stores.traces.getTracesPaginated(args);
|
|
2256
|
-
}
|
|
2257
|
-
async batchTraceInsert({ records }) {
|
|
2258
|
-
return this.stores.traces.batchTraceInsert({ records });
|
|
2259
|
-
}
|
|
2260
3176
|
async createTable({
|
|
2261
3177
|
tableName,
|
|
2262
3178
|
schema
|
|
@@ -2316,12 +3232,6 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2316
3232
|
async getMessages(args) {
|
|
2317
3233
|
return this.stores.memory.getMessages(args);
|
|
2318
3234
|
}
|
|
2319
|
-
async getMessagesById({
|
|
2320
|
-
messageIds,
|
|
2321
|
-
format
|
|
2322
|
-
}) {
|
|
2323
|
-
return this.stores.memory.getMessagesById({ messageIds, format });
|
|
2324
|
-
}
|
|
2325
3235
|
async getMessagesPaginated(args) {
|
|
2326
3236
|
return this.stores.memory.getMessagesPaginated(args);
|
|
2327
3237
|
}
|
|
@@ -2357,9 +3267,9 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2357
3267
|
runId,
|
|
2358
3268
|
stepId,
|
|
2359
3269
|
result,
|
|
2360
|
-
|
|
3270
|
+
requestContext
|
|
2361
3271
|
}) {
|
|
2362
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result,
|
|
3272
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2363
3273
|
}
|
|
2364
3274
|
async updateWorkflowState({
|
|
2365
3275
|
workflowName,
|
|
@@ -2382,7 +3292,7 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2382
3292
|
}) {
|
|
2383
3293
|
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2384
3294
|
}
|
|
2385
|
-
async
|
|
3295
|
+
async listWorkflowRuns({
|
|
2386
3296
|
workflowName,
|
|
2387
3297
|
fromDate,
|
|
2388
3298
|
toDate,
|
|
@@ -2390,7 +3300,7 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2390
3300
|
offset,
|
|
2391
3301
|
resourceId
|
|
2392
3302
|
} = {}) {
|
|
2393
|
-
return this.stores.workflows.
|
|
3303
|
+
return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
2394
3304
|
}
|
|
2395
3305
|
async getWorkflowRunById({
|
|
2396
3306
|
runId,
|
|
@@ -2401,6 +3311,60 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2401
3311
|
async close() {
|
|
2402
3312
|
await this.pool.close();
|
|
2403
3313
|
}
|
|
3314
|
+
/**
|
|
3315
|
+
* Index Management
|
|
3316
|
+
*/
|
|
3317
|
+
async createIndex(options) {
|
|
3318
|
+
return this.stores.operations.createIndex(options);
|
|
3319
|
+
}
|
|
3320
|
+
async listIndexes(tableName) {
|
|
3321
|
+
return this.stores.operations.listIndexes(tableName);
|
|
3322
|
+
}
|
|
3323
|
+
async describeIndex(indexName) {
|
|
3324
|
+
return this.stores.operations.describeIndex(indexName);
|
|
3325
|
+
}
|
|
3326
|
+
async dropIndex(indexName) {
|
|
3327
|
+
return this.stores.operations.dropIndex(indexName);
|
|
3328
|
+
}
|
|
3329
|
+
/**
|
|
3330
|
+
* AI Tracing / Observability
|
|
3331
|
+
*/
|
|
3332
|
+
getObservabilityStore() {
|
|
3333
|
+
if (!this.stores.observability) {
|
|
3334
|
+
throw new error.MastraError({
|
|
3335
|
+
id: "MSSQL_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
3336
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3337
|
+
category: error.ErrorCategory.SYSTEM,
|
|
3338
|
+
text: "Observability storage is not initialized"
|
|
3339
|
+
});
|
|
3340
|
+
}
|
|
3341
|
+
return this.stores.observability;
|
|
3342
|
+
}
|
|
3343
|
+
async createAISpan(span) {
|
|
3344
|
+
return this.getObservabilityStore().createAISpan(span);
|
|
3345
|
+
}
|
|
3346
|
+
async updateAISpan({
|
|
3347
|
+
spanId,
|
|
3348
|
+
traceId,
|
|
3349
|
+
updates
|
|
3350
|
+
}) {
|
|
3351
|
+
return this.getObservabilityStore().updateAISpan({ spanId, traceId, updates });
|
|
3352
|
+
}
|
|
3353
|
+
async getAITrace(traceId) {
|
|
3354
|
+
return this.getObservabilityStore().getAITrace(traceId);
|
|
3355
|
+
}
|
|
3356
|
+
async getAITracesPaginated(args) {
|
|
3357
|
+
return this.getObservabilityStore().getAITracesPaginated(args);
|
|
3358
|
+
}
|
|
3359
|
+
async batchCreateAISpans(args) {
|
|
3360
|
+
return this.getObservabilityStore().batchCreateAISpans(args);
|
|
3361
|
+
}
|
|
3362
|
+
async batchUpdateAISpans(args) {
|
|
3363
|
+
return this.getObservabilityStore().batchUpdateAISpans(args);
|
|
3364
|
+
}
|
|
3365
|
+
async batchDeleteAITraces(args) {
|
|
3366
|
+
return this.getObservabilityStore().batchDeleteAITraces(args);
|
|
3367
|
+
}
|
|
2404
3368
|
/**
|
|
2405
3369
|
* Scorers
|
|
2406
3370
|
*/
|
|
@@ -2409,9 +3373,18 @@ var MSSQLStore = class extends storage.MastraStorage {
|
|
|
2409
3373
|
}
|
|
2410
3374
|
async getScoresByScorerId({
|
|
2411
3375
|
scorerId: _scorerId,
|
|
2412
|
-
pagination: _pagination
|
|
3376
|
+
pagination: _pagination,
|
|
3377
|
+
entityId: _entityId,
|
|
3378
|
+
entityType: _entityType,
|
|
3379
|
+
source: _source
|
|
2413
3380
|
}) {
|
|
2414
|
-
return this.stores.scores.getScoresByScorerId({
|
|
3381
|
+
return this.stores.scores.getScoresByScorerId({
|
|
3382
|
+
scorerId: _scorerId,
|
|
3383
|
+
pagination: _pagination,
|
|
3384
|
+
entityId: _entityId,
|
|
3385
|
+
entityType: _entityType,
|
|
3386
|
+
source: _source
|
|
3387
|
+
});
|
|
2415
3388
|
}
|
|
2416
3389
|
async saveScore(_score) {
|
|
2417
3390
|
return this.stores.scores.saveScore(_score);
|