@mastra/clickhouse 0.0.0-vnext-20251104230439 → 0.0.0-vnext-20251119160359
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 +341 -3
- package/README.md +47 -21
- package/dist/index.cjs +64 -164
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +65 -165
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +1 -4
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/operations/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +1 -1
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +3 -5
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +12 -7
package/dist/index.cjs
CHANGED
|
@@ -14,8 +14,8 @@ var TABLE_ENGINES = {
|
|
|
14
14
|
[storage.TABLE_THREADS]: `ReplacingMergeTree()`,
|
|
15
15
|
[storage.TABLE_SCORERS]: `MergeTree()`,
|
|
16
16
|
[storage.TABLE_RESOURCES]: `ReplacingMergeTree()`,
|
|
17
|
-
// TODO: verify this is the correct engine for
|
|
18
|
-
[storage.
|
|
17
|
+
// TODO: verify this is the correct engine for Spans when implementing clickhouse storage
|
|
18
|
+
[storage.TABLE_SPANS]: `ReplacingMergeTree()`
|
|
19
19
|
};
|
|
20
20
|
var COLUMN_TYPES = {
|
|
21
21
|
text: "String",
|
|
@@ -47,6 +47,24 @@ function transformRows(rows) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// src/storage/domains/memory/index.ts
|
|
50
|
+
function serializeMetadata(metadata) {
|
|
51
|
+
if (!metadata || Object.keys(metadata).length === 0) {
|
|
52
|
+
return "{}";
|
|
53
|
+
}
|
|
54
|
+
return JSON.stringify(metadata);
|
|
55
|
+
}
|
|
56
|
+
function parseMetadata(metadata) {
|
|
57
|
+
if (!metadata) return {};
|
|
58
|
+
if (typeof metadata === "object") return metadata;
|
|
59
|
+
if (typeof metadata !== "string") return {};
|
|
60
|
+
const trimmed = metadata.trim();
|
|
61
|
+
if (trimmed === "" || trimmed === "null") return {};
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(trimmed);
|
|
64
|
+
} catch {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
50
68
|
var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
51
69
|
client;
|
|
52
70
|
operations;
|
|
@@ -55,135 +73,6 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
55
73
|
this.client = client;
|
|
56
74
|
this.operations = operations;
|
|
57
75
|
}
|
|
58
|
-
async getMessages({
|
|
59
|
-
threadId,
|
|
60
|
-
resourceId,
|
|
61
|
-
selectBy
|
|
62
|
-
}) {
|
|
63
|
-
try {
|
|
64
|
-
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
65
|
-
const messages = [];
|
|
66
|
-
const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
67
|
-
const include = selectBy?.include || [];
|
|
68
|
-
if (include.length) {
|
|
69
|
-
const unionQueries = [];
|
|
70
|
-
const params = [];
|
|
71
|
-
let paramIdx = 1;
|
|
72
|
-
for (const inc of include) {
|
|
73
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
74
|
-
const searchId = inc.threadId || threadId;
|
|
75
|
-
unionQueries.push(`
|
|
76
|
-
SELECT * FROM (
|
|
77
|
-
WITH numbered_messages AS (
|
|
78
|
-
SELECT
|
|
79
|
-
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
80
|
-
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
81
|
-
FROM "${storage.TABLE_MESSAGES}"
|
|
82
|
-
WHERE thread_id = {var_thread_id_${paramIdx}:String}
|
|
83
|
-
),
|
|
84
|
-
target_positions AS (
|
|
85
|
-
SELECT row_num as target_pos
|
|
86
|
-
FROM numbered_messages
|
|
87
|
-
WHERE id = {var_include_id_${paramIdx}:String}
|
|
88
|
-
)
|
|
89
|
-
SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId"
|
|
90
|
-
FROM numbered_messages m
|
|
91
|
-
CROSS JOIN target_positions t
|
|
92
|
-
WHERE m.row_num BETWEEN (t.target_pos - {var_withPreviousMessages_${paramIdx}:Int64}) AND (t.target_pos + {var_withNextMessages_${paramIdx}:Int64})
|
|
93
|
-
) AS query_${paramIdx}
|
|
94
|
-
`);
|
|
95
|
-
params.push(
|
|
96
|
-
{ [`var_thread_id_${paramIdx}`]: searchId },
|
|
97
|
-
{ [`var_include_id_${paramIdx}`]: id },
|
|
98
|
-
{ [`var_withPreviousMessages_${paramIdx}`]: withPreviousMessages },
|
|
99
|
-
{ [`var_withNextMessages_${paramIdx}`]: withNextMessages }
|
|
100
|
-
);
|
|
101
|
-
paramIdx++;
|
|
102
|
-
}
|
|
103
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" DESC';
|
|
104
|
-
const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
|
|
105
|
-
const includeResult = await this.client.query({
|
|
106
|
-
query: finalQuery,
|
|
107
|
-
query_params: mergedParams,
|
|
108
|
-
clickhouse_settings: {
|
|
109
|
-
date_time_input_format: "best_effort",
|
|
110
|
-
date_time_output_format: "iso",
|
|
111
|
-
use_client_time_zone: 1,
|
|
112
|
-
output_format_json_quote_64bit_integers: 0
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
const rows2 = await includeResult.json();
|
|
116
|
-
const includedMessages = transformRows(rows2.data);
|
|
117
|
-
const seen = /* @__PURE__ */ new Set();
|
|
118
|
-
const dedupedMessages = includedMessages.filter((message) => {
|
|
119
|
-
if (seen.has(message.id)) return false;
|
|
120
|
-
seen.add(message.id);
|
|
121
|
-
return true;
|
|
122
|
-
});
|
|
123
|
-
messages.push(...dedupedMessages);
|
|
124
|
-
}
|
|
125
|
-
let whereClause = "WHERE thread_id = {threadId:String}";
|
|
126
|
-
const queryParams = {
|
|
127
|
-
threadId,
|
|
128
|
-
exclude: messages.map((m) => m.id),
|
|
129
|
-
limit
|
|
130
|
-
};
|
|
131
|
-
if (resourceId) {
|
|
132
|
-
whereClause += ' AND "resourceId" = {resourceId:String}';
|
|
133
|
-
queryParams.resourceId = resourceId;
|
|
134
|
-
}
|
|
135
|
-
const result = await this.client.query({
|
|
136
|
-
query: `
|
|
137
|
-
SELECT
|
|
138
|
-
id,
|
|
139
|
-
content,
|
|
140
|
-
role,
|
|
141
|
-
type,
|
|
142
|
-
toDateTime64(createdAt, 3) as createdAt,
|
|
143
|
-
thread_id AS "threadId"
|
|
144
|
-
FROM "${storage.TABLE_MESSAGES}"
|
|
145
|
-
${whereClause}
|
|
146
|
-
AND id NOT IN ({exclude:Array(String)})
|
|
147
|
-
ORDER BY "createdAt" DESC
|
|
148
|
-
LIMIT {limit:Int64}
|
|
149
|
-
`,
|
|
150
|
-
query_params: queryParams,
|
|
151
|
-
clickhouse_settings: {
|
|
152
|
-
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
153
|
-
date_time_input_format: "best_effort",
|
|
154
|
-
date_time_output_format: "iso",
|
|
155
|
-
use_client_time_zone: 1,
|
|
156
|
-
output_format_json_quote_64bit_integers: 0
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
const rows = await result.json();
|
|
160
|
-
messages.push(...transformRows(rows.data));
|
|
161
|
-
messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
162
|
-
messages.forEach((message) => {
|
|
163
|
-
if (typeof message.content === "string") {
|
|
164
|
-
try {
|
|
165
|
-
message.content = JSON.parse(message.content);
|
|
166
|
-
} catch {
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
const list = new agent.MessageList({ threadId, resourceId }).add(
|
|
171
|
-
messages,
|
|
172
|
-
"memory"
|
|
173
|
-
);
|
|
174
|
-
return { messages: list.get.all.db() };
|
|
175
|
-
} catch (error$1) {
|
|
176
|
-
throw new error.MastraError(
|
|
177
|
-
{
|
|
178
|
-
id: "CLICKHOUSE_STORAGE_GET_MESSAGES_FAILED",
|
|
179
|
-
domain: error.ErrorDomain.STORAGE,
|
|
180
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
181
|
-
details: { threadId, resourceId: resourceId ?? "" }
|
|
182
|
-
},
|
|
183
|
-
error$1
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
76
|
async listMessagesById({ messageIds }) {
|
|
188
77
|
if (messageIds.length === 0) return { messages: [] };
|
|
189
78
|
try {
|
|
@@ -290,7 +179,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
290
179
|
dataQuery += ` AND createdAt <= parseDateTime64BestEffort({toDate:String}, 3)`;
|
|
291
180
|
dataParams.toDate = endDate;
|
|
292
181
|
}
|
|
293
|
-
const { field, direction } = this.parseOrderBy(orderBy);
|
|
182
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
294
183
|
dataQuery += ` ORDER BY "${field}" ${direction}`;
|
|
295
184
|
if (perPageForResponse === false) ; else {
|
|
296
185
|
dataQuery += ` LIMIT {limit:Int64} OFFSET {offset:Int64}`;
|
|
@@ -579,7 +468,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
579
468
|
id: thread.id,
|
|
580
469
|
resourceId: thread.resourceId,
|
|
581
470
|
title: thread.title,
|
|
582
|
-
metadata: thread.metadata,
|
|
471
|
+
metadata: serializeMetadata(thread.metadata),
|
|
583
472
|
createdAt: thread.createdAt,
|
|
584
473
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
585
474
|
})),
|
|
@@ -614,8 +503,9 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
614
503
|
toDateTime64(createdAt, 3) as createdAt,
|
|
615
504
|
toDateTime64(updatedAt, 3) as updatedAt
|
|
616
505
|
FROM "${storage.TABLE_THREADS}"
|
|
617
|
-
|
|
618
|
-
|
|
506
|
+
WHERE id = {var_id:String}
|
|
507
|
+
ORDER BY updatedAt DESC
|
|
508
|
+
LIMIT 1`,
|
|
619
509
|
query_params: { var_id: threadId },
|
|
620
510
|
clickhouse_settings: {
|
|
621
511
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -632,7 +522,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
632
522
|
}
|
|
633
523
|
return {
|
|
634
524
|
...thread,
|
|
635
|
-
metadata:
|
|
525
|
+
metadata: parseMetadata(thread.metadata),
|
|
636
526
|
createdAt: thread.createdAt,
|
|
637
527
|
updatedAt: thread.updatedAt
|
|
638
528
|
};
|
|
@@ -655,6 +545,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
655
545
|
values: [
|
|
656
546
|
{
|
|
657
547
|
...thread,
|
|
548
|
+
metadata: serializeMetadata(thread.metadata),
|
|
658
549
|
createdAt: thread.createdAt.toISOString(),
|
|
659
550
|
updatedAt: thread.updatedAt.toISOString()
|
|
660
551
|
}
|
|
@@ -708,7 +599,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
708
599
|
id: updatedThread.id,
|
|
709
600
|
resourceId: updatedThread.resourceId,
|
|
710
601
|
title: updatedThread.title,
|
|
711
|
-
metadata: updatedThread.metadata,
|
|
602
|
+
metadata: serializeMetadata(updatedThread.metadata),
|
|
712
603
|
createdAt: updatedThread.createdAt,
|
|
713
604
|
updatedAt: updatedThread.updatedAt.toISOString()
|
|
714
605
|
}
|
|
@@ -778,7 +669,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
778
669
|
const { field, direction } = this.parseOrderBy(orderBy);
|
|
779
670
|
try {
|
|
780
671
|
const countResult = await this.client.query({
|
|
781
|
-
query: `SELECT count() as total FROM ${storage.TABLE_THREADS} WHERE resourceId = {resourceId:String}`,
|
|
672
|
+
query: `SELECT count(DISTINCT id) as total FROM ${storage.TABLE_THREADS} WHERE resourceId = {resourceId:String}`,
|
|
782
673
|
query_params: { resourceId },
|
|
783
674
|
clickhouse_settings: {
|
|
784
675
|
date_time_input_format: "best_effort",
|
|
@@ -800,15 +691,27 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
800
691
|
}
|
|
801
692
|
const dataResult = await this.client.query({
|
|
802
693
|
query: `
|
|
694
|
+
WITH ranked_threads AS (
|
|
695
|
+
SELECT
|
|
696
|
+
id,
|
|
697
|
+
resourceId,
|
|
698
|
+
title,
|
|
699
|
+
metadata,
|
|
700
|
+
toDateTime64(createdAt, 3) as createdAt,
|
|
701
|
+
toDateTime64(updatedAt, 3) as updatedAt,
|
|
702
|
+
ROW_NUMBER() OVER (PARTITION BY id ORDER BY updatedAt DESC) as row_num
|
|
703
|
+
FROM ${storage.TABLE_THREADS}
|
|
704
|
+
WHERE resourceId = {resourceId:String}
|
|
705
|
+
)
|
|
803
706
|
SELECT
|
|
804
707
|
id,
|
|
805
708
|
resourceId,
|
|
806
709
|
title,
|
|
807
710
|
metadata,
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
FROM
|
|
811
|
-
WHERE
|
|
711
|
+
createdAt,
|
|
712
|
+
updatedAt
|
|
713
|
+
FROM ranked_threads
|
|
714
|
+
WHERE row_num = 1
|
|
812
715
|
ORDER BY "${field}" ${direction === "DESC" ? "DESC" : "ASC"}
|
|
813
716
|
LIMIT {perPage:Int64} OFFSET {offset:Int64}
|
|
814
717
|
`,
|
|
@@ -825,7 +728,10 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
825
728
|
}
|
|
826
729
|
});
|
|
827
730
|
const rows = await dataResult.json();
|
|
828
|
-
const threads = transformRows(rows.data)
|
|
731
|
+
const threads = transformRows(rows.data).map((thread) => ({
|
|
732
|
+
...thread,
|
|
733
|
+
metadata: parseMetadata(thread.metadata)
|
|
734
|
+
}));
|
|
829
735
|
return {
|
|
830
736
|
threads,
|
|
831
737
|
total,
|
|
@@ -1042,7 +948,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
1042
948
|
const now = (/* @__PURE__ */ new Date()).toISOString().replace("Z", "");
|
|
1043
949
|
const threadUpdatePromises = Array.from(threadIdsToUpdate).map(async (threadId) => {
|
|
1044
950
|
const threadResult = await this.client.query({
|
|
1045
|
-
query: `SELECT id, resourceId, title, metadata, createdAt FROM ${storage.TABLE_THREADS} WHERE id = {threadId:String}`,
|
|
951
|
+
query: `SELECT id, resourceId, title, metadata, createdAt FROM ${storage.TABLE_THREADS} WHERE id = {threadId:String} ORDER BY updatedAt DESC LIMIT 1`,
|
|
1046
952
|
query_params: { threadId },
|
|
1047
953
|
clickhouse_settings: {
|
|
1048
954
|
date_time_input_format: "best_effort",
|
|
@@ -1071,7 +977,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
1071
977
|
id: existingThread.id,
|
|
1072
978
|
resourceId: existingThread.resourceId,
|
|
1073
979
|
title: existingThread.title,
|
|
1074
|
-
metadata: existingThread.metadata,
|
|
980
|
+
metadata: typeof existingThread.metadata === "string" ? existingThread.metadata : serializeMetadata(existingThread.metadata),
|
|
1075
981
|
createdAt: existingThread.createdAt,
|
|
1076
982
|
updatedAt: now
|
|
1077
983
|
}
|
|
@@ -1130,7 +1036,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
1130
1036
|
async getResourceById({ resourceId }) {
|
|
1131
1037
|
try {
|
|
1132
1038
|
const result = await this.client.query({
|
|
1133
|
-
query: `SELECT id, workingMemory, metadata, createdAt, updatedAt FROM ${storage.TABLE_RESOURCES} WHERE id = {resourceId:String}`,
|
|
1039
|
+
query: `SELECT id, workingMemory, metadata, createdAt, updatedAt FROM ${storage.TABLE_RESOURCES} WHERE id = {resourceId:String} ORDER BY updatedAt DESC LIMIT 1`,
|
|
1134
1040
|
query_params: { resourceId },
|
|
1135
1041
|
clickhouse_settings: {
|
|
1136
1042
|
date_time_input_format: "best_effort",
|
|
@@ -1302,6 +1208,9 @@ var StoreOperationsClickhouse = class extends storage.StoreOperations {
|
|
|
1302
1208
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1303
1209
|
const constraints = [];
|
|
1304
1210
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1211
|
+
if (name === "metadata" && def.type === "text" && def.nullable) {
|
|
1212
|
+
constraints.push("DEFAULT '{}'");
|
|
1213
|
+
}
|
|
1305
1214
|
const columnTtl = this.ttl?.[tableName]?.columns?.[name];
|
|
1306
1215
|
return `"${name}" ${COLUMN_TYPES[def.type]} ${constraints.join(" ")} ${columnTtl ? `TTL toDateTime(${columnTtl.ttlKey ?? "createdAt"}) + INTERVAL ${columnTtl.interval} ${columnTtl.unit}` : ""}`;
|
|
1307
1216
|
}).join(",\n");
|
|
@@ -2073,7 +1982,8 @@ var WorkflowsStorageClickhouse = class extends storage.WorkflowsStorage {
|
|
|
2073
1982
|
toDate,
|
|
2074
1983
|
page,
|
|
2075
1984
|
perPage,
|
|
2076
|
-
resourceId
|
|
1985
|
+
resourceId,
|
|
1986
|
+
status
|
|
2077
1987
|
} = {}) {
|
|
2078
1988
|
try {
|
|
2079
1989
|
const conditions = [];
|
|
@@ -2082,6 +1992,10 @@ var WorkflowsStorageClickhouse = class extends storage.WorkflowsStorage {
|
|
|
2082
1992
|
conditions.push(`workflow_name = {var_workflow_name:String}`);
|
|
2083
1993
|
values.var_workflow_name = workflowName;
|
|
2084
1994
|
}
|
|
1995
|
+
if (status) {
|
|
1996
|
+
conditions.push(`JSONExtractString(snapshot, 'status') = {var_status:String}`);
|
|
1997
|
+
values.var_status = status;
|
|
1998
|
+
}
|
|
2085
1999
|
if (resourceId) {
|
|
2086
2000
|
const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2087
2001
|
if (hasResourceId) {
|
|
@@ -2208,7 +2122,7 @@ var ClickhouseStore = class extends storage.MastraStorage {
|
|
|
2208
2122
|
ttl = {};
|
|
2209
2123
|
stores;
|
|
2210
2124
|
constructor(config) {
|
|
2211
|
-
super({ name: "ClickhouseStore" });
|
|
2125
|
+
super({ id: config.id, name: "ClickhouseStore" });
|
|
2212
2126
|
this.db = client.createClient({
|
|
2213
2127
|
url: config.url,
|
|
2214
2128
|
username: config.username,
|
|
@@ -2335,15 +2249,8 @@ var ClickhouseStore = class extends storage.MastraStorage {
|
|
|
2335
2249
|
}) {
|
|
2336
2250
|
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2337
2251
|
}
|
|
2338
|
-
async listWorkflowRuns({
|
|
2339
|
-
|
|
2340
|
-
fromDate,
|
|
2341
|
-
toDate,
|
|
2342
|
-
perPage,
|
|
2343
|
-
page,
|
|
2344
|
-
resourceId
|
|
2345
|
-
} = {}) {
|
|
2346
|
-
return this.stores.workflows.listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId });
|
|
2252
|
+
async listWorkflowRuns(args = {}) {
|
|
2253
|
+
return this.stores.workflows.listWorkflowRuns(args);
|
|
2347
2254
|
}
|
|
2348
2255
|
async getWorkflowRunById({
|
|
2349
2256
|
runId,
|
|
@@ -2367,13 +2274,6 @@ var ClickhouseStore = class extends storage.MastraStorage {
|
|
|
2367
2274
|
async deleteThread({ threadId }) {
|
|
2368
2275
|
return this.stores.memory.deleteThread({ threadId });
|
|
2369
2276
|
}
|
|
2370
|
-
async getMessages({
|
|
2371
|
-
threadId,
|
|
2372
|
-
resourceId,
|
|
2373
|
-
selectBy
|
|
2374
|
-
}) {
|
|
2375
|
-
return this.stores.memory.getMessages({ threadId, resourceId, selectBy });
|
|
2376
|
-
}
|
|
2377
2277
|
async saveMessages(args) {
|
|
2378
2278
|
return this.stores.memory.saveMessages(args);
|
|
2379
2279
|
}
|