@mastra/clickhouse 0.0.0-vnext-inngest-20250508122351 → 0.0.0-vnext-20251104230439
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 +1080 -2
- package/LICENSE.md +12 -4
- package/dist/index.cjs +2059 -476
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2043 -460
- package/dist/index.js.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +65 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +42 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +54 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +28 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +48 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +194 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/package.json +32 -14
- package/dist/_tsup-dts-rollup.d.cts +0 -138
- package/dist/_tsup-dts-rollup.d.ts +0 -138
- package/dist/index.d.cts +0 -4
- package/docker-compose.yaml +0 -15
- package/eslint.config.js +0 -6
- package/src/index.ts +0 -1
- package/src/storage/index.test.ts +0 -856
- package/src/storage/index.ts +0 -1058
- package/tsconfig.json +0 -5
- package/vitest.config.ts +0 -12
package/dist/index.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { createClient } from '@clickhouse/client';
|
|
2
|
-
import {
|
|
2
|
+
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
+
import { TABLE_AI_SPANS, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_TRACES, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, MastraStorage, StoreOperations, TABLE_SCHEMAS, WorkflowsStorage, normalizePerPage, ScoresStorage, safelyParseJSON, calculatePagination, MemoryStorage, resolveMessageLimit } from '@mastra/core/storage';
|
|
4
|
+
import { MessageList } from '@mastra/core/agent';
|
|
5
|
+
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
3
6
|
|
|
4
7
|
// src/storage/index.ts
|
|
5
|
-
function safelyParseJSON(jsonString) {
|
|
6
|
-
try {
|
|
7
|
-
return JSON.parse(jsonString);
|
|
8
|
-
} catch {
|
|
9
|
-
return {};
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
8
|
var TABLE_ENGINES = {
|
|
13
9
|
[TABLE_MESSAGES]: `MergeTree()`,
|
|
14
10
|
[TABLE_WORKFLOW_SNAPSHOT]: `ReplacingMergeTree()`,
|
|
15
11
|
[TABLE_TRACES]: `MergeTree()`,
|
|
16
12
|
[TABLE_THREADS]: `ReplacingMergeTree()`,
|
|
17
|
-
[
|
|
13
|
+
[TABLE_SCORERS]: `MergeTree()`,
|
|
14
|
+
[TABLE_RESOURCES]: `ReplacingMergeTree()`,
|
|
15
|
+
// TODO: verify this is the correct engine for ai spans when implementing clickhouse storage
|
|
16
|
+
[TABLE_AI_SPANS]: `ReplacingMergeTree()`
|
|
18
17
|
};
|
|
19
18
|
var COLUMN_TYPES = {
|
|
20
19
|
text: "String",
|
|
@@ -22,11 +21,10 @@ var COLUMN_TYPES = {
|
|
|
22
21
|
uuid: "String",
|
|
23
22
|
jsonb: "String",
|
|
24
23
|
integer: "Int64",
|
|
25
|
-
|
|
24
|
+
float: "Float64",
|
|
25
|
+
bigint: "Int64",
|
|
26
|
+
boolean: "Bool"
|
|
26
27
|
};
|
|
27
|
-
function transformRows(rows) {
|
|
28
|
-
return rows.map((row) => transformRow(row));
|
|
29
|
-
}
|
|
30
28
|
function transformRow(row) {
|
|
31
29
|
if (!row) {
|
|
32
30
|
return row;
|
|
@@ -37,54 +35,824 @@ function transformRow(row) {
|
|
|
37
35
|
if (row.updatedAt) {
|
|
38
36
|
row.updatedAt = new Date(row.updatedAt);
|
|
39
37
|
}
|
|
38
|
+
if (row.content && typeof row.content === "string") {
|
|
39
|
+
row.content = safelyParseJSON(row.content);
|
|
40
|
+
}
|
|
40
41
|
return row;
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
43
|
+
function transformRows(rows) {
|
|
44
|
+
return rows.map((row) => transformRow(row));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/storage/domains/memory/index.ts
|
|
48
|
+
var MemoryStorageClickhouse = class extends MemoryStorage {
|
|
49
|
+
client;
|
|
50
|
+
operations;
|
|
51
|
+
constructor({ client, operations }) {
|
|
52
|
+
super();
|
|
53
|
+
this.client = client;
|
|
54
|
+
this.operations = operations;
|
|
55
|
+
}
|
|
56
|
+
async getMessages({
|
|
57
|
+
threadId,
|
|
58
|
+
resourceId,
|
|
59
|
+
selectBy
|
|
60
|
+
}) {
|
|
61
|
+
try {
|
|
62
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
63
|
+
const messages = [];
|
|
64
|
+
const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
65
|
+
const include = selectBy?.include || [];
|
|
66
|
+
if (include.length) {
|
|
67
|
+
const unionQueries = [];
|
|
68
|
+
const params = [];
|
|
69
|
+
let paramIdx = 1;
|
|
70
|
+
for (const inc of include) {
|
|
71
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
72
|
+
const searchId = inc.threadId || threadId;
|
|
73
|
+
unionQueries.push(`
|
|
74
|
+
SELECT * FROM (
|
|
75
|
+
WITH numbered_messages AS (
|
|
76
|
+
SELECT
|
|
77
|
+
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
78
|
+
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
79
|
+
FROM "${TABLE_MESSAGES}"
|
|
80
|
+
WHERE thread_id = {var_thread_id_${paramIdx}:String}
|
|
81
|
+
),
|
|
82
|
+
target_positions AS (
|
|
83
|
+
SELECT row_num as target_pos
|
|
84
|
+
FROM numbered_messages
|
|
85
|
+
WHERE id = {var_include_id_${paramIdx}:String}
|
|
86
|
+
)
|
|
87
|
+
SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId"
|
|
88
|
+
FROM numbered_messages m
|
|
89
|
+
CROSS JOIN target_positions t
|
|
90
|
+
WHERE m.row_num BETWEEN (t.target_pos - {var_withPreviousMessages_${paramIdx}:Int64}) AND (t.target_pos + {var_withNextMessages_${paramIdx}:Int64})
|
|
91
|
+
) AS query_${paramIdx}
|
|
92
|
+
`);
|
|
93
|
+
params.push(
|
|
94
|
+
{ [`var_thread_id_${paramIdx}`]: searchId },
|
|
95
|
+
{ [`var_include_id_${paramIdx}`]: id },
|
|
96
|
+
{ [`var_withPreviousMessages_${paramIdx}`]: withPreviousMessages },
|
|
97
|
+
{ [`var_withNextMessages_${paramIdx}`]: withNextMessages }
|
|
98
|
+
);
|
|
99
|
+
paramIdx++;
|
|
100
|
+
}
|
|
101
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" DESC';
|
|
102
|
+
const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
|
|
103
|
+
const includeResult = await this.client.query({
|
|
104
|
+
query: finalQuery,
|
|
105
|
+
query_params: mergedParams,
|
|
106
|
+
clickhouse_settings: {
|
|
107
|
+
date_time_input_format: "best_effort",
|
|
108
|
+
date_time_output_format: "iso",
|
|
109
|
+
use_client_time_zone: 1,
|
|
110
|
+
output_format_json_quote_64bit_integers: 0
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
const rows2 = await includeResult.json();
|
|
114
|
+
const includedMessages = transformRows(rows2.data);
|
|
115
|
+
const seen = /* @__PURE__ */ new Set();
|
|
116
|
+
const dedupedMessages = includedMessages.filter((message) => {
|
|
117
|
+
if (seen.has(message.id)) return false;
|
|
118
|
+
seen.add(message.id);
|
|
119
|
+
return true;
|
|
120
|
+
});
|
|
121
|
+
messages.push(...dedupedMessages);
|
|
57
122
|
}
|
|
58
|
-
|
|
59
|
-
|
|
123
|
+
let whereClause = "WHERE thread_id = {threadId:String}";
|
|
124
|
+
const queryParams = {
|
|
125
|
+
threadId,
|
|
126
|
+
exclude: messages.map((m) => m.id),
|
|
127
|
+
limit
|
|
128
|
+
};
|
|
129
|
+
if (resourceId) {
|
|
130
|
+
whereClause += ' AND "resourceId" = {resourceId:String}';
|
|
131
|
+
queryParams.resourceId = resourceId;
|
|
132
|
+
}
|
|
133
|
+
const result = await this.client.query({
|
|
134
|
+
query: `
|
|
135
|
+
SELECT
|
|
136
|
+
id,
|
|
137
|
+
content,
|
|
138
|
+
role,
|
|
139
|
+
type,
|
|
140
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
141
|
+
thread_id AS "threadId"
|
|
142
|
+
FROM "${TABLE_MESSAGES}"
|
|
143
|
+
${whereClause}
|
|
144
|
+
AND id NOT IN ({exclude:Array(String)})
|
|
145
|
+
ORDER BY "createdAt" DESC
|
|
146
|
+
LIMIT {limit:Int64}
|
|
147
|
+
`,
|
|
148
|
+
query_params: queryParams,
|
|
149
|
+
clickhouse_settings: {
|
|
150
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
151
|
+
date_time_input_format: "best_effort",
|
|
152
|
+
date_time_output_format: "iso",
|
|
153
|
+
use_client_time_zone: 1,
|
|
154
|
+
output_format_json_quote_64bit_integers: 0
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const rows = await result.json();
|
|
158
|
+
messages.push(...transformRows(rows.data));
|
|
159
|
+
messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
160
|
+
messages.forEach((message) => {
|
|
161
|
+
if (typeof message.content === "string") {
|
|
162
|
+
try {
|
|
163
|
+
message.content = JSON.parse(message.content);
|
|
164
|
+
} catch {
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
const list = new MessageList({ threadId, resourceId }).add(
|
|
169
|
+
messages,
|
|
170
|
+
"memory"
|
|
171
|
+
);
|
|
172
|
+
return { messages: list.get.all.db() };
|
|
173
|
+
} catch (error) {
|
|
174
|
+
throw new MastraError(
|
|
175
|
+
{
|
|
176
|
+
id: "CLICKHOUSE_STORAGE_GET_MESSAGES_FAILED",
|
|
177
|
+
domain: ErrorDomain.STORAGE,
|
|
178
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
179
|
+
details: { threadId, resourceId: resourceId ?? "" }
|
|
180
|
+
},
|
|
181
|
+
error
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async listMessagesById({ messageIds }) {
|
|
186
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
187
|
+
try {
|
|
188
|
+
const result = await this.client.query({
|
|
189
|
+
query: `
|
|
190
|
+
SELECT
|
|
191
|
+
id,
|
|
192
|
+
content,
|
|
193
|
+
role,
|
|
194
|
+
type,
|
|
195
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
196
|
+
thread_id AS "threadId",
|
|
197
|
+
"resourceId"
|
|
198
|
+
FROM "${TABLE_MESSAGES}"
|
|
199
|
+
WHERE id IN {messageIds:Array(String)}
|
|
200
|
+
ORDER BY "createdAt" DESC
|
|
201
|
+
`,
|
|
202
|
+
query_params: {
|
|
203
|
+
messageIds
|
|
204
|
+
},
|
|
205
|
+
clickhouse_settings: {
|
|
206
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
207
|
+
date_time_input_format: "best_effort",
|
|
208
|
+
date_time_output_format: "iso",
|
|
209
|
+
use_client_time_zone: 1,
|
|
210
|
+
output_format_json_quote_64bit_integers: 0
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
const rows = await result.json();
|
|
214
|
+
const messages = transformRows(rows.data);
|
|
215
|
+
messages.forEach((message) => {
|
|
216
|
+
if (typeof message.content === "string") {
|
|
217
|
+
try {
|
|
218
|
+
message.content = JSON.parse(message.content);
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
const list = new MessageList().add(messages, "memory");
|
|
224
|
+
return { messages: list.get.all.db() };
|
|
225
|
+
} catch (error) {
|
|
226
|
+
throw new MastraError(
|
|
227
|
+
{
|
|
228
|
+
id: "CLICKHOUSE_STORAGE_LIST_MESSAGES_BY_ID_FAILED",
|
|
229
|
+
domain: ErrorDomain.STORAGE,
|
|
230
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
231
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
232
|
+
},
|
|
233
|
+
error
|
|
234
|
+
);
|
|
235
|
+
}
|
|
60
236
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
237
|
+
async listMessages(args) {
|
|
238
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
239
|
+
if (page < 0) {
|
|
240
|
+
throw new MastraError(
|
|
241
|
+
{
|
|
242
|
+
id: "STORAGE_CLICKHOUSE_LIST_MESSAGES_INVALID_PAGE",
|
|
243
|
+
domain: ErrorDomain.STORAGE,
|
|
244
|
+
category: ErrorCategory.USER,
|
|
245
|
+
details: { page }
|
|
246
|
+
},
|
|
247
|
+
new Error("page must be >= 0")
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
if (!threadId.trim()) {
|
|
251
|
+
throw new MastraError(
|
|
252
|
+
{
|
|
253
|
+
id: "STORAGE_CLICKHOUSE_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
254
|
+
domain: ErrorDomain.STORAGE,
|
|
255
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
256
|
+
details: { threadId }
|
|
257
|
+
},
|
|
258
|
+
new Error("threadId must be a non-empty string")
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const perPageForQuery = normalizePerPage(perPageInput, 40);
|
|
262
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPageForQuery);
|
|
263
|
+
try {
|
|
264
|
+
let dataQuery = `
|
|
265
|
+
SELECT
|
|
266
|
+
id,
|
|
267
|
+
content,
|
|
268
|
+
role,
|
|
269
|
+
type,
|
|
270
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
271
|
+
thread_id AS "threadId",
|
|
272
|
+
resourceId
|
|
273
|
+
FROM ${TABLE_MESSAGES}
|
|
274
|
+
WHERE thread_id = {threadId:String}
|
|
275
|
+
`;
|
|
276
|
+
const dataParams = { threadId };
|
|
277
|
+
if (resourceId) {
|
|
278
|
+
dataQuery += ` AND resourceId = {resourceId:String}`;
|
|
279
|
+
dataParams.resourceId = resourceId;
|
|
280
|
+
}
|
|
281
|
+
if (filter?.dateRange?.start) {
|
|
282
|
+
const startDate = filter.dateRange.start instanceof Date ? filter.dateRange.start.toISOString() : new Date(filter.dateRange.start).toISOString();
|
|
283
|
+
dataQuery += ` AND createdAt >= parseDateTime64BestEffort({fromDate:String}, 3)`;
|
|
284
|
+
dataParams.fromDate = startDate;
|
|
285
|
+
}
|
|
286
|
+
if (filter?.dateRange?.end) {
|
|
287
|
+
const endDate = filter.dateRange.end instanceof Date ? filter.dateRange.end.toISOString() : new Date(filter.dateRange.end).toISOString();
|
|
288
|
+
dataQuery += ` AND createdAt <= parseDateTime64BestEffort({toDate:String}, 3)`;
|
|
289
|
+
dataParams.toDate = endDate;
|
|
290
|
+
}
|
|
291
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
292
|
+
dataQuery += ` ORDER BY "${field}" ${direction}`;
|
|
293
|
+
if (perPageForResponse === false) ; else {
|
|
294
|
+
dataQuery += ` LIMIT {limit:Int64} OFFSET {offset:Int64}`;
|
|
295
|
+
dataParams.limit = perPageForQuery;
|
|
296
|
+
dataParams.offset = offset;
|
|
297
|
+
}
|
|
298
|
+
const result = await this.client.query({
|
|
299
|
+
query: dataQuery,
|
|
300
|
+
query_params: dataParams,
|
|
301
|
+
clickhouse_settings: {
|
|
302
|
+
date_time_input_format: "best_effort",
|
|
303
|
+
date_time_output_format: "iso",
|
|
304
|
+
use_client_time_zone: 1,
|
|
305
|
+
output_format_json_quote_64bit_integers: 0
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
const rows = await result.json();
|
|
309
|
+
const paginatedMessages = transformRows(rows.data);
|
|
310
|
+
const paginatedCount = paginatedMessages.length;
|
|
311
|
+
let countQuery = `SELECT count() as total FROM ${TABLE_MESSAGES} WHERE thread_id = {threadId:String}`;
|
|
312
|
+
const countParams = { threadId };
|
|
313
|
+
if (resourceId) {
|
|
314
|
+
countQuery += ` AND resourceId = {resourceId:String}`;
|
|
315
|
+
countParams.resourceId = resourceId;
|
|
316
|
+
}
|
|
317
|
+
if (filter?.dateRange?.start) {
|
|
318
|
+
const startDate = filter.dateRange.start instanceof Date ? filter.dateRange.start.toISOString() : new Date(filter.dateRange.start).toISOString();
|
|
319
|
+
countQuery += ` AND createdAt >= parseDateTime64BestEffort({fromDate:String}, 3)`;
|
|
320
|
+
countParams.fromDate = startDate;
|
|
321
|
+
}
|
|
322
|
+
if (filter?.dateRange?.end) {
|
|
323
|
+
const endDate = filter.dateRange.end instanceof Date ? filter.dateRange.end.toISOString() : new Date(filter.dateRange.end).toISOString();
|
|
324
|
+
countQuery += ` AND createdAt <= parseDateTime64BestEffort({toDate:String}, 3)`;
|
|
325
|
+
countParams.toDate = endDate;
|
|
326
|
+
}
|
|
327
|
+
const countResult = await this.client.query({
|
|
328
|
+
query: countQuery,
|
|
329
|
+
query_params: countParams,
|
|
330
|
+
clickhouse_settings: {
|
|
331
|
+
date_time_input_format: "best_effort",
|
|
332
|
+
date_time_output_format: "iso",
|
|
333
|
+
use_client_time_zone: 1,
|
|
334
|
+
output_format_json_quote_64bit_integers: 0
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
const countData = await countResult.json();
|
|
338
|
+
const total = countData.data[0].total;
|
|
339
|
+
if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
|
|
340
|
+
return {
|
|
341
|
+
messages: [],
|
|
342
|
+
total: 0,
|
|
343
|
+
page,
|
|
344
|
+
perPage: perPageForResponse,
|
|
345
|
+
hasMore: false
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
349
|
+
let includeMessages = [];
|
|
350
|
+
if (include && include.length > 0) {
|
|
351
|
+
const unionQueries = [];
|
|
352
|
+
const params = [];
|
|
353
|
+
let paramIdx = 1;
|
|
354
|
+
for (const inc of include) {
|
|
355
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
356
|
+
const searchId = inc.threadId || threadId;
|
|
357
|
+
unionQueries.push(`
|
|
358
|
+
SELECT * FROM (
|
|
359
|
+
WITH numbered_messages AS (
|
|
360
|
+
SELECT
|
|
361
|
+
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
362
|
+
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
363
|
+
FROM "${TABLE_MESSAGES}"
|
|
364
|
+
WHERE thread_id = {var_thread_id_${paramIdx}:String}
|
|
365
|
+
),
|
|
366
|
+
target_positions AS (
|
|
367
|
+
SELECT row_num as target_pos
|
|
368
|
+
FROM numbered_messages
|
|
369
|
+
WHERE id = {var_include_id_${paramIdx}:String}
|
|
370
|
+
)
|
|
371
|
+
SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId", m."resourceId"
|
|
372
|
+
FROM numbered_messages m
|
|
373
|
+
CROSS JOIN target_positions t
|
|
374
|
+
WHERE m.row_num BETWEEN (t.target_pos - {var_withPreviousMessages_${paramIdx}:Int64}) AND (t.target_pos + {var_withNextMessages_${paramIdx}:Int64})
|
|
375
|
+
) AS query_${paramIdx}
|
|
376
|
+
`);
|
|
377
|
+
params.push(
|
|
378
|
+
{ [`var_thread_id_${paramIdx}`]: searchId },
|
|
379
|
+
{ [`var_include_id_${paramIdx}`]: id },
|
|
380
|
+
{ [`var_withPreviousMessages_${paramIdx}`]: withPreviousMessages },
|
|
381
|
+
{ [`var_withNextMessages_${paramIdx}`]: withNextMessages }
|
|
382
|
+
);
|
|
383
|
+
paramIdx++;
|
|
384
|
+
}
|
|
385
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
386
|
+
const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
|
|
387
|
+
const includeResult = await this.client.query({
|
|
388
|
+
query: finalQuery,
|
|
389
|
+
query_params: mergedParams,
|
|
390
|
+
clickhouse_settings: {
|
|
391
|
+
date_time_input_format: "best_effort",
|
|
392
|
+
date_time_output_format: "iso",
|
|
393
|
+
use_client_time_zone: 1,
|
|
394
|
+
output_format_json_quote_64bit_integers: 0
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
const includeRows = await includeResult.json();
|
|
398
|
+
includeMessages = transformRows(includeRows.data);
|
|
399
|
+
for (const includeMsg of includeMessages) {
|
|
400
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
401
|
+
paginatedMessages.push(includeMsg);
|
|
402
|
+
messageIds.add(includeMsg.id);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const list = new MessageList().add(paginatedMessages, "memory");
|
|
407
|
+
let finalMessages = list.get.all.db();
|
|
408
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
409
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
410
|
+
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
411
|
+
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
412
|
+
if (aValue === bValue) {
|
|
413
|
+
return a.id.localeCompare(b.id);
|
|
414
|
+
}
|
|
415
|
+
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
416
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
417
|
+
}
|
|
418
|
+
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
419
|
+
});
|
|
420
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
421
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
422
|
+
const hasMore = perPageForResponse === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
|
|
423
|
+
return {
|
|
424
|
+
messages: finalMessages,
|
|
425
|
+
total,
|
|
426
|
+
page,
|
|
427
|
+
perPage: perPageForResponse,
|
|
428
|
+
hasMore
|
|
429
|
+
};
|
|
430
|
+
} catch (error) {
|
|
431
|
+
const mastraError = new MastraError(
|
|
432
|
+
{
|
|
433
|
+
id: "STORAGE_CLICKHOUSE_STORE_LIST_MESSAGES_FAILED",
|
|
434
|
+
domain: ErrorDomain.STORAGE,
|
|
435
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
436
|
+
details: {
|
|
437
|
+
threadId,
|
|
438
|
+
resourceId: resourceId ?? ""
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
error
|
|
442
|
+
);
|
|
443
|
+
this.logger?.error?.(mastraError.toString());
|
|
444
|
+
this.logger?.trackException?.(mastraError);
|
|
445
|
+
return {
|
|
446
|
+
messages: [],
|
|
447
|
+
total: 0,
|
|
448
|
+
page,
|
|
449
|
+
perPage: perPageForResponse,
|
|
450
|
+
hasMore: false
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
async saveMessages(args) {
|
|
455
|
+
const { messages } = args;
|
|
456
|
+
if (messages.length === 0) return { messages };
|
|
457
|
+
for (const message of messages) {
|
|
458
|
+
const resourceId = message.resourceId;
|
|
459
|
+
if (!resourceId) {
|
|
460
|
+
throw new Error("Resource ID is required");
|
|
461
|
+
}
|
|
462
|
+
if (!message.threadId) {
|
|
463
|
+
throw new Error("Thread ID is required");
|
|
464
|
+
}
|
|
465
|
+
const thread = await this.getThreadById({ threadId: message.threadId });
|
|
466
|
+
if (!thread) {
|
|
467
|
+
throw new Error(`Thread ${message.threadId} not found`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const threadIdSet = /* @__PURE__ */ new Map();
|
|
471
|
+
await Promise.all(
|
|
472
|
+
messages.map(async (m) => {
|
|
473
|
+
const resourceId = m.resourceId;
|
|
474
|
+
if (!resourceId) {
|
|
475
|
+
throw new Error("Resource ID is required");
|
|
476
|
+
}
|
|
477
|
+
if (!m.threadId) {
|
|
478
|
+
throw new Error("Thread ID is required");
|
|
479
|
+
}
|
|
480
|
+
const thread = await this.getThreadById({ threadId: m.threadId });
|
|
481
|
+
if (!thread) {
|
|
482
|
+
throw new Error(`Thread ${m.threadId} not found`);
|
|
483
|
+
}
|
|
484
|
+
threadIdSet.set(m.threadId, thread);
|
|
485
|
+
})
|
|
486
|
+
);
|
|
487
|
+
try {
|
|
488
|
+
const existingResult = await this.client.query({
|
|
489
|
+
query: `SELECT id, thread_id FROM ${TABLE_MESSAGES} WHERE id IN ({ids:Array(String)})`,
|
|
490
|
+
query_params: {
|
|
491
|
+
ids: messages.map((m) => m.id)
|
|
492
|
+
},
|
|
493
|
+
clickhouse_settings: {
|
|
494
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
495
|
+
date_time_input_format: "best_effort",
|
|
496
|
+
date_time_output_format: "iso",
|
|
497
|
+
use_client_time_zone: 1,
|
|
498
|
+
output_format_json_quote_64bit_integers: 0
|
|
499
|
+
},
|
|
500
|
+
format: "JSONEachRow"
|
|
501
|
+
});
|
|
502
|
+
const existingRows = await existingResult.json();
|
|
503
|
+
const existingSet = new Set(existingRows.map((row) => `${row.id}::${row.thread_id}`));
|
|
504
|
+
const toInsert = messages.filter((m) => !existingSet.has(`${m.id}::${m.threadId}`));
|
|
505
|
+
const toUpdate = messages.filter((m) => existingSet.has(`${m.id}::${m.threadId}`));
|
|
506
|
+
const toMove = messages.filter((m) => {
|
|
507
|
+
const existingRow = existingRows.find((row) => row.id === m.id);
|
|
508
|
+
return existingRow && existingRow.thread_id !== m.threadId;
|
|
509
|
+
});
|
|
510
|
+
const deletePromises = toMove.map((message) => {
|
|
511
|
+
const existingRow = existingRows.find((row) => row.id === message.id);
|
|
512
|
+
if (!existingRow) return Promise.resolve();
|
|
513
|
+
return this.client.command({
|
|
514
|
+
query: `DELETE FROM ${TABLE_MESSAGES} WHERE id = {var_id:String} AND thread_id = {var_old_thread_id:String}`,
|
|
515
|
+
query_params: {
|
|
516
|
+
var_id: message.id,
|
|
517
|
+
var_old_thread_id: existingRow.thread_id
|
|
518
|
+
},
|
|
519
|
+
clickhouse_settings: {
|
|
520
|
+
date_time_input_format: "best_effort",
|
|
521
|
+
use_client_time_zone: 1,
|
|
522
|
+
output_format_json_quote_64bit_integers: 0
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
const updatePromises = toUpdate.map(
|
|
527
|
+
(message) => this.client.command({
|
|
528
|
+
query: `
|
|
529
|
+
ALTER TABLE ${TABLE_MESSAGES}
|
|
530
|
+
UPDATE content = {var_content:String}, role = {var_role:String}, type = {var_type:String}, resourceId = {var_resourceId:String}
|
|
531
|
+
WHERE id = {var_id:String} AND thread_id = {var_thread_id:String}
|
|
532
|
+
`,
|
|
533
|
+
query_params: {
|
|
534
|
+
var_content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
535
|
+
var_role: message.role,
|
|
536
|
+
var_type: message.type || "v2",
|
|
537
|
+
var_resourceId: message.resourceId,
|
|
538
|
+
var_id: message.id,
|
|
539
|
+
var_thread_id: message.threadId
|
|
540
|
+
},
|
|
541
|
+
clickhouse_settings: {
|
|
542
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
543
|
+
date_time_input_format: "best_effort",
|
|
544
|
+
use_client_time_zone: 1,
|
|
545
|
+
output_format_json_quote_64bit_integers: 0
|
|
546
|
+
}
|
|
547
|
+
})
|
|
548
|
+
);
|
|
549
|
+
await Promise.all([
|
|
550
|
+
// Insert new messages (including moved messages)
|
|
551
|
+
this.client.insert({
|
|
552
|
+
table: TABLE_MESSAGES,
|
|
553
|
+
format: "JSONEachRow",
|
|
554
|
+
values: toInsert.map((message) => ({
|
|
555
|
+
id: message.id,
|
|
556
|
+
thread_id: message.threadId,
|
|
557
|
+
resourceId: message.resourceId,
|
|
558
|
+
content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
559
|
+
createdAt: message.createdAt.toISOString(),
|
|
560
|
+
role: message.role,
|
|
561
|
+
type: message.type || "v2"
|
|
562
|
+
})),
|
|
563
|
+
clickhouse_settings: {
|
|
564
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
565
|
+
date_time_input_format: "best_effort",
|
|
566
|
+
use_client_time_zone: 1,
|
|
567
|
+
output_format_json_quote_64bit_integers: 0
|
|
568
|
+
}
|
|
569
|
+
}),
|
|
570
|
+
...updatePromises,
|
|
571
|
+
...deletePromises,
|
|
572
|
+
// Update thread's updatedAt timestamp
|
|
573
|
+
this.client.insert({
|
|
574
|
+
table: TABLE_THREADS,
|
|
575
|
+
format: "JSONEachRow",
|
|
576
|
+
values: Array.from(threadIdSet.values()).map((thread) => ({
|
|
577
|
+
id: thread.id,
|
|
578
|
+
resourceId: thread.resourceId,
|
|
579
|
+
title: thread.title,
|
|
580
|
+
metadata: thread.metadata,
|
|
581
|
+
createdAt: thread.createdAt,
|
|
582
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
583
|
+
})),
|
|
584
|
+
clickhouse_settings: {
|
|
585
|
+
date_time_input_format: "best_effort",
|
|
586
|
+
use_client_time_zone: 1,
|
|
587
|
+
output_format_json_quote_64bit_integers: 0
|
|
588
|
+
}
|
|
589
|
+
})
|
|
590
|
+
]);
|
|
591
|
+
const list = new MessageList().add(messages, "memory");
|
|
592
|
+
return { messages: list.get.all.db() };
|
|
593
|
+
} catch (error) {
|
|
594
|
+
throw new MastraError(
|
|
595
|
+
{
|
|
596
|
+
id: "CLICKHOUSE_STORAGE_SAVE_MESSAGES_FAILED",
|
|
597
|
+
domain: ErrorDomain.STORAGE,
|
|
598
|
+
category: ErrorCategory.THIRD_PARTY
|
|
599
|
+
},
|
|
600
|
+
error
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
async getThreadById({ threadId }) {
|
|
605
|
+
try {
|
|
606
|
+
const result = await this.client.query({
|
|
607
|
+
query: `SELECT
|
|
608
|
+
id,
|
|
609
|
+
"resourceId",
|
|
610
|
+
title,
|
|
611
|
+
metadata,
|
|
612
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
613
|
+
toDateTime64(updatedAt, 3) as updatedAt
|
|
614
|
+
FROM "${TABLE_THREADS}"
|
|
615
|
+
FINAL
|
|
616
|
+
WHERE id = {var_id:String}`,
|
|
617
|
+
query_params: { var_id: threadId },
|
|
618
|
+
clickhouse_settings: {
|
|
619
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
620
|
+
date_time_input_format: "best_effort",
|
|
621
|
+
date_time_output_format: "iso",
|
|
622
|
+
use_client_time_zone: 1,
|
|
623
|
+
output_format_json_quote_64bit_integers: 0
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
const rows = await result.json();
|
|
627
|
+
const thread = transformRow(rows.data[0]);
|
|
628
|
+
if (!thread) {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
return {
|
|
632
|
+
...thread,
|
|
633
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
634
|
+
createdAt: thread.createdAt,
|
|
635
|
+
updatedAt: thread.updatedAt
|
|
636
|
+
};
|
|
637
|
+
} catch (error) {
|
|
638
|
+
throw new MastraError(
|
|
639
|
+
{
|
|
640
|
+
id: "CLICKHOUSE_STORAGE_GET_THREAD_BY_ID_FAILED",
|
|
641
|
+
domain: ErrorDomain.STORAGE,
|
|
642
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
643
|
+
details: { threadId }
|
|
644
|
+
},
|
|
645
|
+
error
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
async saveThread({ thread }) {
|
|
650
|
+
try {
|
|
651
|
+
await this.client.insert({
|
|
652
|
+
table: TABLE_THREADS,
|
|
653
|
+
values: [
|
|
654
|
+
{
|
|
655
|
+
...thread,
|
|
656
|
+
createdAt: thread.createdAt.toISOString(),
|
|
657
|
+
updatedAt: thread.updatedAt.toISOString()
|
|
658
|
+
}
|
|
659
|
+
],
|
|
660
|
+
format: "JSONEachRow",
|
|
661
|
+
clickhouse_settings: {
|
|
662
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
663
|
+
date_time_input_format: "best_effort",
|
|
664
|
+
use_client_time_zone: 1,
|
|
665
|
+
output_format_json_quote_64bit_integers: 0
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
return thread;
|
|
669
|
+
} catch (error) {
|
|
670
|
+
throw new MastraError(
|
|
671
|
+
{
|
|
672
|
+
id: "CLICKHOUSE_STORAGE_SAVE_THREAD_FAILED",
|
|
673
|
+
domain: ErrorDomain.STORAGE,
|
|
674
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
675
|
+
details: { threadId: thread.id }
|
|
676
|
+
},
|
|
677
|
+
error
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
async updateThread({
|
|
682
|
+
id,
|
|
683
|
+
title,
|
|
684
|
+
metadata
|
|
685
|
+
}) {
|
|
686
|
+
try {
|
|
687
|
+
const existingThread = await this.getThreadById({ threadId: id });
|
|
688
|
+
if (!existingThread) {
|
|
689
|
+
throw new Error(`Thread ${id} not found`);
|
|
690
|
+
}
|
|
691
|
+
const mergedMetadata = {
|
|
692
|
+
...existingThread.metadata,
|
|
693
|
+
...metadata
|
|
694
|
+
};
|
|
695
|
+
const updatedThread = {
|
|
696
|
+
...existingThread,
|
|
697
|
+
title,
|
|
698
|
+
metadata: mergedMetadata,
|
|
699
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
700
|
+
};
|
|
701
|
+
await this.client.insert({
|
|
702
|
+
table: TABLE_THREADS,
|
|
703
|
+
format: "JSONEachRow",
|
|
704
|
+
values: [
|
|
705
|
+
{
|
|
706
|
+
id: updatedThread.id,
|
|
707
|
+
resourceId: updatedThread.resourceId,
|
|
708
|
+
title: updatedThread.title,
|
|
709
|
+
metadata: updatedThread.metadata,
|
|
710
|
+
createdAt: updatedThread.createdAt,
|
|
711
|
+
updatedAt: updatedThread.updatedAt.toISOString()
|
|
712
|
+
}
|
|
713
|
+
],
|
|
714
|
+
clickhouse_settings: {
|
|
715
|
+
date_time_input_format: "best_effort",
|
|
716
|
+
use_client_time_zone: 1,
|
|
717
|
+
output_format_json_quote_64bit_integers: 0
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
return updatedThread;
|
|
721
|
+
} catch (error) {
|
|
722
|
+
throw new MastraError(
|
|
723
|
+
{
|
|
724
|
+
id: "CLICKHOUSE_STORAGE_UPDATE_THREAD_FAILED",
|
|
725
|
+
domain: ErrorDomain.STORAGE,
|
|
726
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
727
|
+
details: { threadId: id, title }
|
|
728
|
+
},
|
|
729
|
+
error
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async deleteThread({ threadId }) {
|
|
734
|
+
try {
|
|
735
|
+
await this.client.command({
|
|
736
|
+
query: `DELETE FROM "${TABLE_MESSAGES}" WHERE thread_id = {var_thread_id:String};`,
|
|
737
|
+
query_params: { var_thread_id: threadId },
|
|
738
|
+
clickhouse_settings: {
|
|
739
|
+
output_format_json_quote_64bit_integers: 0
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
await this.client.command({
|
|
743
|
+
query: `DELETE FROM "${TABLE_THREADS}" WHERE id = {var_id:String};`,
|
|
744
|
+
query_params: { var_id: threadId },
|
|
745
|
+
clickhouse_settings: {
|
|
746
|
+
output_format_json_quote_64bit_integers: 0
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
} catch (error) {
|
|
750
|
+
throw new MastraError(
|
|
751
|
+
{
|
|
752
|
+
id: "CLICKHOUSE_STORAGE_DELETE_THREAD_FAILED",
|
|
753
|
+
domain: ErrorDomain.STORAGE,
|
|
754
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
755
|
+
details: { threadId }
|
|
756
|
+
},
|
|
757
|
+
error
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
async listThreadsByResourceId(args) {
|
|
762
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
763
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
764
|
+
if (page < 0) {
|
|
765
|
+
throw new MastraError(
|
|
766
|
+
{
|
|
767
|
+
id: "STORAGE_CLICKHOUSE_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
|
|
768
|
+
domain: ErrorDomain.STORAGE,
|
|
769
|
+
category: ErrorCategory.USER,
|
|
770
|
+
details: { page }
|
|
771
|
+
},
|
|
772
|
+
new Error("page must be >= 0")
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
776
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
777
|
+
try {
|
|
778
|
+
const countResult = await this.client.query({
|
|
779
|
+
query: `SELECT count() as total FROM ${TABLE_THREADS} WHERE resourceId = {resourceId:String}`,
|
|
780
|
+
query_params: { resourceId },
|
|
781
|
+
clickhouse_settings: {
|
|
782
|
+
date_time_input_format: "best_effort",
|
|
783
|
+
date_time_output_format: "iso",
|
|
784
|
+
use_client_time_zone: 1,
|
|
785
|
+
output_format_json_quote_64bit_integers: 0
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
const countData = await countResult.json();
|
|
789
|
+
const total = countData.data[0].total;
|
|
790
|
+
if (total === 0) {
|
|
791
|
+
return {
|
|
792
|
+
threads: [],
|
|
793
|
+
total: 0,
|
|
794
|
+
page,
|
|
795
|
+
perPage: perPageForResponse,
|
|
796
|
+
hasMore: false
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
const dataResult = await this.client.query({
|
|
800
|
+
query: `
|
|
801
|
+
SELECT
|
|
802
|
+
id,
|
|
803
|
+
resourceId,
|
|
804
|
+
title,
|
|
805
|
+
metadata,
|
|
806
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
807
|
+
toDateTime64(updatedAt, 3) as updatedAt
|
|
808
|
+
FROM ${TABLE_THREADS}
|
|
809
|
+
WHERE resourceId = {resourceId:String}
|
|
810
|
+
ORDER BY "${field}" ${direction === "DESC" ? "DESC" : "ASC"}
|
|
811
|
+
LIMIT {perPage:Int64} OFFSET {offset:Int64}
|
|
812
|
+
`,
|
|
813
|
+
query_params: {
|
|
814
|
+
resourceId,
|
|
815
|
+
perPage,
|
|
816
|
+
offset
|
|
817
|
+
},
|
|
818
|
+
clickhouse_settings: {
|
|
819
|
+
date_time_input_format: "best_effort",
|
|
820
|
+
date_time_output_format: "iso",
|
|
821
|
+
use_client_time_zone: 1,
|
|
822
|
+
output_format_json_quote_64bit_integers: 0
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
const rows = await dataResult.json();
|
|
826
|
+
const threads = transformRows(rows.data);
|
|
827
|
+
return {
|
|
828
|
+
threads,
|
|
829
|
+
total,
|
|
830
|
+
page,
|
|
831
|
+
perPage: perPageForResponse,
|
|
832
|
+
hasMore: offset + perPage < total
|
|
833
|
+
};
|
|
834
|
+
} catch (error) {
|
|
835
|
+
throw new MastraError(
|
|
836
|
+
{
|
|
837
|
+
id: "CLICKHOUSE_STORAGE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
|
|
838
|
+
domain: ErrorDomain.STORAGE,
|
|
839
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
840
|
+
details: { resourceId, page }
|
|
841
|
+
},
|
|
842
|
+
error
|
|
843
|
+
);
|
|
67
844
|
}
|
|
68
|
-
return {
|
|
69
|
-
input: row.input,
|
|
70
|
-
output: row.output,
|
|
71
|
-
result: resultValue,
|
|
72
|
-
agentName: row.agent_name,
|
|
73
|
-
metricName: row.metric_name,
|
|
74
|
-
instructions: row.instructions,
|
|
75
|
-
testInfo: testInfoValue,
|
|
76
|
-
globalRunId: row.global_run_id,
|
|
77
|
-
runId: row.run_id,
|
|
78
|
-
createdAt: row.created_at
|
|
79
|
-
};
|
|
80
845
|
}
|
|
81
|
-
async
|
|
846
|
+
async updateMessages(args) {
|
|
847
|
+
const { messages } = args;
|
|
848
|
+
if (messages.length === 0) {
|
|
849
|
+
return [];
|
|
850
|
+
}
|
|
82
851
|
try {
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
query_params: { var_agent_name: agentName },
|
|
852
|
+
const messageIds = messages.map((m) => m.id);
|
|
853
|
+
const existingResult = await this.client.query({
|
|
854
|
+
query: `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId" FROM ${TABLE_MESSAGES} WHERE id IN (${messageIds.map((_, i) => `{id_${i}:String}`).join(",")})`,
|
|
855
|
+
query_params: messageIds.reduce((acc, m, i) => ({ ...acc, [`id_${i}`]: m }), {}),
|
|
88
856
|
clickhouse_settings: {
|
|
89
857
|
date_time_input_format: "best_effort",
|
|
90
858
|
date_time_output_format: "iso",
|
|
@@ -92,131 +860,437 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
92
860
|
output_format_json_quote_64bit_integers: 0
|
|
93
861
|
}
|
|
94
862
|
});
|
|
95
|
-
|
|
863
|
+
const existingRows = await existingResult.json();
|
|
864
|
+
const existingMessages = transformRows(existingRows.data);
|
|
865
|
+
if (existingMessages.length === 0) {
|
|
96
866
|
return [];
|
|
97
867
|
}
|
|
98
|
-
const
|
|
99
|
-
|
|
868
|
+
const parsedExistingMessages = existingMessages.map((msg) => {
|
|
869
|
+
if (typeof msg.content === "string") {
|
|
870
|
+
try {
|
|
871
|
+
msg.content = JSON.parse(msg.content);
|
|
872
|
+
} catch {
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return msg;
|
|
876
|
+
});
|
|
877
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
878
|
+
const updatePromises = [];
|
|
879
|
+
for (const existingMessage of parsedExistingMessages) {
|
|
880
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
881
|
+
if (!updatePayload) continue;
|
|
882
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
883
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
884
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
885
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
886
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
887
|
+
}
|
|
888
|
+
const setClauses = [];
|
|
889
|
+
const values = {};
|
|
890
|
+
let paramIdx = 1;
|
|
891
|
+
let newContent = null;
|
|
892
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
893
|
+
if (updatableFields.content) {
|
|
894
|
+
const existingContent = existingMessage.content || {};
|
|
895
|
+
const existingMetadata = existingContent.metadata || {};
|
|
896
|
+
const updateMetadata = updatableFields.content.metadata || {};
|
|
897
|
+
newContent = {
|
|
898
|
+
...existingContent,
|
|
899
|
+
...updatableFields.content,
|
|
900
|
+
// Deep merge metadata
|
|
901
|
+
metadata: {
|
|
902
|
+
...existingMetadata,
|
|
903
|
+
...updateMetadata
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
setClauses.push(`content = {var_content_${paramIdx}:String}`);
|
|
907
|
+
values[`var_content_${paramIdx}`] = JSON.stringify(newContent);
|
|
908
|
+
paramIdx++;
|
|
909
|
+
delete updatableFields.content;
|
|
910
|
+
}
|
|
911
|
+
for (const key in updatableFields) {
|
|
912
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
913
|
+
const dbColumn = key === "threadId" ? "thread_id" : key;
|
|
914
|
+
setClauses.push(`"${dbColumn}" = {var_${key}_${paramIdx}:String}`);
|
|
915
|
+
values[`var_${key}_${paramIdx}`] = updatableFields[key];
|
|
916
|
+
paramIdx++;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
if (setClauses.length > 0) {
|
|
920
|
+
values[`var_id_${paramIdx}`] = id;
|
|
921
|
+
const updateQuery = `
|
|
922
|
+
ALTER TABLE ${TABLE_MESSAGES}
|
|
923
|
+
UPDATE ${setClauses.join(", ")}
|
|
924
|
+
WHERE id = {var_id_${paramIdx}:String}
|
|
925
|
+
`;
|
|
926
|
+
console.info("Updating message:", id, "with query:", updateQuery, "values:", values);
|
|
927
|
+
updatePromises.push(
|
|
928
|
+
this.client.command({
|
|
929
|
+
query: updateQuery,
|
|
930
|
+
query_params: values,
|
|
931
|
+
clickhouse_settings: {
|
|
932
|
+
date_time_input_format: "best_effort",
|
|
933
|
+
use_client_time_zone: 1,
|
|
934
|
+
output_format_json_quote_64bit_integers: 0
|
|
935
|
+
}
|
|
936
|
+
})
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (updatePromises.length > 0) {
|
|
941
|
+
await Promise.all(updatePromises);
|
|
942
|
+
}
|
|
943
|
+
await this.client.command({
|
|
944
|
+
query: `OPTIMIZE TABLE ${TABLE_MESSAGES} FINAL`,
|
|
945
|
+
clickhouse_settings: {
|
|
946
|
+
date_time_input_format: "best_effort",
|
|
947
|
+
use_client_time_zone: 1,
|
|
948
|
+
output_format_json_quote_64bit_integers: 0
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
for (const existingMessage of parsedExistingMessages) {
|
|
952
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
953
|
+
if (!updatePayload) continue;
|
|
954
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
955
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
956
|
+
const verifyResult = await this.client.query({
|
|
957
|
+
query: `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId" FROM ${TABLE_MESSAGES} WHERE id = {messageId:String}`,
|
|
958
|
+
query_params: { messageId: id },
|
|
959
|
+
clickhouse_settings: {
|
|
960
|
+
date_time_input_format: "best_effort",
|
|
961
|
+
date_time_output_format: "iso",
|
|
962
|
+
use_client_time_zone: 1,
|
|
963
|
+
output_format_json_quote_64bit_integers: 0
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
const verifyRows = await verifyResult.json();
|
|
967
|
+
if (verifyRows.data.length > 0) {
|
|
968
|
+
const updatedMessage = transformRows(verifyRows.data)[0];
|
|
969
|
+
if (updatedMessage) {
|
|
970
|
+
let needsRetry = false;
|
|
971
|
+
for (const [key, value] of Object.entries(fieldsToUpdate)) {
|
|
972
|
+
if (key === "content") {
|
|
973
|
+
const expectedContent = typeof value === "string" ? value : JSON.stringify(value);
|
|
974
|
+
const actualContent = typeof updatedMessage.content === "string" ? updatedMessage.content : JSON.stringify(updatedMessage.content);
|
|
975
|
+
if (actualContent !== expectedContent) {
|
|
976
|
+
needsRetry = true;
|
|
977
|
+
break;
|
|
978
|
+
}
|
|
979
|
+
} else if (updatedMessage[key] !== value) {
|
|
980
|
+
needsRetry = true;
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
if (needsRetry) {
|
|
985
|
+
console.info("Update not applied correctly, retrying with DELETE + INSERT for message:", id);
|
|
986
|
+
await this.client.command({
|
|
987
|
+
query: `DELETE FROM ${TABLE_MESSAGES} WHERE id = {messageId:String}`,
|
|
988
|
+
query_params: { messageId: id },
|
|
989
|
+
clickhouse_settings: {
|
|
990
|
+
date_time_input_format: "best_effort",
|
|
991
|
+
use_client_time_zone: 1,
|
|
992
|
+
output_format_json_quote_64bit_integers: 0
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
let updatedContent = existingMessage.content || {};
|
|
996
|
+
if (fieldsToUpdate.content) {
|
|
997
|
+
const existingContent = existingMessage.content || {};
|
|
998
|
+
const existingMetadata = existingContent.metadata || {};
|
|
999
|
+
const updateMetadata = fieldsToUpdate.content.metadata || {};
|
|
1000
|
+
updatedContent = {
|
|
1001
|
+
...existingContent,
|
|
1002
|
+
...fieldsToUpdate.content,
|
|
1003
|
+
metadata: {
|
|
1004
|
+
...existingMetadata,
|
|
1005
|
+
...updateMetadata
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
1009
|
+
const updatedMessageData = {
|
|
1010
|
+
...existingMessage,
|
|
1011
|
+
...fieldsToUpdate,
|
|
1012
|
+
content: updatedContent
|
|
1013
|
+
};
|
|
1014
|
+
await this.client.insert({
|
|
1015
|
+
table: TABLE_MESSAGES,
|
|
1016
|
+
format: "JSONEachRow",
|
|
1017
|
+
values: [
|
|
1018
|
+
{
|
|
1019
|
+
id: updatedMessageData.id,
|
|
1020
|
+
thread_id: updatedMessageData.threadId,
|
|
1021
|
+
resourceId: updatedMessageData.resourceId,
|
|
1022
|
+
content: typeof updatedMessageData.content === "string" ? updatedMessageData.content : JSON.stringify(updatedMessageData.content),
|
|
1023
|
+
createdAt: updatedMessageData.createdAt.toISOString(),
|
|
1024
|
+
role: updatedMessageData.role,
|
|
1025
|
+
type: updatedMessageData.type || "v2"
|
|
1026
|
+
}
|
|
1027
|
+
],
|
|
1028
|
+
clickhouse_settings: {
|
|
1029
|
+
date_time_input_format: "best_effort",
|
|
1030
|
+
use_client_time_zone: 1,
|
|
1031
|
+
output_format_json_quote_64bit_integers: 0
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
if (threadIdsToUpdate.size > 0) {
|
|
1039
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
1040
|
+
const now = (/* @__PURE__ */ new Date()).toISOString().replace("Z", "");
|
|
1041
|
+
const threadUpdatePromises = Array.from(threadIdsToUpdate).map(async (threadId) => {
|
|
1042
|
+
const threadResult = await this.client.query({
|
|
1043
|
+
query: `SELECT id, resourceId, title, metadata, createdAt FROM ${TABLE_THREADS} WHERE id = {threadId:String}`,
|
|
1044
|
+
query_params: { threadId },
|
|
1045
|
+
clickhouse_settings: {
|
|
1046
|
+
date_time_input_format: "best_effort",
|
|
1047
|
+
date_time_output_format: "iso",
|
|
1048
|
+
use_client_time_zone: 1,
|
|
1049
|
+
output_format_json_quote_64bit_integers: 0
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
const threadRows = await threadResult.json();
|
|
1053
|
+
if (threadRows.data.length > 0) {
|
|
1054
|
+
const existingThread = threadRows.data[0];
|
|
1055
|
+
await this.client.command({
|
|
1056
|
+
query: `DELETE FROM ${TABLE_THREADS} WHERE id = {threadId:String}`,
|
|
1057
|
+
query_params: { threadId },
|
|
1058
|
+
clickhouse_settings: {
|
|
1059
|
+
date_time_input_format: "best_effort",
|
|
1060
|
+
use_client_time_zone: 1,
|
|
1061
|
+
output_format_json_quote_64bit_integers: 0
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
await this.client.insert({
|
|
1065
|
+
table: TABLE_THREADS,
|
|
1066
|
+
format: "JSONEachRow",
|
|
1067
|
+
values: [
|
|
1068
|
+
{
|
|
1069
|
+
id: existingThread.id,
|
|
1070
|
+
resourceId: existingThread.resourceId,
|
|
1071
|
+
title: existingThread.title,
|
|
1072
|
+
metadata: existingThread.metadata,
|
|
1073
|
+
createdAt: existingThread.createdAt,
|
|
1074
|
+
updatedAt: now
|
|
1075
|
+
}
|
|
1076
|
+
],
|
|
1077
|
+
clickhouse_settings: {
|
|
1078
|
+
date_time_input_format: "best_effort",
|
|
1079
|
+
use_client_time_zone: 1,
|
|
1080
|
+
output_format_json_quote_64bit_integers: 0
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
1085
|
+
await Promise.all(threadUpdatePromises);
|
|
1086
|
+
}
|
|
1087
|
+
const updatedMessages = [];
|
|
1088
|
+
for (const messageId of messageIds) {
|
|
1089
|
+
const updatedResult = await this.client.query({
|
|
1090
|
+
query: `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId" FROM ${TABLE_MESSAGES} WHERE id = {messageId:String}`,
|
|
1091
|
+
query_params: { messageId },
|
|
1092
|
+
clickhouse_settings: {
|
|
1093
|
+
date_time_input_format: "best_effort",
|
|
1094
|
+
date_time_output_format: "iso",
|
|
1095
|
+
use_client_time_zone: 1,
|
|
1096
|
+
output_format_json_quote_64bit_integers: 0
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
const updatedRows = await updatedResult.json();
|
|
1100
|
+
if (updatedRows.data.length > 0) {
|
|
1101
|
+
const message = transformRows(updatedRows.data)[0];
|
|
1102
|
+
if (message) {
|
|
1103
|
+
updatedMessages.push(message);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return updatedMessages.map((message) => {
|
|
1108
|
+
if (typeof message.content === "string") {
|
|
1109
|
+
try {
|
|
1110
|
+
message.content = JSON.parse(message.content);
|
|
1111
|
+
} catch {
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return message;
|
|
1115
|
+
});
|
|
100
1116
|
} catch (error) {
|
|
101
|
-
|
|
102
|
-
|
|
1117
|
+
throw new MastraError(
|
|
1118
|
+
{
|
|
1119
|
+
id: "CLICKHOUSE_STORAGE_UPDATE_MESSAGES_FAILED",
|
|
1120
|
+
domain: ErrorDomain.STORAGE,
|
|
1121
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1122
|
+
details: { messageIds: messages.map((m) => m.id).join(",") }
|
|
1123
|
+
},
|
|
1124
|
+
error
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
async getResourceById({ resourceId }) {
|
|
1129
|
+
try {
|
|
1130
|
+
const result = await this.client.query({
|
|
1131
|
+
query: `SELECT id, workingMemory, metadata, createdAt, updatedAt FROM ${TABLE_RESOURCES} WHERE id = {resourceId:String}`,
|
|
1132
|
+
query_params: { resourceId },
|
|
1133
|
+
clickhouse_settings: {
|
|
1134
|
+
date_time_input_format: "best_effort",
|
|
1135
|
+
date_time_output_format: "iso",
|
|
1136
|
+
use_client_time_zone: 1,
|
|
1137
|
+
output_format_json_quote_64bit_integers: 0
|
|
1138
|
+
}
|
|
1139
|
+
});
|
|
1140
|
+
const rows = await result.json();
|
|
1141
|
+
if (rows.data.length === 0) {
|
|
1142
|
+
return null;
|
|
103
1143
|
}
|
|
104
|
-
|
|
105
|
-
|
|
1144
|
+
const resource = rows.data[0];
|
|
1145
|
+
return {
|
|
1146
|
+
id: resource.id,
|
|
1147
|
+
workingMemory: resource.workingMemory && typeof resource.workingMemory === "object" ? JSON.stringify(resource.workingMemory) : resource.workingMemory,
|
|
1148
|
+
metadata: resource.metadata && typeof resource.metadata === "string" ? JSON.parse(resource.metadata) : resource.metadata,
|
|
1149
|
+
createdAt: new Date(resource.createdAt),
|
|
1150
|
+
updatedAt: new Date(resource.updatedAt)
|
|
1151
|
+
};
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
throw new MastraError(
|
|
1154
|
+
{
|
|
1155
|
+
id: "CLICKHOUSE_STORAGE_GET_RESOURCE_BY_ID_FAILED",
|
|
1156
|
+
domain: ErrorDomain.STORAGE,
|
|
1157
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1158
|
+
details: { resourceId }
|
|
1159
|
+
},
|
|
1160
|
+
error
|
|
1161
|
+
);
|
|
106
1162
|
}
|
|
107
1163
|
}
|
|
108
|
-
async
|
|
1164
|
+
async saveResource({ resource }) {
|
|
109
1165
|
try {
|
|
110
|
-
await this.
|
|
111
|
-
table:
|
|
112
|
-
values: records.map((record) => ({
|
|
113
|
-
...Object.fromEntries(
|
|
114
|
-
Object.entries(record).map(([key, value]) => [
|
|
115
|
-
key,
|
|
116
|
-
TABLE_SCHEMAS[tableName]?.[key]?.type === "timestamp" ? new Date(value).toISOString() : value
|
|
117
|
-
])
|
|
118
|
-
)
|
|
119
|
-
})),
|
|
1166
|
+
await this.client.insert({
|
|
1167
|
+
table: TABLE_RESOURCES,
|
|
120
1168
|
format: "JSONEachRow",
|
|
1169
|
+
values: [
|
|
1170
|
+
{
|
|
1171
|
+
id: resource.id,
|
|
1172
|
+
workingMemory: resource.workingMemory,
|
|
1173
|
+
metadata: JSON.stringify(resource.metadata),
|
|
1174
|
+
createdAt: resource.createdAt.toISOString(),
|
|
1175
|
+
updatedAt: resource.updatedAt.toISOString()
|
|
1176
|
+
}
|
|
1177
|
+
],
|
|
121
1178
|
clickhouse_settings: {
|
|
122
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
123
1179
|
date_time_input_format: "best_effort",
|
|
124
1180
|
use_client_time_zone: 1,
|
|
125
1181
|
output_format_json_quote_64bit_integers: 0
|
|
126
1182
|
}
|
|
127
1183
|
});
|
|
1184
|
+
return resource;
|
|
128
1185
|
} catch (error) {
|
|
129
|
-
|
|
130
|
-
|
|
1186
|
+
throw new MastraError(
|
|
1187
|
+
{
|
|
1188
|
+
id: "CLICKHOUSE_STORAGE_SAVE_RESOURCE_FAILED",
|
|
1189
|
+
domain: ErrorDomain.STORAGE,
|
|
1190
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1191
|
+
details: { resourceId: resource.id }
|
|
1192
|
+
},
|
|
1193
|
+
error
|
|
1194
|
+
);
|
|
131
1195
|
}
|
|
132
1196
|
}
|
|
133
|
-
async
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
perPage,
|
|
138
|
-
attributes,
|
|
139
|
-
filters,
|
|
140
|
-
fromDate,
|
|
141
|
-
toDate
|
|
1197
|
+
async updateResource({
|
|
1198
|
+
resourceId,
|
|
1199
|
+
workingMemory,
|
|
1200
|
+
metadata
|
|
142
1201
|
}) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
if (attributes) {
|
|
156
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
157
|
-
conditions.push(`JSONExtractString(attributes, '${key}') = {var_attr_${key}:String}`);
|
|
158
|
-
args[`var_attr_${key}`] = value;
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
if (filters) {
|
|
162
|
-
Object.entries(filters).forEach(([key, value]) => {
|
|
163
|
-
conditions.push(
|
|
164
|
-
`${key} = {var_col_${key}:${COLUMN_TYPES[TABLE_SCHEMAS.mastra_traces?.[key]?.type ?? "text"]}}`
|
|
165
|
-
);
|
|
166
|
-
args[`var_col_${key}`] = value;
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
if (fromDate) {
|
|
170
|
-
conditions.push(`createdAt >= {var_from_date:DateTime64(3)}`);
|
|
171
|
-
args.var_from_date = fromDate.getTime() / 1e3;
|
|
172
|
-
}
|
|
173
|
-
if (toDate) {
|
|
174
|
-
conditions.push(`createdAt <= {var_to_date:DateTime64(3)}`);
|
|
175
|
-
args.var_to_date = toDate.getTime() / 1e3;
|
|
176
|
-
}
|
|
177
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
178
|
-
const result = await this.db.query({
|
|
179
|
-
query: `SELECT *, toDateTime64(createdAt, 3) as createdAt FROM ${TABLE_TRACES} ${whereClause} ORDER BY "createdAt" DESC LIMIT ${limit} OFFSET ${offset}`,
|
|
180
|
-
query_params: args,
|
|
181
|
-
clickhouse_settings: {
|
|
182
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
183
|
-
date_time_input_format: "best_effort",
|
|
184
|
-
date_time_output_format: "iso",
|
|
185
|
-
use_client_time_zone: 1,
|
|
186
|
-
output_format_json_quote_64bit_integers: 0
|
|
1202
|
+
try {
|
|
1203
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1204
|
+
if (!existingResource) {
|
|
1205
|
+
const newResource = {
|
|
1206
|
+
id: resourceId,
|
|
1207
|
+
workingMemory,
|
|
1208
|
+
metadata: metadata || {},
|
|
1209
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1210
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1211
|
+
};
|
|
1212
|
+
return this.saveResource({ resource: newResource });
|
|
187
1213
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
1214
|
+
const updatedResource = {
|
|
1215
|
+
...existingResource,
|
|
1216
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1217
|
+
metadata: {
|
|
1218
|
+
...existingResource.metadata,
|
|
1219
|
+
...metadata
|
|
1220
|
+
},
|
|
1221
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1222
|
+
};
|
|
1223
|
+
const updateQuery = `
|
|
1224
|
+
ALTER TABLE ${TABLE_RESOURCES}
|
|
1225
|
+
UPDATE workingMemory = {workingMemory:String}, metadata = {metadata:String}, updatedAt = {updatedAt:String}
|
|
1226
|
+
WHERE id = {resourceId:String}
|
|
1227
|
+
`;
|
|
1228
|
+
await this.client.command({
|
|
1229
|
+
query: updateQuery,
|
|
1230
|
+
query_params: {
|
|
1231
|
+
workingMemory: updatedResource.workingMemory,
|
|
1232
|
+
metadata: JSON.stringify(updatedResource.metadata),
|
|
1233
|
+
updatedAt: updatedResource.updatedAt.toISOString().replace("Z", ""),
|
|
1234
|
+
resourceId
|
|
1235
|
+
},
|
|
1236
|
+
clickhouse_settings: {
|
|
1237
|
+
date_time_input_format: "best_effort",
|
|
1238
|
+
use_client_time_zone: 1,
|
|
1239
|
+
output_format_json_quote_64bit_integers: 0
|
|
1240
|
+
}
|
|
1241
|
+
});
|
|
1242
|
+
await this.client.command({
|
|
1243
|
+
query: `OPTIMIZE TABLE ${TABLE_RESOURCES} FINAL`,
|
|
1244
|
+
clickhouse_settings: {
|
|
1245
|
+
date_time_input_format: "best_effort",
|
|
1246
|
+
use_client_time_zone: 1,
|
|
1247
|
+
output_format_json_quote_64bit_integers: 0
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
return updatedResource;
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
throw new MastraError(
|
|
1253
|
+
{
|
|
1254
|
+
id: "CLICKHOUSE_STORAGE_UPDATE_RESOURCE_FAILED",
|
|
1255
|
+
domain: ErrorDomain.STORAGE,
|
|
1256
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1257
|
+
details: { resourceId }
|
|
1258
|
+
},
|
|
1259
|
+
error
|
|
1260
|
+
);
|
|
191
1261
|
}
|
|
192
|
-
const resp = await result.json();
|
|
193
|
-
const rows = resp.data;
|
|
194
|
-
return rows.map((row) => ({
|
|
195
|
-
id: row.id,
|
|
196
|
-
parentSpanId: row.parentSpanId,
|
|
197
|
-
traceId: row.traceId,
|
|
198
|
-
name: row.name,
|
|
199
|
-
scope: row.scope,
|
|
200
|
-
kind: row.kind,
|
|
201
|
-
status: safelyParseJSON(row.status),
|
|
202
|
-
events: safelyParseJSON(row.events),
|
|
203
|
-
links: safelyParseJSON(row.links),
|
|
204
|
-
attributes: safelyParseJSON(row.attributes),
|
|
205
|
-
startTime: row.startTime,
|
|
206
|
-
endTime: row.endTime,
|
|
207
|
-
other: safelyParseJSON(row.other),
|
|
208
|
-
createdAt: row.createdAt
|
|
209
|
-
}));
|
|
210
1262
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
1263
|
+
};
|
|
1264
|
+
var StoreOperationsClickhouse = class extends StoreOperations {
|
|
1265
|
+
ttl;
|
|
1266
|
+
client;
|
|
1267
|
+
constructor({ client, ttl }) {
|
|
1268
|
+
super();
|
|
1269
|
+
this.ttl = ttl;
|
|
1270
|
+
this.client = client;
|
|
215
1271
|
}
|
|
216
|
-
async
|
|
217
|
-
await this.
|
|
218
|
-
query: `
|
|
1272
|
+
async hasColumn(table, column) {
|
|
1273
|
+
const result = await this.client.query({
|
|
1274
|
+
query: `DESCRIBE TABLE ${table}`,
|
|
1275
|
+
format: "JSONEachRow"
|
|
219
1276
|
});
|
|
1277
|
+
const columns = await result.json();
|
|
1278
|
+
return columns.some((c) => c.name === column);
|
|
1279
|
+
}
|
|
1280
|
+
getSqlType(type) {
|
|
1281
|
+
switch (type) {
|
|
1282
|
+
case "text":
|
|
1283
|
+
return "String";
|
|
1284
|
+
case "timestamp":
|
|
1285
|
+
return "DateTime64(3)";
|
|
1286
|
+
case "integer":
|
|
1287
|
+
case "bigint":
|
|
1288
|
+
return "Int64";
|
|
1289
|
+
case "jsonb":
|
|
1290
|
+
return "String";
|
|
1291
|
+
default:
|
|
1292
|
+
return super.getSqlType(type);
|
|
1293
|
+
}
|
|
220
1294
|
}
|
|
221
1295
|
async createTable({
|
|
222
1296
|
tableName,
|
|
@@ -231,27 +1305,25 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
231
1305
|
}).join(",\n");
|
|
232
1306
|
const rowTtl = this.ttl?.[tableName]?.row;
|
|
233
1307
|
const sql = tableName === TABLE_WORKFLOW_SNAPSHOT ? `
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
`;
|
|
254
|
-
await this.db.query({
|
|
1308
|
+
CREATE TABLE IF NOT EXISTS ${tableName} (
|
|
1309
|
+
${["id String"].concat(columns)}
|
|
1310
|
+
)
|
|
1311
|
+
ENGINE = ${TABLE_ENGINES[tableName] ?? "MergeTree()"}
|
|
1312
|
+
PRIMARY KEY (createdAt, run_id, workflow_name)
|
|
1313
|
+
ORDER BY (createdAt, run_id, workflow_name)
|
|
1314
|
+
${rowTtl ? `TTL toDateTime(${rowTtl.ttlKey ?? "createdAt"}) + INTERVAL ${rowTtl.interval} ${rowTtl.unit}` : ""}
|
|
1315
|
+
SETTINGS index_granularity = 8192
|
|
1316
|
+
` : `
|
|
1317
|
+
CREATE TABLE IF NOT EXISTS ${tableName} (
|
|
1318
|
+
${columns}
|
|
1319
|
+
)
|
|
1320
|
+
ENGINE = ${TABLE_ENGINES[tableName] ?? "MergeTree()"}
|
|
1321
|
+
PRIMARY KEY (createdAt, ${"id"})
|
|
1322
|
+
ORDER BY (createdAt, ${"id"})
|
|
1323
|
+
${this.ttl?.[tableName]?.row ? `TTL toDateTime(createdAt) + INTERVAL ${this.ttl[tableName].row.interval} ${this.ttl[tableName].row.unit}` : ""}
|
|
1324
|
+
SETTINGS index_granularity = 8192
|
|
1325
|
+
`;
|
|
1326
|
+
await this.client.query({
|
|
255
1327
|
query: sql,
|
|
256
1328
|
clickhouse_settings: {
|
|
257
1329
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -262,13 +1334,59 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
262
1334
|
}
|
|
263
1335
|
});
|
|
264
1336
|
} catch (error) {
|
|
265
|
-
|
|
266
|
-
|
|
1337
|
+
throw new MastraError(
|
|
1338
|
+
{
|
|
1339
|
+
id: "CLICKHOUSE_STORAGE_CREATE_TABLE_FAILED",
|
|
1340
|
+
domain: ErrorDomain.STORAGE,
|
|
1341
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1342
|
+
details: { tableName }
|
|
1343
|
+
},
|
|
1344
|
+
error
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
async alterTable({
|
|
1349
|
+
tableName,
|
|
1350
|
+
schema,
|
|
1351
|
+
ifNotExists
|
|
1352
|
+
}) {
|
|
1353
|
+
try {
|
|
1354
|
+
const describeSql = `DESCRIBE TABLE ${tableName}`;
|
|
1355
|
+
const result = await this.client.query({
|
|
1356
|
+
query: describeSql
|
|
1357
|
+
});
|
|
1358
|
+
const rows = await result.json();
|
|
1359
|
+
const existingColumnNames = new Set(rows.data.map((row) => row.name.toLowerCase()));
|
|
1360
|
+
for (const columnName of ifNotExists) {
|
|
1361
|
+
if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
|
|
1362
|
+
const columnDef = schema[columnName];
|
|
1363
|
+
let sqlType = this.getSqlType(columnDef.type);
|
|
1364
|
+
if (columnDef.nullable !== false) {
|
|
1365
|
+
sqlType = `Nullable(${sqlType})`;
|
|
1366
|
+
}
|
|
1367
|
+
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1368
|
+
const alterSql = `ALTER TABLE ${tableName} ADD COLUMN IF NOT EXISTS "${columnName}" ${sqlType} ${defaultValue}`.trim();
|
|
1369
|
+
await this.client.query({
|
|
1370
|
+
query: alterSql
|
|
1371
|
+
});
|
|
1372
|
+
this.logger?.debug?.(`Added column ${columnName} to table ${tableName}`);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
} catch (error) {
|
|
1376
|
+
throw new MastraError(
|
|
1377
|
+
{
|
|
1378
|
+
id: "CLICKHOUSE_STORAGE_ALTER_TABLE_FAILED",
|
|
1379
|
+
domain: ErrorDomain.STORAGE,
|
|
1380
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1381
|
+
details: { tableName }
|
|
1382
|
+
},
|
|
1383
|
+
error
|
|
1384
|
+
);
|
|
267
1385
|
}
|
|
268
1386
|
}
|
|
269
1387
|
async clearTable({ tableName }) {
|
|
270
1388
|
try {
|
|
271
|
-
await this.
|
|
1389
|
+
await this.client.query({
|
|
272
1390
|
query: `TRUNCATE TABLE ${tableName}`,
|
|
273
1391
|
clickhouse_settings: {
|
|
274
1392
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -279,19 +1397,33 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
279
1397
|
}
|
|
280
1398
|
});
|
|
281
1399
|
} catch (error) {
|
|
282
|
-
|
|
283
|
-
|
|
1400
|
+
throw new MastraError(
|
|
1401
|
+
{
|
|
1402
|
+
id: "CLICKHOUSE_STORAGE_CLEAR_TABLE_FAILED",
|
|
1403
|
+
domain: ErrorDomain.STORAGE,
|
|
1404
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1405
|
+
details: { tableName }
|
|
1406
|
+
},
|
|
1407
|
+
error
|
|
1408
|
+
);
|
|
284
1409
|
}
|
|
285
1410
|
}
|
|
1411
|
+
async dropTable({ tableName }) {
|
|
1412
|
+
await this.client.query({
|
|
1413
|
+
query: `DROP TABLE IF EXISTS ${tableName}`
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
286
1416
|
async insert({ tableName, record }) {
|
|
1417
|
+
const createdAt = (record.createdAt || record.created_at || /* @__PURE__ */ new Date()).toISOString();
|
|
1418
|
+
const updatedAt = (record.updatedAt || /* @__PURE__ */ new Date()).toISOString();
|
|
287
1419
|
try {
|
|
288
|
-
await this.
|
|
1420
|
+
const result = await this.client.insert({
|
|
289
1421
|
table: tableName,
|
|
290
1422
|
values: [
|
|
291
1423
|
{
|
|
292
1424
|
...record,
|
|
293
|
-
createdAt
|
|
294
|
-
updatedAt
|
|
1425
|
+
createdAt,
|
|
1426
|
+
updatedAt
|
|
295
1427
|
}
|
|
296
1428
|
],
|
|
297
1429
|
format: "JSONEachRow",
|
|
@@ -302,13 +1434,55 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
302
1434
|
use_client_time_zone: 1
|
|
303
1435
|
}
|
|
304
1436
|
});
|
|
1437
|
+
console.info("INSERT RESULT", result);
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
throw new MastraError(
|
|
1440
|
+
{
|
|
1441
|
+
id: "CLICKHOUSE_STORAGE_INSERT_FAILED",
|
|
1442
|
+
domain: ErrorDomain.STORAGE,
|
|
1443
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1444
|
+
details: { tableName }
|
|
1445
|
+
},
|
|
1446
|
+
error
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
async batchInsert({ tableName, records }) {
|
|
1451
|
+
const recordsToBeInserted = records.map((record) => ({
|
|
1452
|
+
...Object.fromEntries(
|
|
1453
|
+
Object.entries(record).map(([key, value]) => [
|
|
1454
|
+
key,
|
|
1455
|
+
TABLE_SCHEMAS[tableName]?.[key]?.type === "timestamp" ? new Date(value).toISOString() : value
|
|
1456
|
+
])
|
|
1457
|
+
)
|
|
1458
|
+
}));
|
|
1459
|
+
try {
|
|
1460
|
+
await this.client.insert({
|
|
1461
|
+
table: tableName,
|
|
1462
|
+
values: recordsToBeInserted,
|
|
1463
|
+
format: "JSONEachRow",
|
|
1464
|
+
clickhouse_settings: {
|
|
1465
|
+
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
1466
|
+
date_time_input_format: "best_effort",
|
|
1467
|
+
use_client_time_zone: 1,
|
|
1468
|
+
output_format_json_quote_64bit_integers: 0
|
|
1469
|
+
}
|
|
1470
|
+
});
|
|
305
1471
|
} catch (error) {
|
|
306
|
-
|
|
307
|
-
|
|
1472
|
+
throw new MastraError(
|
|
1473
|
+
{
|
|
1474
|
+
id: "CLICKHOUSE_STORAGE_BATCH_INSERT_FAILED",
|
|
1475
|
+
domain: ErrorDomain.STORAGE,
|
|
1476
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1477
|
+
details: { tableName }
|
|
1478
|
+
},
|
|
1479
|
+
error
|
|
1480
|
+
);
|
|
308
1481
|
}
|
|
309
1482
|
}
|
|
310
1483
|
async load({ tableName, keys }) {
|
|
311
1484
|
try {
|
|
1485
|
+
const engine = TABLE_ENGINES[tableName] ?? "MergeTree()";
|
|
312
1486
|
const keyEntries = Object.entries(keys);
|
|
313
1487
|
const conditions = keyEntries.map(
|
|
314
1488
|
([key]) => `"${key}" = {var_${key}:${COLUMN_TYPES[TABLE_SCHEMAS[tableName]?.[key]?.type ?? "text"]}}`
|
|
@@ -316,8 +1490,10 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
316
1490
|
const values = keyEntries.reduce((acc, [key, value]) => {
|
|
317
1491
|
return { ...acc, [`var_${key}`]: value };
|
|
318
1492
|
}, {});
|
|
319
|
-
const
|
|
320
|
-
|
|
1493
|
+
const hasUpdatedAt = TABLE_SCHEMAS[tableName]?.updatedAt;
|
|
1494
|
+
const selectClause = `SELECT *, toDateTime64(createdAt, 3) as createdAt${hasUpdatedAt ? ", toDateTime64(updatedAt, 3) as updatedAt" : ""}`;
|
|
1495
|
+
const result = await this.client.query({
|
|
1496
|
+
query: `${selectClause} FROM ${tableName} ${engine.startsWith("ReplacingMergeTree") ? "FINAL" : ""} WHERE ${conditions} ORDER BY createdAt DESC LIMIT 1`,
|
|
321
1497
|
query_params: values,
|
|
322
1498
|
clickhouse_settings: {
|
|
323
1499
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -344,24 +1520,57 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
344
1520
|
const data = transformRow(rows.data[0]);
|
|
345
1521
|
return data;
|
|
346
1522
|
} catch (error) {
|
|
347
|
-
|
|
348
|
-
|
|
1523
|
+
throw new MastraError(
|
|
1524
|
+
{
|
|
1525
|
+
id: "CLICKHOUSE_STORAGE_LOAD_FAILED",
|
|
1526
|
+
domain: ErrorDomain.STORAGE,
|
|
1527
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1528
|
+
details: { tableName }
|
|
1529
|
+
},
|
|
1530
|
+
error
|
|
1531
|
+
);
|
|
349
1532
|
}
|
|
350
1533
|
}
|
|
351
|
-
|
|
1534
|
+
};
|
|
1535
|
+
var ScoresStorageClickhouse = class extends ScoresStorage {
|
|
1536
|
+
client;
|
|
1537
|
+
operations;
|
|
1538
|
+
constructor({ client, operations }) {
|
|
1539
|
+
super();
|
|
1540
|
+
this.client = client;
|
|
1541
|
+
this.operations = operations;
|
|
1542
|
+
}
|
|
1543
|
+
transformScoreRow(row) {
|
|
1544
|
+
const scorer = safelyParseJSON(row.scorer);
|
|
1545
|
+
const preprocessStepResult = safelyParseJSON(row.preprocessStepResult);
|
|
1546
|
+
const analyzeStepResult = safelyParseJSON(row.analyzeStepResult);
|
|
1547
|
+
const metadata = safelyParseJSON(row.metadata);
|
|
1548
|
+
const input = safelyParseJSON(row.input);
|
|
1549
|
+
const output = safelyParseJSON(row.output);
|
|
1550
|
+
const additionalContext = safelyParseJSON(row.additionalContext);
|
|
1551
|
+
const requestContext = safelyParseJSON(row.requestContext);
|
|
1552
|
+
const entity = safelyParseJSON(row.entity);
|
|
1553
|
+
return {
|
|
1554
|
+
...row,
|
|
1555
|
+
scorer,
|
|
1556
|
+
preprocessStepResult,
|
|
1557
|
+
analyzeStepResult,
|
|
1558
|
+
metadata,
|
|
1559
|
+
input,
|
|
1560
|
+
output,
|
|
1561
|
+
additionalContext,
|
|
1562
|
+
requestContext,
|
|
1563
|
+
entity,
|
|
1564
|
+
createdAt: new Date(row.createdAt),
|
|
1565
|
+
updatedAt: new Date(row.updatedAt)
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
async getScoreById({ id }) {
|
|
352
1569
|
try {
|
|
353
|
-
const result = await this.
|
|
354
|
-
query: `SELECT
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
title,
|
|
358
|
-
metadata,
|
|
359
|
-
toDateTime64(createdAt, 3) as createdAt,
|
|
360
|
-
toDateTime64(updatedAt, 3) as updatedAt
|
|
361
|
-
FROM "${TABLE_THREADS}"
|
|
362
|
-
FINAL
|
|
363
|
-
WHERE id = {var_id:String}`,
|
|
364
|
-
query_params: { var_id: threadId },
|
|
1570
|
+
const result = await this.client.query({
|
|
1571
|
+
query: `SELECT * FROM ${TABLE_SCORERS} WHERE id = {var_id:String}`,
|
|
1572
|
+
query_params: { var_id: id },
|
|
1573
|
+
format: "JSONEachRow",
|
|
365
1574
|
clickhouse_settings: {
|
|
366
1575
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
367
1576
|
date_time_input_format: "best_effort",
|
|
@@ -370,223 +1579,269 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
370
1579
|
output_format_json_quote_64bit_integers: 0
|
|
371
1580
|
}
|
|
372
1581
|
});
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
if (!thread) {
|
|
1582
|
+
const resultJson = await result.json();
|
|
1583
|
+
if (!Array.isArray(resultJson) || resultJson.length === 0) {
|
|
376
1584
|
return null;
|
|
377
1585
|
}
|
|
378
|
-
return
|
|
379
|
-
...thread,
|
|
380
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
381
|
-
createdAt: thread.createdAt,
|
|
382
|
-
updatedAt: thread.updatedAt
|
|
383
|
-
};
|
|
1586
|
+
return this.transformScoreRow(resultJson[0]);
|
|
384
1587
|
} catch (error) {
|
|
385
|
-
|
|
386
|
-
|
|
1588
|
+
throw new MastraError(
|
|
1589
|
+
{
|
|
1590
|
+
id: "CLICKHOUSE_STORAGE_GET_SCORE_BY_ID_FAILED",
|
|
1591
|
+
domain: ErrorDomain.STORAGE,
|
|
1592
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1593
|
+
details: { scoreId: id }
|
|
1594
|
+
},
|
|
1595
|
+
error
|
|
1596
|
+
);
|
|
387
1597
|
}
|
|
388
1598
|
}
|
|
389
|
-
async
|
|
1599
|
+
async saveScore(score) {
|
|
1600
|
+
let parsedScore;
|
|
390
1601
|
try {
|
|
391
|
-
|
|
392
|
-
query: `SELECT
|
|
393
|
-
id,
|
|
394
|
-
"resourceId",
|
|
395
|
-
title,
|
|
396
|
-
metadata,
|
|
397
|
-
toDateTime64(createdAt, 3) as createdAt,
|
|
398
|
-
toDateTime64(updatedAt, 3) as updatedAt
|
|
399
|
-
FROM "${TABLE_THREADS}"
|
|
400
|
-
WHERE "resourceId" = {var_resourceId:String}`,
|
|
401
|
-
query_params: { var_resourceId: resourceId },
|
|
402
|
-
clickhouse_settings: {
|
|
403
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
404
|
-
date_time_input_format: "best_effort",
|
|
405
|
-
date_time_output_format: "iso",
|
|
406
|
-
use_client_time_zone: 1,
|
|
407
|
-
output_format_json_quote_64bit_integers: 0
|
|
408
|
-
}
|
|
409
|
-
});
|
|
410
|
-
const rows = await result.json();
|
|
411
|
-
const threads = transformRows(rows.data);
|
|
412
|
-
return threads.map((thread) => ({
|
|
413
|
-
...thread,
|
|
414
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
415
|
-
createdAt: thread.createdAt,
|
|
416
|
-
updatedAt: thread.updatedAt
|
|
417
|
-
}));
|
|
1602
|
+
parsedScore = saveScorePayloadSchema.parse(score);
|
|
418
1603
|
} catch (error) {
|
|
419
|
-
|
|
420
|
-
|
|
1604
|
+
throw new MastraError(
|
|
1605
|
+
{
|
|
1606
|
+
id: "CLICKHOUSE_STORAGE_SAVE_SCORE_FAILED_INVALID_SCORE_PAYLOAD",
|
|
1607
|
+
domain: ErrorDomain.STORAGE,
|
|
1608
|
+
category: ErrorCategory.USER,
|
|
1609
|
+
details: { scoreId: score.id }
|
|
1610
|
+
},
|
|
1611
|
+
error
|
|
1612
|
+
);
|
|
421
1613
|
}
|
|
422
|
-
}
|
|
423
|
-
async saveThread({ thread }) {
|
|
424
1614
|
try {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
updatedAt: thread.updatedAt.toISOString()
|
|
432
|
-
}
|
|
433
|
-
],
|
|
1615
|
+
const record = {
|
|
1616
|
+
...parsedScore
|
|
1617
|
+
};
|
|
1618
|
+
await this.client.insert({
|
|
1619
|
+
table: TABLE_SCORERS,
|
|
1620
|
+
values: [record],
|
|
434
1621
|
format: "JSONEachRow",
|
|
435
1622
|
clickhouse_settings: {
|
|
436
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
437
1623
|
date_time_input_format: "best_effort",
|
|
438
1624
|
use_client_time_zone: 1,
|
|
439
1625
|
output_format_json_quote_64bit_integers: 0
|
|
440
1626
|
}
|
|
441
1627
|
});
|
|
442
|
-
return
|
|
1628
|
+
return { score };
|
|
443
1629
|
} catch (error) {
|
|
444
|
-
|
|
445
|
-
|
|
1630
|
+
throw new MastraError(
|
|
1631
|
+
{
|
|
1632
|
+
id: "CLICKHOUSE_STORAGE_SAVE_SCORE_FAILED",
|
|
1633
|
+
domain: ErrorDomain.STORAGE,
|
|
1634
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1635
|
+
details: { scoreId: score.id }
|
|
1636
|
+
},
|
|
1637
|
+
error
|
|
1638
|
+
);
|
|
446
1639
|
}
|
|
447
1640
|
}
|
|
448
|
-
async
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
metadata
|
|
1641
|
+
async listScoresByRunId({
|
|
1642
|
+
runId,
|
|
1643
|
+
pagination
|
|
452
1644
|
}) {
|
|
453
1645
|
try {
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
1646
|
+
const countResult = await this.client.query({
|
|
1647
|
+
query: `SELECT COUNT(*) as count FROM ${TABLE_SCORERS} WHERE runId = {var_runId:String}`,
|
|
1648
|
+
query_params: { var_runId: runId },
|
|
1649
|
+
format: "JSONEachRow"
|
|
1650
|
+
});
|
|
1651
|
+
const countRows = await countResult.json();
|
|
1652
|
+
let total = 0;
|
|
1653
|
+
if (Array.isArray(countRows) && countRows.length > 0 && countRows[0]) {
|
|
1654
|
+
const countObj = countRows[0];
|
|
1655
|
+
total = Number(countObj.count);
|
|
1656
|
+
}
|
|
1657
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1658
|
+
if (!total) {
|
|
1659
|
+
return {
|
|
1660
|
+
pagination: {
|
|
1661
|
+
total: 0,
|
|
1662
|
+
page,
|
|
1663
|
+
perPage: perPageInput,
|
|
1664
|
+
hasMore: false
|
|
1665
|
+
},
|
|
1666
|
+
scores: []
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1670
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1671
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
1672
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1673
|
+
const result = await this.client.query({
|
|
1674
|
+
query: `SELECT * FROM ${TABLE_SCORERS} WHERE runId = {var_runId:String} ORDER BY createdAt DESC LIMIT {var_limit:Int64} OFFSET {var_offset:Int64}`,
|
|
1675
|
+
query_params: {
|
|
1676
|
+
var_runId: runId,
|
|
1677
|
+
var_limit: limitValue,
|
|
1678
|
+
var_offset: start
|
|
1679
|
+
},
|
|
476
1680
|
format: "JSONEachRow",
|
|
477
1681
|
clickhouse_settings: {
|
|
478
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
479
1682
|
date_time_input_format: "best_effort",
|
|
1683
|
+
date_time_output_format: "iso",
|
|
480
1684
|
use_client_time_zone: 1,
|
|
481
1685
|
output_format_json_quote_64bit_integers: 0
|
|
482
1686
|
}
|
|
483
1687
|
});
|
|
484
|
-
|
|
1688
|
+
const rows = await result.json();
|
|
1689
|
+
const scores = Array.isArray(rows) ? rows.map((row) => this.transformScoreRow(row)) : [];
|
|
1690
|
+
return {
|
|
1691
|
+
pagination: {
|
|
1692
|
+
total,
|
|
1693
|
+
page,
|
|
1694
|
+
perPage: perPageForResponse,
|
|
1695
|
+
hasMore: end < total
|
|
1696
|
+
},
|
|
1697
|
+
scores
|
|
1698
|
+
};
|
|
485
1699
|
} catch (error) {
|
|
486
|
-
|
|
487
|
-
|
|
1700
|
+
throw new MastraError(
|
|
1701
|
+
{
|
|
1702
|
+
id: "CLICKHOUSE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1703
|
+
domain: ErrorDomain.STORAGE,
|
|
1704
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1705
|
+
details: { runId }
|
|
1706
|
+
},
|
|
1707
|
+
error
|
|
1708
|
+
);
|
|
488
1709
|
}
|
|
489
1710
|
}
|
|
490
|
-
async
|
|
1711
|
+
async listScoresByScorerId({
|
|
1712
|
+
scorerId,
|
|
1713
|
+
entityId,
|
|
1714
|
+
entityType,
|
|
1715
|
+
source,
|
|
1716
|
+
pagination
|
|
1717
|
+
}) {
|
|
1718
|
+
let whereClause = `scorerId = {var_scorerId:String}`;
|
|
1719
|
+
if (entityId) {
|
|
1720
|
+
whereClause += ` AND entityId = {var_entityId:String}`;
|
|
1721
|
+
}
|
|
1722
|
+
if (entityType) {
|
|
1723
|
+
whereClause += ` AND entityType = {var_entityType:String}`;
|
|
1724
|
+
}
|
|
1725
|
+
if (source) {
|
|
1726
|
+
whereClause += ` AND source = {var_source:String}`;
|
|
1727
|
+
}
|
|
491
1728
|
try {
|
|
492
|
-
await this.
|
|
493
|
-
query: `
|
|
494
|
-
query_params: {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
1729
|
+
const countResult = await this.client.query({
|
|
1730
|
+
query: `SELECT COUNT(*) as count FROM ${TABLE_SCORERS} WHERE ${whereClause}`,
|
|
1731
|
+
query_params: {
|
|
1732
|
+
var_scorerId: scorerId,
|
|
1733
|
+
var_entityId: entityId,
|
|
1734
|
+
var_entityType: entityType,
|
|
1735
|
+
var_source: source
|
|
1736
|
+
},
|
|
1737
|
+
format: "JSONEachRow"
|
|
498
1738
|
});
|
|
499
|
-
await
|
|
500
|
-
|
|
501
|
-
|
|
1739
|
+
const countRows = await countResult.json();
|
|
1740
|
+
let total = 0;
|
|
1741
|
+
if (Array.isArray(countRows) && countRows.length > 0 && countRows[0]) {
|
|
1742
|
+
const countObj = countRows[0];
|
|
1743
|
+
total = Number(countObj.count);
|
|
1744
|
+
}
|
|
1745
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1746
|
+
if (!total) {
|
|
1747
|
+
return {
|
|
1748
|
+
pagination: {
|
|
1749
|
+
total: 0,
|
|
1750
|
+
page,
|
|
1751
|
+
perPage: perPageInput,
|
|
1752
|
+
hasMore: false
|
|
1753
|
+
},
|
|
1754
|
+
scores: []
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1757
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1758
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1759
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
1760
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1761
|
+
const result = await this.client.query({
|
|
1762
|
+
query: `SELECT * FROM ${TABLE_SCORERS} WHERE ${whereClause} ORDER BY createdAt DESC LIMIT {var_limit:Int64} OFFSET {var_offset:Int64}`,
|
|
1763
|
+
query_params: {
|
|
1764
|
+
var_scorerId: scorerId,
|
|
1765
|
+
var_limit: limitValue,
|
|
1766
|
+
var_offset: start,
|
|
1767
|
+
var_entityId: entityId,
|
|
1768
|
+
var_entityType: entityType,
|
|
1769
|
+
var_source: source
|
|
1770
|
+
},
|
|
1771
|
+
format: "JSONEachRow",
|
|
502
1772
|
clickhouse_settings: {
|
|
1773
|
+
date_time_input_format: "best_effort",
|
|
1774
|
+
date_time_output_format: "iso",
|
|
1775
|
+
use_client_time_zone: 1,
|
|
503
1776
|
output_format_json_quote_64bit_integers: 0
|
|
504
1777
|
}
|
|
505
1778
|
});
|
|
1779
|
+
const rows = await result.json();
|
|
1780
|
+
const scores = Array.isArray(rows) ? rows.map((row) => this.transformScoreRow(row)) : [];
|
|
1781
|
+
return {
|
|
1782
|
+
pagination: {
|
|
1783
|
+
total,
|
|
1784
|
+
page,
|
|
1785
|
+
perPage: perPageForResponse,
|
|
1786
|
+
hasMore: end < total
|
|
1787
|
+
},
|
|
1788
|
+
scores
|
|
1789
|
+
};
|
|
506
1790
|
} catch (error) {
|
|
507
|
-
|
|
508
|
-
|
|
1791
|
+
throw new MastraError(
|
|
1792
|
+
{
|
|
1793
|
+
id: "CLICKHOUSE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
1794
|
+
domain: ErrorDomain.STORAGE,
|
|
1795
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1796
|
+
details: { scorerId }
|
|
1797
|
+
},
|
|
1798
|
+
error
|
|
1799
|
+
);
|
|
509
1800
|
}
|
|
510
1801
|
}
|
|
511
|
-
async
|
|
1802
|
+
async listScoresByEntityId({
|
|
1803
|
+
entityId,
|
|
1804
|
+
entityType,
|
|
1805
|
+
pagination
|
|
1806
|
+
}) {
|
|
512
1807
|
try {
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
m.type as type,
|
|
533
|
-
m.createdAt as createdAt,
|
|
534
|
-
m.updatedAt as updatedAt,
|
|
535
|
-
m.thread_id AS "threadId"
|
|
536
|
-
FROM ordered_messages m
|
|
537
|
-
WHERE m.id = ANY({var_include:Array(String)})
|
|
538
|
-
OR EXISTS (
|
|
539
|
-
SELECT 1 FROM ordered_messages target
|
|
540
|
-
WHERE target.id = ANY({var_include:Array(String)})
|
|
541
|
-
AND (
|
|
542
|
-
-- Get previous messages based on the max withPreviousMessages
|
|
543
|
-
(m.row_num <= target.row_num + {var_withPreviousMessages:Int64} AND m.row_num > target.row_num)
|
|
544
|
-
OR
|
|
545
|
-
-- Get next messages based on the max withNextMessages
|
|
546
|
-
(m.row_num >= target.row_num - {var_withNextMessages:Int64} AND m.row_num < target.row_num)
|
|
547
|
-
)
|
|
548
|
-
)
|
|
549
|
-
ORDER BY m."createdAt" DESC
|
|
550
|
-
`,
|
|
551
|
-
query_params: {
|
|
552
|
-
var_thread_id: threadId,
|
|
553
|
-
var_include: include.map((i) => i.id),
|
|
554
|
-
var_withPreviousMessages: Math.max(...include.map((i) => i.withPreviousMessages || 0)),
|
|
555
|
-
var_withNextMessages: Math.max(...include.map((i) => i.withNextMessages || 0))
|
|
1808
|
+
const countResult = await this.client.query({
|
|
1809
|
+
query: `SELECT COUNT(*) as count FROM ${TABLE_SCORERS} WHERE entityId = {var_entityId:String} AND entityType = {var_entityType:String}`,
|
|
1810
|
+
query_params: { var_entityId: entityId, var_entityType: entityType },
|
|
1811
|
+
format: "JSONEachRow"
|
|
1812
|
+
});
|
|
1813
|
+
const countRows = await countResult.json();
|
|
1814
|
+
let total = 0;
|
|
1815
|
+
if (Array.isArray(countRows) && countRows.length > 0 && countRows[0]) {
|
|
1816
|
+
const countObj = countRows[0];
|
|
1817
|
+
total = Number(countObj.count);
|
|
1818
|
+
}
|
|
1819
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1820
|
+
if (!total) {
|
|
1821
|
+
return {
|
|
1822
|
+
pagination: {
|
|
1823
|
+
total: 0,
|
|
1824
|
+
page,
|
|
1825
|
+
perPage: perPageInput,
|
|
1826
|
+
hasMore: false
|
|
556
1827
|
},
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
date_time_input_format: "best_effort",
|
|
560
|
-
date_time_output_format: "iso",
|
|
561
|
-
use_client_time_zone: 1,
|
|
562
|
-
output_format_json_quote_64bit_integers: 0
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
|
-
const rows2 = await includeResult.json();
|
|
566
|
-
messages.push(...transformRows(rows2.data));
|
|
1828
|
+
scores: []
|
|
1829
|
+
};
|
|
567
1830
|
}
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
type,
|
|
575
|
-
toDateTime64(createdAt, 3) as createdAt,
|
|
576
|
-
thread_id AS "threadId"
|
|
577
|
-
FROM "${TABLE_MESSAGES}"
|
|
578
|
-
WHERE thread_id = {threadId:String}
|
|
579
|
-
AND id NOT IN ({exclude:Array(String)})
|
|
580
|
-
ORDER BY "createdAt" DESC
|
|
581
|
-
LIMIT {limit:Int64}
|
|
582
|
-
`,
|
|
1831
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1832
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1833
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
1834
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1835
|
+
const result = await this.client.query({
|
|
1836
|
+
query: `SELECT * FROM ${TABLE_SCORERS} WHERE entityId = {var_entityId:String} AND entityType = {var_entityType:String} ORDER BY createdAt DESC LIMIT {var_limit:Int64} OFFSET {var_offset:Int64}`,
|
|
583
1837
|
query_params: {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
1838
|
+
var_entityId: entityId,
|
|
1839
|
+
var_entityType: entityType,
|
|
1840
|
+
var_limit: limitValue,
|
|
1841
|
+
var_offset: start
|
|
587
1842
|
},
|
|
1843
|
+
format: "JSONEachRow",
|
|
588
1844
|
clickhouse_settings: {
|
|
589
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
590
1845
|
date_time_input_format: "best_effort",
|
|
591
1846
|
date_time_output_format: "iso",
|
|
592
1847
|
use_client_time_zone: 1,
|
|
@@ -594,80 +1849,154 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
594
1849
|
}
|
|
595
1850
|
});
|
|
596
1851
|
const rows = await result.json();
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
return messages;
|
|
1852
|
+
const scores = Array.isArray(rows) ? rows.map((row) => this.transformScoreRow(row)) : [];
|
|
1853
|
+
return {
|
|
1854
|
+
pagination: {
|
|
1855
|
+
total,
|
|
1856
|
+
page,
|
|
1857
|
+
perPage: perPageForResponse,
|
|
1858
|
+
hasMore: end < total
|
|
1859
|
+
},
|
|
1860
|
+
scores
|
|
1861
|
+
};
|
|
608
1862
|
} catch (error) {
|
|
609
|
-
|
|
610
|
-
|
|
1863
|
+
throw new MastraError(
|
|
1864
|
+
{
|
|
1865
|
+
id: "CLICKHOUSE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1866
|
+
domain: ErrorDomain.STORAGE,
|
|
1867
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1868
|
+
details: { entityId, entityType }
|
|
1869
|
+
},
|
|
1870
|
+
error
|
|
1871
|
+
);
|
|
611
1872
|
}
|
|
612
1873
|
}
|
|
613
|
-
async
|
|
614
|
-
|
|
1874
|
+
async listScoresBySpan({
|
|
1875
|
+
traceId,
|
|
1876
|
+
spanId,
|
|
1877
|
+
pagination
|
|
1878
|
+
}) {
|
|
615
1879
|
try {
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
1880
|
+
const countResult = await this.client.query({
|
|
1881
|
+
query: `SELECT COUNT(*) as count FROM ${TABLE_SCORERS} WHERE traceId = {var_traceId:String} AND spanId = {var_spanId:String}`,
|
|
1882
|
+
query_params: {
|
|
1883
|
+
var_traceId: traceId,
|
|
1884
|
+
var_spanId: spanId
|
|
1885
|
+
},
|
|
1886
|
+
format: "JSONEachRow"
|
|
1887
|
+
});
|
|
1888
|
+
const countRows = await countResult.json();
|
|
1889
|
+
let total = 0;
|
|
1890
|
+
if (Array.isArray(countRows) && countRows.length > 0 && countRows[0]) {
|
|
1891
|
+
const countObj = countRows[0];
|
|
1892
|
+
total = Number(countObj.count);
|
|
619
1893
|
}
|
|
620
|
-
const
|
|
621
|
-
if (!
|
|
622
|
-
|
|
1894
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1895
|
+
if (!total) {
|
|
1896
|
+
return {
|
|
1897
|
+
pagination: {
|
|
1898
|
+
total: 0,
|
|
1899
|
+
page,
|
|
1900
|
+
perPage: perPageInput,
|
|
1901
|
+
hasMore: false
|
|
1902
|
+
},
|
|
1903
|
+
scores: []
|
|
1904
|
+
};
|
|
623
1905
|
}
|
|
624
|
-
|
|
625
|
-
|
|
1906
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1907
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1908
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
1909
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1910
|
+
const result = await this.client.query({
|
|
1911
|
+
query: `SELECT * FROM ${TABLE_SCORERS} WHERE traceId = {var_traceId:String} AND spanId = {var_spanId:String} ORDER BY createdAt DESC LIMIT {var_limit:Int64} OFFSET {var_offset:Int64}`,
|
|
1912
|
+
query_params: {
|
|
1913
|
+
var_traceId: traceId,
|
|
1914
|
+
var_spanId: spanId,
|
|
1915
|
+
var_limit: limitValue,
|
|
1916
|
+
var_offset: start
|
|
1917
|
+
},
|
|
626
1918
|
format: "JSONEachRow",
|
|
627
|
-
values: messages.map((message) => ({
|
|
628
|
-
id: message.id,
|
|
629
|
-
thread_id: threadId,
|
|
630
|
-
content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
631
|
-
createdAt: message.createdAt.toISOString(),
|
|
632
|
-
role: message.role,
|
|
633
|
-
type: message.type
|
|
634
|
-
})),
|
|
635
1919
|
clickhouse_settings: {
|
|
636
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
637
1920
|
date_time_input_format: "best_effort",
|
|
1921
|
+
date_time_output_format: "iso",
|
|
638
1922
|
use_client_time_zone: 1,
|
|
639
1923
|
output_format_json_quote_64bit_integers: 0
|
|
640
1924
|
}
|
|
641
1925
|
});
|
|
642
|
-
|
|
1926
|
+
const rows = await result.json();
|
|
1927
|
+
const scores = Array.isArray(rows) ? rows.map((row) => this.transformScoreRow(row)) : [];
|
|
1928
|
+
return {
|
|
1929
|
+
pagination: {
|
|
1930
|
+
total,
|
|
1931
|
+
page,
|
|
1932
|
+
perPage: perPageForResponse,
|
|
1933
|
+
hasMore: end < total
|
|
1934
|
+
},
|
|
1935
|
+
scores
|
|
1936
|
+
};
|
|
643
1937
|
} catch (error) {
|
|
644
|
-
|
|
645
|
-
|
|
1938
|
+
throw new MastraError(
|
|
1939
|
+
{
|
|
1940
|
+
id: "CLICKHOUSE_STORAGE_GET_SCORES_BY_SPAN_FAILED",
|
|
1941
|
+
domain: ErrorDomain.STORAGE,
|
|
1942
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1943
|
+
details: { traceId, spanId }
|
|
1944
|
+
},
|
|
1945
|
+
error
|
|
1946
|
+
);
|
|
646
1947
|
}
|
|
647
1948
|
}
|
|
1949
|
+
};
|
|
1950
|
+
var WorkflowsStorageClickhouse = class extends WorkflowsStorage {
|
|
1951
|
+
client;
|
|
1952
|
+
operations;
|
|
1953
|
+
constructor({ client, operations }) {
|
|
1954
|
+
super();
|
|
1955
|
+
this.operations = operations;
|
|
1956
|
+
this.client = client;
|
|
1957
|
+
}
|
|
1958
|
+
updateWorkflowResults({
|
|
1959
|
+
// workflowName,
|
|
1960
|
+
// runId,
|
|
1961
|
+
// stepId,
|
|
1962
|
+
// result,
|
|
1963
|
+
// requestContext,
|
|
1964
|
+
}) {
|
|
1965
|
+
throw new Error("Method not implemented.");
|
|
1966
|
+
}
|
|
1967
|
+
updateWorkflowState({
|
|
1968
|
+
// workflowName,
|
|
1969
|
+
// runId,
|
|
1970
|
+
// opts,
|
|
1971
|
+
}) {
|
|
1972
|
+
throw new Error("Method not implemented.");
|
|
1973
|
+
}
|
|
648
1974
|
async persistWorkflowSnapshot({
|
|
649
1975
|
workflowName,
|
|
650
1976
|
runId,
|
|
1977
|
+
resourceId,
|
|
651
1978
|
snapshot
|
|
652
1979
|
}) {
|
|
653
1980
|
try {
|
|
654
|
-
const currentSnapshot = await this.load({
|
|
1981
|
+
const currentSnapshot = await this.operations.load({
|
|
655
1982
|
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
656
1983
|
keys: { workflow_name: workflowName, run_id: runId }
|
|
657
1984
|
});
|
|
658
1985
|
const now = /* @__PURE__ */ new Date();
|
|
659
1986
|
const persisting = currentSnapshot ? {
|
|
660
1987
|
...currentSnapshot,
|
|
1988
|
+
resourceId,
|
|
661
1989
|
snapshot: JSON.stringify(snapshot),
|
|
662
1990
|
updatedAt: now.toISOString()
|
|
663
1991
|
} : {
|
|
664
1992
|
workflow_name: workflowName,
|
|
665
1993
|
run_id: runId,
|
|
1994
|
+
resourceId,
|
|
666
1995
|
snapshot: JSON.stringify(snapshot),
|
|
667
1996
|
createdAt: now.toISOString(),
|
|
668
1997
|
updatedAt: now.toISOString()
|
|
669
1998
|
};
|
|
670
|
-
await this.
|
|
1999
|
+
await this.client.insert({
|
|
671
2000
|
table: TABLE_WORKFLOW_SNAPSHOT,
|
|
672
2001
|
format: "JSONEachRow",
|
|
673
2002
|
values: [persisting],
|
|
@@ -679,8 +2008,15 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
679
2008
|
}
|
|
680
2009
|
});
|
|
681
2010
|
} catch (error) {
|
|
682
|
-
|
|
683
|
-
|
|
2011
|
+
throw new MastraError(
|
|
2012
|
+
{
|
|
2013
|
+
id: "CLICKHOUSE_STORAGE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
2014
|
+
domain: ErrorDomain.STORAGE,
|
|
2015
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2016
|
+
details: { workflowName, runId }
|
|
2017
|
+
},
|
|
2018
|
+
error
|
|
2019
|
+
);
|
|
684
2020
|
}
|
|
685
2021
|
}
|
|
686
2022
|
async loadWorkflowSnapshot({
|
|
@@ -688,7 +2024,7 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
688
2024
|
runId
|
|
689
2025
|
}) {
|
|
690
2026
|
try {
|
|
691
|
-
const result = await this.load({
|
|
2027
|
+
const result = await this.operations.load({
|
|
692
2028
|
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
693
2029
|
keys: {
|
|
694
2030
|
workflow_name: workflowName,
|
|
@@ -700,8 +2036,15 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
700
2036
|
}
|
|
701
2037
|
return result.snapshot;
|
|
702
2038
|
} catch (error) {
|
|
703
|
-
|
|
704
|
-
|
|
2039
|
+
throw new MastraError(
|
|
2040
|
+
{
|
|
2041
|
+
id: "CLICKHOUSE_STORAGE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
2042
|
+
domain: ErrorDomain.STORAGE,
|
|
2043
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2044
|
+
details: { workflowName, runId }
|
|
2045
|
+
},
|
|
2046
|
+
error
|
|
2047
|
+
);
|
|
705
2048
|
}
|
|
706
2049
|
}
|
|
707
2050
|
parseWorkflowRun(row) {
|
|
@@ -722,12 +2065,12 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
722
2065
|
resourceId: row.resourceId
|
|
723
2066
|
};
|
|
724
2067
|
}
|
|
725
|
-
async
|
|
2068
|
+
async listWorkflowRuns({
|
|
726
2069
|
workflowName,
|
|
727
2070
|
fromDate,
|
|
728
2071
|
toDate,
|
|
729
|
-
|
|
730
|
-
|
|
2072
|
+
page,
|
|
2073
|
+
perPage,
|
|
731
2074
|
resourceId
|
|
732
2075
|
} = {}) {
|
|
733
2076
|
try {
|
|
@@ -738,7 +2081,7 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
738
2081
|
values.var_workflow_name = workflowName;
|
|
739
2082
|
}
|
|
740
2083
|
if (resourceId) {
|
|
741
|
-
const hasResourceId = await this.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2084
|
+
const hasResourceId = await this.operations.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
742
2085
|
if (hasResourceId) {
|
|
743
2086
|
conditions.push(`resourceId = {var_resourceId:String}`);
|
|
744
2087
|
values.var_resourceId = resourceId;
|
|
@@ -755,11 +2098,14 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
755
2098
|
values.var_to_date = toDate.getTime() / 1e3;
|
|
756
2099
|
}
|
|
757
2100
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
758
|
-
const
|
|
759
|
-
const
|
|
2101
|
+
const usePagination = perPage !== void 0 && page !== void 0;
|
|
2102
|
+
const normalizedPerPage = usePagination ? normalizePerPage(perPage, Number.MAX_SAFE_INTEGER) : 0;
|
|
2103
|
+
const offset = usePagination ? page * normalizedPerPage : 0;
|
|
2104
|
+
const limitClause = usePagination ? `LIMIT ${normalizedPerPage}` : "";
|
|
2105
|
+
const offsetClause = usePagination ? `OFFSET ${offset}` : "";
|
|
760
2106
|
let total = 0;
|
|
761
|
-
if (
|
|
762
|
-
const countResult = await this.
|
|
2107
|
+
if (usePagination) {
|
|
2108
|
+
const countResult = await this.client.query({
|
|
763
2109
|
query: `SELECT COUNT(*) as count FROM ${TABLE_WORKFLOW_SNAPSHOT} ${TABLE_ENGINES[TABLE_WORKFLOW_SNAPSHOT].startsWith("ReplacingMergeTree") ? "FINAL" : ""} ${whereClause}`,
|
|
764
2110
|
query_params: values,
|
|
765
2111
|
format: "JSONEachRow"
|
|
@@ -767,21 +2113,21 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
767
2113
|
const countRows = await countResult.json();
|
|
768
2114
|
total = Number(countRows[0]?.count ?? 0);
|
|
769
2115
|
}
|
|
770
|
-
const result = await this.
|
|
2116
|
+
const result = await this.client.query({
|
|
771
2117
|
query: `
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
2118
|
+
SELECT
|
|
2119
|
+
workflow_name,
|
|
2120
|
+
run_id,
|
|
2121
|
+
snapshot,
|
|
2122
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
2123
|
+
toDateTime64(updatedAt, 3) as updatedAt,
|
|
2124
|
+
resourceId
|
|
2125
|
+
FROM ${TABLE_WORKFLOW_SNAPSHOT} ${TABLE_ENGINES[TABLE_WORKFLOW_SNAPSHOT].startsWith("ReplacingMergeTree") ? "FINAL" : ""}
|
|
2126
|
+
${whereClause}
|
|
2127
|
+
ORDER BY createdAt DESC
|
|
2128
|
+
${limitClause}
|
|
2129
|
+
${offsetClause}
|
|
2130
|
+
`,
|
|
785
2131
|
query_params: values,
|
|
786
2132
|
format: "JSONEachRow"
|
|
787
2133
|
});
|
|
@@ -792,8 +2138,15 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
792
2138
|
});
|
|
793
2139
|
return { runs, total: total || runs.length };
|
|
794
2140
|
} catch (error) {
|
|
795
|
-
|
|
796
|
-
|
|
2141
|
+
throw new MastraError(
|
|
2142
|
+
{
|
|
2143
|
+
id: "CLICKHOUSE_STORAGE_LIST_WORKFLOW_RUNS_FAILED",
|
|
2144
|
+
domain: ErrorDomain.STORAGE,
|
|
2145
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2146
|
+
details: { workflowName: workflowName ?? "", resourceId: resourceId ?? "" }
|
|
2147
|
+
},
|
|
2148
|
+
error
|
|
2149
|
+
);
|
|
797
2150
|
}
|
|
798
2151
|
}
|
|
799
2152
|
async getWorkflowRunById({
|
|
@@ -812,18 +2165,19 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
812
2165
|
values.var_workflow_name = workflowName;
|
|
813
2166
|
}
|
|
814
2167
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
815
|
-
const result = await this.
|
|
2168
|
+
const result = await this.client.query({
|
|
816
2169
|
query: `
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
2170
|
+
SELECT
|
|
2171
|
+
workflow_name,
|
|
2172
|
+
run_id,
|
|
2173
|
+
snapshot,
|
|
2174
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
2175
|
+
toDateTime64(updatedAt, 3) as updatedAt,
|
|
2176
|
+
resourceId
|
|
2177
|
+
FROM ${TABLE_WORKFLOW_SNAPSHOT} ${TABLE_ENGINES[TABLE_WORKFLOW_SNAPSHOT].startsWith("ReplacingMergeTree") ? "FINAL" : ""}
|
|
2178
|
+
${whereClause}
|
|
2179
|
+
ORDER BY createdAt DESC LIMIT 1
|
|
2180
|
+
`,
|
|
827
2181
|
query_params: values,
|
|
828
2182
|
format: "JSONEachRow"
|
|
829
2183
|
});
|
|
@@ -833,17 +2187,244 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
833
2187
|
}
|
|
834
2188
|
return this.parseWorkflowRun(resultJson[0]);
|
|
835
2189
|
} catch (error) {
|
|
836
|
-
|
|
837
|
-
|
|
2190
|
+
throw new MastraError(
|
|
2191
|
+
{
|
|
2192
|
+
id: "CLICKHOUSE_STORAGE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
2193
|
+
domain: ErrorDomain.STORAGE,
|
|
2194
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2195
|
+
details: { runId: runId ?? "", workflowName: workflowName ?? "" }
|
|
2196
|
+
},
|
|
2197
|
+
error
|
|
2198
|
+
);
|
|
838
2199
|
}
|
|
839
2200
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
2201
|
+
};
|
|
2202
|
+
|
|
2203
|
+
// src/storage/index.ts
|
|
2204
|
+
var ClickhouseStore = class extends MastraStorage {
|
|
2205
|
+
db;
|
|
2206
|
+
ttl = {};
|
|
2207
|
+
stores;
|
|
2208
|
+
constructor(config) {
|
|
2209
|
+
super({ name: "ClickhouseStore" });
|
|
2210
|
+
this.db = createClient({
|
|
2211
|
+
url: config.url,
|
|
2212
|
+
username: config.username,
|
|
2213
|
+
password: config.password,
|
|
2214
|
+
clickhouse_settings: {
|
|
2215
|
+
date_time_input_format: "best_effort",
|
|
2216
|
+
date_time_output_format: "iso",
|
|
2217
|
+
// This is crucial
|
|
2218
|
+
use_client_time_zone: 1,
|
|
2219
|
+
output_format_json_quote_64bit_integers: 0
|
|
2220
|
+
}
|
|
844
2221
|
});
|
|
845
|
-
|
|
846
|
-
|
|
2222
|
+
this.ttl = config.ttl;
|
|
2223
|
+
const operations = new StoreOperationsClickhouse({ client: this.db, ttl: this.ttl });
|
|
2224
|
+
const workflows = new WorkflowsStorageClickhouse({ client: this.db, operations });
|
|
2225
|
+
const scores = new ScoresStorageClickhouse({ client: this.db, operations });
|
|
2226
|
+
const memory = new MemoryStorageClickhouse({ client: this.db, operations });
|
|
2227
|
+
this.stores = {
|
|
2228
|
+
operations,
|
|
2229
|
+
workflows,
|
|
2230
|
+
scores,
|
|
2231
|
+
memory
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
get supports() {
|
|
2235
|
+
return {
|
|
2236
|
+
selectByIncludeResourceScope: true,
|
|
2237
|
+
resourceWorkingMemory: true,
|
|
2238
|
+
hasColumn: true,
|
|
2239
|
+
createTable: true,
|
|
2240
|
+
deleteMessages: false,
|
|
2241
|
+
listScoresBySpan: true
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
async batchInsert({ tableName, records }) {
|
|
2245
|
+
await this.stores.operations.batchInsert({ tableName, records });
|
|
2246
|
+
}
|
|
2247
|
+
async optimizeTable({ tableName }) {
|
|
2248
|
+
try {
|
|
2249
|
+
await this.db.command({
|
|
2250
|
+
query: `OPTIMIZE TABLE ${tableName} FINAL`
|
|
2251
|
+
});
|
|
2252
|
+
} catch (error) {
|
|
2253
|
+
throw new MastraError(
|
|
2254
|
+
{
|
|
2255
|
+
id: "CLICKHOUSE_STORAGE_OPTIMIZE_TABLE_FAILED",
|
|
2256
|
+
domain: ErrorDomain.STORAGE,
|
|
2257
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2258
|
+
details: { tableName }
|
|
2259
|
+
},
|
|
2260
|
+
error
|
|
2261
|
+
);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
async materializeTtl({ tableName }) {
|
|
2265
|
+
try {
|
|
2266
|
+
await this.db.command({
|
|
2267
|
+
query: `ALTER TABLE ${tableName} MATERIALIZE TTL;`
|
|
2268
|
+
});
|
|
2269
|
+
} catch (error) {
|
|
2270
|
+
throw new MastraError(
|
|
2271
|
+
{
|
|
2272
|
+
id: "CLICKHOUSE_STORAGE_MATERIALIZE_TTL_FAILED",
|
|
2273
|
+
domain: ErrorDomain.STORAGE,
|
|
2274
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2275
|
+
details: { tableName }
|
|
2276
|
+
},
|
|
2277
|
+
error
|
|
2278
|
+
);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
async createTable({
|
|
2282
|
+
tableName,
|
|
2283
|
+
schema
|
|
2284
|
+
}) {
|
|
2285
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
2286
|
+
}
|
|
2287
|
+
async dropTable({ tableName }) {
|
|
2288
|
+
return this.stores.operations.dropTable({ tableName });
|
|
2289
|
+
}
|
|
2290
|
+
async alterTable({
|
|
2291
|
+
tableName,
|
|
2292
|
+
schema,
|
|
2293
|
+
ifNotExists
|
|
2294
|
+
}) {
|
|
2295
|
+
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2296
|
+
}
|
|
2297
|
+
async clearTable({ tableName }) {
|
|
2298
|
+
return this.stores.operations.clearTable({ tableName });
|
|
2299
|
+
}
|
|
2300
|
+
async insert({ tableName, record }) {
|
|
2301
|
+
return this.stores.operations.insert({ tableName, record });
|
|
2302
|
+
}
|
|
2303
|
+
async load({ tableName, keys }) {
|
|
2304
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2305
|
+
}
|
|
2306
|
+
async updateWorkflowResults({
|
|
2307
|
+
workflowName,
|
|
2308
|
+
runId,
|
|
2309
|
+
stepId,
|
|
2310
|
+
result,
|
|
2311
|
+
requestContext
|
|
2312
|
+
}) {
|
|
2313
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2314
|
+
}
|
|
2315
|
+
async updateWorkflowState({
|
|
2316
|
+
workflowName,
|
|
2317
|
+
runId,
|
|
2318
|
+
opts
|
|
2319
|
+
}) {
|
|
2320
|
+
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2321
|
+
}
|
|
2322
|
+
async persistWorkflowSnapshot({
|
|
2323
|
+
workflowName,
|
|
2324
|
+
runId,
|
|
2325
|
+
resourceId,
|
|
2326
|
+
snapshot
|
|
2327
|
+
}) {
|
|
2328
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2329
|
+
}
|
|
2330
|
+
async loadWorkflowSnapshot({
|
|
2331
|
+
workflowName,
|
|
2332
|
+
runId
|
|
2333
|
+
}) {
|
|
2334
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2335
|
+
}
|
|
2336
|
+
async listWorkflowRuns({
|
|
2337
|
+
workflowName,
|
|
2338
|
+
fromDate,
|
|
2339
|
+
toDate,
|
|
2340
|
+
perPage,
|
|
2341
|
+
page,
|
|
2342
|
+
resourceId
|
|
2343
|
+
} = {}) {
|
|
2344
|
+
return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId });
|
|
2345
|
+
}
|
|
2346
|
+
async getWorkflowRunById({
|
|
2347
|
+
runId,
|
|
2348
|
+
workflowName
|
|
2349
|
+
}) {
|
|
2350
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2351
|
+
}
|
|
2352
|
+
async getThreadById({ threadId }) {
|
|
2353
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2354
|
+
}
|
|
2355
|
+
async saveThread({ thread }) {
|
|
2356
|
+
return this.stores.memory.saveThread({ thread });
|
|
2357
|
+
}
|
|
2358
|
+
async updateThread({
|
|
2359
|
+
id,
|
|
2360
|
+
title,
|
|
2361
|
+
metadata
|
|
2362
|
+
}) {
|
|
2363
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2364
|
+
}
|
|
2365
|
+
async deleteThread({ threadId }) {
|
|
2366
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2367
|
+
}
|
|
2368
|
+
async getMessages({
|
|
2369
|
+
threadId,
|
|
2370
|
+
resourceId,
|
|
2371
|
+
selectBy
|
|
2372
|
+
}) {
|
|
2373
|
+
return this.stores.memory.getMessages({ threadId, resourceId, selectBy });
|
|
2374
|
+
}
|
|
2375
|
+
async saveMessages(args) {
|
|
2376
|
+
return this.stores.memory.saveMessages(args);
|
|
2377
|
+
}
|
|
2378
|
+
async updateMessages(args) {
|
|
2379
|
+
return this.stores.memory.updateMessages(args);
|
|
2380
|
+
}
|
|
2381
|
+
async getResourceById({ resourceId }) {
|
|
2382
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2383
|
+
}
|
|
2384
|
+
async saveResource({ resource }) {
|
|
2385
|
+
return this.stores.memory.saveResource({ resource });
|
|
2386
|
+
}
|
|
2387
|
+
async updateResource({
|
|
2388
|
+
resourceId,
|
|
2389
|
+
workingMemory,
|
|
2390
|
+
metadata
|
|
2391
|
+
}) {
|
|
2392
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2393
|
+
}
|
|
2394
|
+
async getScoreById({ id }) {
|
|
2395
|
+
return this.stores.scores.getScoreById({ id });
|
|
2396
|
+
}
|
|
2397
|
+
async saveScore(_score) {
|
|
2398
|
+
return this.stores.scores.saveScore(_score);
|
|
2399
|
+
}
|
|
2400
|
+
async listScoresByRunId({
|
|
2401
|
+
runId,
|
|
2402
|
+
pagination
|
|
2403
|
+
}) {
|
|
2404
|
+
return this.stores.scores.listScoresByRunId({ runId, pagination });
|
|
2405
|
+
}
|
|
2406
|
+
async listScoresByEntityId({
|
|
2407
|
+
entityId,
|
|
2408
|
+
entityType,
|
|
2409
|
+
pagination
|
|
2410
|
+
}) {
|
|
2411
|
+
return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
|
|
2412
|
+
}
|
|
2413
|
+
async listScoresByScorerId({
|
|
2414
|
+
scorerId,
|
|
2415
|
+
pagination,
|
|
2416
|
+
entityId,
|
|
2417
|
+
entityType,
|
|
2418
|
+
source
|
|
2419
|
+
}) {
|
|
2420
|
+
return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
|
|
2421
|
+
}
|
|
2422
|
+
async listScoresBySpan({
|
|
2423
|
+
traceId,
|
|
2424
|
+
spanId,
|
|
2425
|
+
pagination
|
|
2426
|
+
}) {
|
|
2427
|
+
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
847
2428
|
}
|
|
848
2429
|
async close() {
|
|
849
2430
|
await this.db.close();
|
|
@@ -851,3 +2432,5 @@ var ClickhouseStore = class extends MastraStorage {
|
|
|
851
2432
|
};
|
|
852
2433
|
|
|
853
2434
|
export { COLUMN_TYPES, ClickhouseStore, TABLE_ENGINES };
|
|
2435
|
+
//# sourceMappingURL=index.js.map
|
|
2436
|
+
//# sourceMappingURL=index.js.map
|