@mastra/clickhouse 0.0.0-toolOptionTypes-20250917085558 → 0.0.0-trace-timeline-update-20251121114225

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/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { createClient } from '@clickhouse/client';
2
2
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
- import { TABLE_AI_SPANS, TABLE_RESOURCES, TABLE_SCORERS, TABLE_EVALS, TABLE_THREADS, TABLE_TRACES, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, MastraStorage, StoreOperations, TABLE_SCHEMAS, WorkflowsStorage, ScoresStorage, safelyParseJSON, LegacyEvalsStorage, TracesStorage, MemoryStorage, resolveMessageLimit } from '@mastra/core/storage';
3
+ import { TABLE_SPANS, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_TRACES, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, MastraStorage, StoreOperations, TABLE_SCHEMAS, WorkflowsStorage, normalizePerPage, ScoresStorage, safelyParseJSON, calculatePagination, MemoryStorage } from '@mastra/core/storage';
4
4
  import { MessageList } from '@mastra/core/agent';
5
+ import { saveScorePayloadSchema } from '@mastra/core/evals';
5
6
 
6
7
  // src/storage/index.ts
7
8
  var TABLE_ENGINES = {
@@ -9,11 +10,10 @@ var TABLE_ENGINES = {
9
10
  [TABLE_WORKFLOW_SNAPSHOT]: `ReplacingMergeTree()`,
10
11
  [TABLE_TRACES]: `MergeTree()`,
11
12
  [TABLE_THREADS]: `ReplacingMergeTree()`,
12
- [TABLE_EVALS]: `MergeTree()`,
13
13
  [TABLE_SCORERS]: `MergeTree()`,
14
14
  [TABLE_RESOURCES]: `ReplacingMergeTree()`,
15
- // TODO: verify this is the correct engine for ai spans when implementing clickhouse storage
16
- [TABLE_AI_SPANS]: `ReplacingMergeTree()`
15
+ // TODO: verify this is the correct engine for Spans when implementing clickhouse storage
16
+ [TABLE_SPANS]: `ReplacingMergeTree()`
17
17
  };
18
18
  var COLUMN_TYPES = {
19
19
  text: "String",
@@ -44,8 +44,26 @@ function transformRows(rows) {
44
44
  return rows.map((row) => transformRow(row));
45
45
  }
46
46
 
47
- // src/storage/domains/legacy-evals/index.ts
48
- var LegacyEvalsStorageClickhouse = class extends LegacyEvalsStorage {
47
+ // src/storage/domains/memory/index.ts
48
+ function serializeMetadata(metadata) {
49
+ if (!metadata || Object.keys(metadata).length === 0) {
50
+ return "{}";
51
+ }
52
+ return JSON.stringify(metadata);
53
+ }
54
+ function parseMetadata(metadata) {
55
+ if (!metadata) return {};
56
+ if (typeof metadata === "object") return metadata;
57
+ if (typeof metadata !== "string") return {};
58
+ const trimmed = metadata.trim();
59
+ if (trimmed === "" || trimmed === "null") return {};
60
+ try {
61
+ return JSON.parse(trimmed);
62
+ } catch {
63
+ return {};
64
+ }
65
+ }
66
+ var MemoryStorageClickhouse = class extends MemoryStorage {
49
67
  client;
50
68
  operations;
51
69
  constructor({ client, operations }) {
@@ -53,127 +71,122 @@ var LegacyEvalsStorageClickhouse = class extends LegacyEvalsStorage {
53
71
  this.client = client;
54
72
  this.operations = operations;
55
73
  }
56
- transformEvalRow(row) {
57
- row = transformRow(row);
58
- let resultValue;
74
+ async listMessagesById({ messageIds }) {
75
+ if (messageIds.length === 0) return { messages: [] };
59
76
  try {
60
- if (row.result && typeof row.result === "string" && row.result.trim() !== "") {
61
- resultValue = JSON.parse(row.result);
62
- } else if (typeof row.result === "object" && row.result !== null) {
63
- resultValue = row.result;
64
- } else if (row.result === null || row.result === void 0 || row.result === "") {
65
- resultValue = { score: 0 };
66
- } else {
67
- throw new Error(`Invalid or empty result field: ${JSON.stringify(row.result)}`);
68
- }
69
- } catch (error) {
70
- console.error("Error parsing result field:", row.result, error);
71
- throw new MastraError({
72
- id: "CLICKHOUSE_STORAGE_INVALID_RESULT_FORMAT",
73
- text: `Invalid result format: ${JSON.stringify(row.result)}`,
74
- domain: ErrorDomain.STORAGE,
75
- category: ErrorCategory.USER
76
- });
77
- }
78
- let testInfoValue;
79
- try {
80
- if (row.test_info && typeof row.test_info === "string" && row.test_info.trim() !== "" && row.test_info !== "null") {
81
- testInfoValue = JSON.parse(row.test_info);
82
- } else if (typeof row.test_info === "object" && row.test_info !== null) {
83
- testInfoValue = row.test_info;
84
- }
85
- } catch {
86
- testInfoValue = void 0;
87
- }
88
- if (!resultValue || typeof resultValue !== "object" || !("score" in resultValue)) {
89
- throw new MastraError({
90
- id: "CLICKHOUSE_STORAGE_INVALID_METRIC_FORMAT",
91
- text: `Invalid MetricResult format: ${JSON.stringify(resultValue)}`,
92
- domain: ErrorDomain.STORAGE,
93
- category: ErrorCategory.USER
94
- });
95
- }
96
- return {
97
- input: row.input,
98
- output: row.output,
99
- result: resultValue,
100
- agentName: row.agent_name,
101
- metricName: row.metric_name,
102
- instructions: row.instructions,
103
- testInfo: testInfoValue,
104
- globalRunId: row.global_run_id,
105
- runId: row.run_id,
106
- createdAt: row.created_at
107
- };
108
- }
109
- async getEvalsByAgentName(agentName, type) {
110
- try {
111
- const baseQuery = `SELECT *, toDateTime64(created_at, 3) as createdAt FROM ${TABLE_EVALS} WHERE agent_name = {var_agent_name:String}`;
112
- const typeCondition = type === "test" ? " AND test_info IS NOT NULL AND test_info != 'null' AND JSONExtractString(test_info, 'testPath') IS NOT NULL AND JSONExtractString(test_info, 'testPath') != ''" : type === "live" ? " AND (test_info IS NULL OR test_info = 'null' OR JSONExtractString(test_info, 'testPath') IS NULL OR JSONExtractString(test_info, 'testPath') = '')" : "";
113
77
  const result = await this.client.query({
114
- query: `${baseQuery}${typeCondition} ORDER BY createdAt DESC`,
115
- query_params: { var_agent_name: agentName },
78
+ query: `
79
+ SELECT
80
+ id,
81
+ content,
82
+ role,
83
+ type,
84
+ toDateTime64(createdAt, 3) as createdAt,
85
+ thread_id AS "threadId",
86
+ "resourceId"
87
+ FROM "${TABLE_MESSAGES}"
88
+ WHERE id IN {messageIds:Array(String)}
89
+ ORDER BY "createdAt" DESC
90
+ `,
91
+ query_params: {
92
+ messageIds
93
+ },
116
94
  clickhouse_settings: {
95
+ // Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
117
96
  date_time_input_format: "best_effort",
118
97
  date_time_output_format: "iso",
119
98
  use_client_time_zone: 1,
120
99
  output_format_json_quote_64bit_integers: 0
121
100
  }
122
101
  });
123
- if (!result) {
124
- return [];
125
- }
126
102
  const rows = await result.json();
127
- return rows.data.map((row) => this.transformEvalRow(row));
103
+ const messages = transformRows(rows.data);
104
+ messages.forEach((message) => {
105
+ if (typeof message.content === "string") {
106
+ try {
107
+ message.content = JSON.parse(message.content);
108
+ } catch {
109
+ }
110
+ }
111
+ });
112
+ const list = new MessageList().add(messages, "memory");
113
+ return { messages: list.get.all.db() };
128
114
  } catch (error) {
129
- if (error?.message?.includes("no such table") || error?.message?.includes("does not exist")) {
130
- return [];
131
- }
132
115
  throw new MastraError(
133
116
  {
134
- id: "CLICKHOUSE_STORAGE_GET_EVALS_BY_AGENT_FAILED",
117
+ id: "CLICKHOUSE_STORAGE_LIST_MESSAGES_BY_ID_FAILED",
135
118
  domain: ErrorDomain.STORAGE,
136
119
  category: ErrorCategory.THIRD_PARTY,
137
- details: { agentName, type: type ?? null }
120
+ details: { messageIds: JSON.stringify(messageIds) }
138
121
  },
139
122
  error
140
123
  );
141
124
  }
142
125
  }
143
- async getEvals(options = {}) {
144
- const { agentName, type, page = 0, perPage = 100, dateRange } = options;
145
- const fromDate = dateRange?.start;
146
- const toDate = dateRange?.end;
147
- const conditions = [];
148
- if (agentName) {
149
- conditions.push(`agent_name = {var_agent_name:String}`);
150
- }
151
- if (type === "test") {
152
- conditions.push(
153
- `(test_info IS NOT NULL AND test_info != 'null' AND JSONExtractString(test_info, 'testPath') IS NOT NULL AND JSONExtractString(test_info, 'testPath') != '')`
154
- );
155
- } else if (type === "live") {
156
- conditions.push(
157
- `(test_info IS NULL OR test_info = 'null' OR JSONExtractString(test_info, 'testPath') IS NULL OR JSONExtractString(test_info, 'testPath') = '')`
126
+ async listMessages(args) {
127
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
128
+ if (page < 0) {
129
+ throw new MastraError(
130
+ {
131
+ id: "STORAGE_CLICKHOUSE_LIST_MESSAGES_INVALID_PAGE",
132
+ domain: ErrorDomain.STORAGE,
133
+ category: ErrorCategory.USER,
134
+ details: { page }
135
+ },
136
+ new Error("page must be >= 0")
158
137
  );
159
138
  }
160
- if (fromDate) {
161
- conditions.push(`created_at >= parseDateTime64BestEffort({var_from_date:String})`);
162
- fromDate.toISOString();
163
- }
164
- if (toDate) {
165
- conditions.push(`created_at <= parseDateTime64BestEffort({var_to_date:String})`);
166
- toDate.toISOString();
139
+ if (!threadId.trim()) {
140
+ throw new MastraError(
141
+ {
142
+ id: "STORAGE_CLICKHOUSE_LIST_MESSAGES_INVALID_THREAD_ID",
143
+ domain: ErrorDomain.STORAGE,
144
+ category: ErrorCategory.THIRD_PARTY,
145
+ details: { threadId }
146
+ },
147
+ new Error("threadId must be a non-empty string")
148
+ );
167
149
  }
168
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
150
+ const perPageForQuery = normalizePerPage(perPageInput, 40);
151
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPageForQuery);
169
152
  try {
170
- const countResult = await this.client.query({
171
- query: `SELECT COUNT(*) as count FROM ${TABLE_EVALS} ${whereClause}`,
172
- query_params: {
173
- ...agentName ? { var_agent_name: agentName } : {},
174
- ...fromDate ? { var_from_date: fromDate.toISOString() } : {},
175
- ...toDate ? { var_to_date: toDate.toISOString() } : {}
176
- },
153
+ let dataQuery = `
154
+ SELECT
155
+ id,
156
+ content,
157
+ role,
158
+ type,
159
+ toDateTime64(createdAt, 3) as createdAt,
160
+ thread_id AS "threadId",
161
+ resourceId
162
+ FROM ${TABLE_MESSAGES}
163
+ WHERE thread_id = {threadId:String}
164
+ `;
165
+ const dataParams = { threadId };
166
+ if (resourceId) {
167
+ dataQuery += ` AND resourceId = {resourceId:String}`;
168
+ dataParams.resourceId = resourceId;
169
+ }
170
+ if (filter?.dateRange?.start) {
171
+ const startDate = filter.dateRange.start instanceof Date ? filter.dateRange.start.toISOString() : new Date(filter.dateRange.start).toISOString();
172
+ dataQuery += ` AND createdAt >= parseDateTime64BestEffort({fromDate:String}, 3)`;
173
+ dataParams.fromDate = startDate;
174
+ }
175
+ if (filter?.dateRange?.end) {
176
+ const endDate = filter.dateRange.end instanceof Date ? filter.dateRange.end.toISOString() : new Date(filter.dateRange.end).toISOString();
177
+ dataQuery += ` AND createdAt <= parseDateTime64BestEffort({toDate:String}, 3)`;
178
+ dataParams.toDate = endDate;
179
+ }
180
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
181
+ dataQuery += ` ORDER BY "${field}" ${direction}`;
182
+ if (perPageForResponse === false) ; else {
183
+ dataQuery += ` LIMIT {limit:Int64} OFFSET {offset:Int64}`;
184
+ dataParams.limit = perPageForQuery;
185
+ dataParams.offset = offset;
186
+ }
187
+ const result = await this.client.query({
188
+ query: dataQuery,
189
+ query_params: dataParams,
177
190
  clickhouse_settings: {
178
191
  date_time_input_format: "best_effort",
179
192
  date_time_output_format: "iso",
@@ -181,28 +194,28 @@ var LegacyEvalsStorageClickhouse = class extends LegacyEvalsStorage {
181
194
  output_format_json_quote_64bit_integers: 0
182
195
  }
183
196
  });
184
- const countData = await countResult.json();
185
- const total = Number(countData.data?.[0]?.count ?? 0);
186
- const currentOffset = page * perPage;
187
- const hasMore = currentOffset + perPage < total;
188
- if (total === 0) {
189
- return {
190
- evals: [],
191
- total: 0,
192
- page,
193
- perPage,
194
- hasMore: false
195
- };
197
+ const rows = await result.json();
198
+ const paginatedMessages = transformRows(rows.data);
199
+ const paginatedCount = paginatedMessages.length;
200
+ let countQuery = `SELECT count() as total FROM ${TABLE_MESSAGES} WHERE thread_id = {threadId:String}`;
201
+ const countParams = { threadId };
202
+ if (resourceId) {
203
+ countQuery += ` AND resourceId = {resourceId:String}`;
204
+ countParams.resourceId = resourceId;
196
205
  }
197
- const dataResult = await this.client.query({
198
- query: `SELECT *, toDateTime64(createdAt, 3) as createdAt FROM ${TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT {var_limit:UInt32} OFFSET {var_offset:UInt32}`,
199
- query_params: {
200
- ...agentName ? { var_agent_name: agentName } : {},
201
- ...fromDate ? { var_from_date: fromDate.toISOString() } : {},
202
- ...toDate ? { var_to_date: toDate.toISOString() } : {},
203
- var_limit: perPage || 100,
204
- var_offset: currentOffset || 0
205
- },
206
+ if (filter?.dateRange?.start) {
207
+ const startDate = filter.dateRange.start instanceof Date ? filter.dateRange.start.toISOString() : new Date(filter.dateRange.start).toISOString();
208
+ countQuery += ` AND createdAt >= parseDateTime64BestEffort({fromDate:String}, 3)`;
209
+ countParams.fromDate = startDate;
210
+ }
211
+ if (filter?.dateRange?.end) {
212
+ const endDate = filter.dateRange.end instanceof Date ? filter.dateRange.end.toISOString() : new Date(filter.dateRange.end).toISOString();
213
+ countQuery += ` AND createdAt <= parseDateTime64BestEffort({toDate:String}, 3)`;
214
+ countParams.toDate = endDate;
215
+ }
216
+ const countResult = await this.client.query({
217
+ query: countQuery,
218
+ query_params: countParams,
206
219
  clickhouse_settings: {
207
220
  date_time_input_format: "best_effort",
208
221
  date_time_output_format: "iso",
@@ -210,56 +223,20 @@ var LegacyEvalsStorageClickhouse = class extends LegacyEvalsStorage {
210
223
  output_format_json_quote_64bit_integers: 0
211
224
  }
212
225
  });
213
- const rows = await dataResult.json();
214
- return {
215
- evals: rows.data.map((row) => this.transformEvalRow(row)),
216
- total,
217
- page,
218
- perPage,
219
- hasMore
220
- };
221
- } catch (error) {
222
- if (error?.message?.includes("no such table") || error?.message?.includes("does not exist")) {
226
+ const countData = await countResult.json();
227
+ const total = countData.data[0].total;
228
+ if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
223
229
  return {
224
- evals: [],
230
+ messages: [],
225
231
  total: 0,
226
232
  page,
227
- perPage,
233
+ perPage: perPageForResponse,
228
234
  hasMore: false
229
235
  };
230
236
  }
231
- throw new MastraError(
232
- {
233
- id: "CLICKHOUSE_STORAGE_GET_EVALS_FAILED",
234
- domain: ErrorDomain.STORAGE,
235
- category: ErrorCategory.THIRD_PARTY,
236
- details: { agentName: agentName ?? "all", type: type ?? "all" }
237
- },
238
- error
239
- );
240
- }
241
- }
242
- };
243
- var MemoryStorageClickhouse = class extends MemoryStorage {
244
- client;
245
- operations;
246
- constructor({ client, operations }) {
247
- super();
248
- this.client = client;
249
- this.operations = operations;
250
- }
251
- async getMessages({
252
- threadId,
253
- resourceId,
254
- selectBy,
255
- format
256
- }) {
257
- try {
258
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
259
- const messages = [];
260
- const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
261
- const include = selectBy?.include || [];
262
- if (include.length) {
237
+ const messageIds = new Set(paginatedMessages.map((m) => m.id));
238
+ let includeMessages = [];
239
+ if (include && include.length > 0) {
263
240
  const unionQueries = [];
264
241
  const params = [];
265
242
  let paramIdx = 1;
@@ -280,7 +257,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
280
257
  FROM numbered_messages
281
258
  WHERE id = {var_include_id_${paramIdx}:String}
282
259
  )
283
- SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId"
260
+ SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId", m."resourceId"
284
261
  FROM numbered_messages m
285
262
  CROSS JOIN target_positions t
286
263
  WHERE m.row_num BETWEEN (t.target_pos - {var_withPreviousMessages_${paramIdx}:Int64}) AND (t.target_pos + {var_withNextMessages_${paramIdx}:Int64})
@@ -294,7 +271,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
294
271
  );
295
272
  paramIdx++;
296
273
  }
297
- const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" DESC';
274
+ const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
298
275
  const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
299
276
  const includeResult = await this.client.query({
300
277
  query: finalQuery,
@@ -306,129 +283,66 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
306
283
  output_format_json_quote_64bit_integers: 0
307
284
  }
308
285
  });
309
- const rows2 = await includeResult.json();
310
- const includedMessages = transformRows(rows2.data);
311
- const seen = /* @__PURE__ */ new Set();
312
- const dedupedMessages = includedMessages.filter((message) => {
313
- if (seen.has(message.id)) return false;
314
- seen.add(message.id);
315
- return true;
316
- });
317
- messages.push(...dedupedMessages);
318
- }
319
- const result = await this.client.query({
320
- query: `
321
- SELECT
322
- id,
323
- content,
324
- role,
325
- type,
326
- toDateTime64(createdAt, 3) as createdAt,
327
- thread_id AS "threadId"
328
- FROM "${TABLE_MESSAGES}"
329
- WHERE thread_id = {threadId:String}
330
- AND id NOT IN ({exclude:Array(String)})
331
- ORDER BY "createdAt" DESC
332
- LIMIT {limit:Int64}
333
- `,
334
- query_params: {
335
- threadId,
336
- exclude: messages.map((m) => m.id),
337
- limit
338
- },
339
- clickhouse_settings: {
340
- // Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
341
- date_time_input_format: "best_effort",
342
- date_time_output_format: "iso",
343
- use_client_time_zone: 1,
344
- output_format_json_quote_64bit_integers: 0
345
- }
346
- });
347
- const rows = await result.json();
348
- messages.push(...transformRows(rows.data));
349
- messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
350
- messages.forEach((message) => {
351
- if (typeof message.content === "string") {
352
- try {
353
- message.content = JSON.parse(message.content);
354
- } catch {
286
+ const includeRows = await includeResult.json();
287
+ includeMessages = transformRows(includeRows.data);
288
+ for (const includeMsg of includeMessages) {
289
+ if (!messageIds.has(includeMsg.id)) {
290
+ paginatedMessages.push(includeMsg);
291
+ messageIds.add(includeMsg.id);
355
292
  }
356
293
  }
357
- });
358
- const list = new MessageList({ threadId, resourceId }).add(messages, "memory");
359
- if (format === `v2`) return list.get.all.v2();
360
- return list.get.all.v1();
361
- } catch (error) {
362
- throw new MastraError(
363
- {
364
- id: "CLICKHOUSE_STORAGE_GET_MESSAGES_FAILED",
365
- domain: ErrorDomain.STORAGE,
366
- category: ErrorCategory.THIRD_PARTY,
367
- details: { threadId, resourceId: resourceId ?? "" }
368
- },
369
- error
370
- );
371
- }
372
- }
373
- async getMessagesById({
374
- messageIds,
375
- format
376
- }) {
377
- if (messageIds.length === 0) return [];
378
- try {
379
- const result = await this.client.query({
380
- query: `
381
- SELECT
382
- id,
383
- content,
384
- role,
385
- type,
386
- toDateTime64(createdAt, 3) as createdAt,
387
- thread_id AS "threadId",
388
- "resourceId"
389
- FROM "${TABLE_MESSAGES}"
390
- WHERE id IN {messageIds:Array(String)}
391
- ORDER BY "createdAt" DESC
392
- `,
393
- query_params: {
394
- messageIds
395
- },
396
- clickhouse_settings: {
397
- // Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
398
- date_time_input_format: "best_effort",
399
- date_time_output_format: "iso",
400
- use_client_time_zone: 1,
401
- output_format_json_quote_64bit_integers: 0
294
+ }
295
+ const list = new MessageList().add(paginatedMessages, "memory");
296
+ let finalMessages = list.get.all.db();
297
+ finalMessages = finalMessages.sort((a, b) => {
298
+ const isDateField = field === "createdAt" || field === "updatedAt";
299
+ const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
300
+ const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
301
+ if (aValue === bValue) {
302
+ return a.id.localeCompare(b.id);
402
303
  }
403
- });
404
- const rows = await result.json();
405
- const messages = transformRows(rows.data);
406
- messages.forEach((message) => {
407
- if (typeof message.content === "string") {
408
- try {
409
- message.content = JSON.parse(message.content);
410
- } catch {
411
- }
304
+ if (typeof aValue === "number" && typeof bValue === "number") {
305
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
412
306
  }
307
+ return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
413
308
  });
414
- const list = new MessageList().add(messages, "memory");
415
- if (format === `v1`) return list.get.all.v1();
416
- return list.get.all.v2();
309
+ const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
310
+ const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
311
+ const hasMore = perPageForResponse === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
312
+ return {
313
+ messages: finalMessages,
314
+ total,
315
+ page,
316
+ perPage: perPageForResponse,
317
+ hasMore
318
+ };
417
319
  } catch (error) {
418
- throw new MastraError(
320
+ const mastraError = new MastraError(
419
321
  {
420
- id: "CLICKHOUSE_STORAGE_GET_MESSAGES_BY_ID_FAILED",
322
+ id: "STORAGE_CLICKHOUSE_STORE_LIST_MESSAGES_FAILED",
421
323
  domain: ErrorDomain.STORAGE,
422
324
  category: ErrorCategory.THIRD_PARTY,
423
- details: { messageIds: JSON.stringify(messageIds) }
325
+ details: {
326
+ threadId,
327
+ resourceId: resourceId ?? ""
328
+ }
424
329
  },
425
330
  error
426
331
  );
332
+ this.logger?.error?.(mastraError.toString());
333
+ this.logger?.trackException?.(mastraError);
334
+ return {
335
+ messages: [],
336
+ total: 0,
337
+ page,
338
+ perPage: perPageForResponse,
339
+ hasMore: false
340
+ };
427
341
  }
428
342
  }
429
343
  async saveMessages(args) {
430
- const { messages, format = "v1" } = args;
431
- if (messages.length === 0) return messages;
344
+ const { messages } = args;
345
+ if (messages.length === 0) return { messages };
432
346
  for (const message of messages) {
433
347
  const resourceId = message.resourceId;
434
348
  if (!resourceId) {
@@ -552,7 +466,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
552
466
  id: thread.id,
553
467
  resourceId: thread.resourceId,
554
468
  title: thread.title,
555
- metadata: thread.metadata,
469
+ metadata: serializeMetadata(thread.metadata),
556
470
  createdAt: thread.createdAt,
557
471
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
558
472
  })),
@@ -564,8 +478,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
564
478
  })
565
479
  ]);
566
480
  const list = new MessageList().add(messages, "memory");
567
- if (format === `v2`) return list.get.all.v2();
568
- return list.get.all.v1();
481
+ return { messages: list.get.all.db() };
569
482
  } catch (error) {
570
483
  throw new MastraError(
571
484
  {
@@ -588,8 +501,9 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
588
501
  toDateTime64(createdAt, 3) as createdAt,
589
502
  toDateTime64(updatedAt, 3) as updatedAt
590
503
  FROM "${TABLE_THREADS}"
591
- FINAL
592
- WHERE id = {var_id:String}`,
504
+ WHERE id = {var_id:String}
505
+ ORDER BY updatedAt DESC
506
+ LIMIT 1`,
593
507
  query_params: { var_id: threadId },
594
508
  clickhouse_settings: {
595
509
  // Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
@@ -606,7 +520,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
606
520
  }
607
521
  return {
608
522
  ...thread,
609
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
523
+ metadata: parseMetadata(thread.metadata),
610
524
  createdAt: thread.createdAt,
611
525
  updatedAt: thread.updatedAt
612
526
  };
@@ -622,47 +536,6 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
622
536
  );
623
537
  }
624
538
  }
625
- async getThreadsByResourceId({ resourceId }) {
626
- try {
627
- const result = await this.client.query({
628
- query: `SELECT
629
- id,
630
- "resourceId",
631
- title,
632
- metadata,
633
- toDateTime64(createdAt, 3) as createdAt,
634
- toDateTime64(updatedAt, 3) as updatedAt
635
- FROM "${TABLE_THREADS}"
636
- WHERE "resourceId" = {var_resourceId:String}`,
637
- query_params: { var_resourceId: resourceId },
638
- clickhouse_settings: {
639
- // Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
640
- date_time_input_format: "best_effort",
641
- date_time_output_format: "iso",
642
- use_client_time_zone: 1,
643
- output_format_json_quote_64bit_integers: 0
644
- }
645
- });
646
- const rows = await result.json();
647
- const threads = transformRows(rows.data);
648
- return threads.map((thread) => ({
649
- ...thread,
650
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
651
- createdAt: thread.createdAt,
652
- updatedAt: thread.updatedAt
653
- }));
654
- } catch (error) {
655
- throw new MastraError(
656
- {
657
- id: "CLICKHOUSE_STORAGE_GET_THREADS_BY_RESOURCE_ID_FAILED",
658
- domain: ErrorDomain.STORAGE,
659
- category: ErrorCategory.THIRD_PARTY,
660
- details: { resourceId }
661
- },
662
- error
663
- );
664
- }
665
- }
666
539
  async saveThread({ thread }) {
667
540
  try {
668
541
  await this.client.insert({
@@ -670,6 +543,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
670
543
  values: [
671
544
  {
672
545
  ...thread,
546
+ metadata: serializeMetadata(thread.metadata),
673
547
  createdAt: thread.createdAt.toISOString(),
674
548
  updatedAt: thread.updatedAt.toISOString()
675
549
  }
@@ -723,7 +597,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
723
597
  id: updatedThread.id,
724
598
  resourceId: updatedThread.resourceId,
725
599
  title: updatedThread.title,
726
- metadata: updatedThread.metadata,
600
+ metadata: serializeMetadata(updatedThread.metadata),
727
601
  createdAt: updatedThread.createdAt,
728
602
  updatedAt: updatedThread.updatedAt.toISOString()
729
603
  }
@@ -762,174 +636,39 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
762
636
  clickhouse_settings: {
763
637
  output_format_json_quote_64bit_integers: 0
764
638
  }
765
- });
766
- } catch (error) {
767
- throw new MastraError(
768
- {
769
- id: "CLICKHOUSE_STORAGE_DELETE_THREAD_FAILED",
770
- domain: ErrorDomain.STORAGE,
771
- category: ErrorCategory.THIRD_PARTY,
772
- details: { threadId }
773
- },
774
- error
775
- );
776
- }
777
- }
778
- async getThreadsByResourceIdPaginated(args) {
779
- const { resourceId, page = 0, perPage = 100 } = args;
780
- try {
781
- const currentOffset = page * perPage;
782
- const countResult = await this.client.query({
783
- query: `SELECT count() as total FROM ${TABLE_THREADS} WHERE resourceId = {resourceId:String}`,
784
- query_params: { resourceId },
785
- clickhouse_settings: {
786
- date_time_input_format: "best_effort",
787
- date_time_output_format: "iso",
788
- use_client_time_zone: 1,
789
- output_format_json_quote_64bit_integers: 0
790
- }
791
- });
792
- const countData = await countResult.json();
793
- const total = countData.data[0].total;
794
- if (total === 0) {
795
- return {
796
- threads: [],
797
- total: 0,
798
- page,
799
- perPage,
800
- hasMore: false
801
- };
802
- }
803
- const dataResult = await this.client.query({
804
- query: `
805
- SELECT
806
- id,
807
- resourceId,
808
- title,
809
- metadata,
810
- toDateTime64(createdAt, 3) as createdAt,
811
- toDateTime64(updatedAt, 3) as updatedAt
812
- FROM ${TABLE_THREADS}
813
- WHERE resourceId = {resourceId:String}
814
- ORDER BY createdAt DESC
815
- LIMIT {limit:Int64} OFFSET {offset:Int64}
816
- `,
817
- query_params: {
818
- resourceId,
819
- limit: perPage,
820
- offset: currentOffset
821
- },
822
- clickhouse_settings: {
823
- date_time_input_format: "best_effort",
824
- date_time_output_format: "iso",
825
- use_client_time_zone: 1,
826
- output_format_json_quote_64bit_integers: 0
827
- }
828
- });
829
- const rows = await dataResult.json();
830
- const threads = transformRows(rows.data);
831
- return {
832
- threads,
833
- total,
834
- page,
835
- perPage,
836
- hasMore: currentOffset + threads.length < total
837
- };
639
+ });
838
640
  } catch (error) {
839
641
  throw new MastraError(
840
642
  {
841
- id: "CLICKHOUSE_STORAGE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
643
+ id: "CLICKHOUSE_STORAGE_DELETE_THREAD_FAILED",
842
644
  domain: ErrorDomain.STORAGE,
843
645
  category: ErrorCategory.THIRD_PARTY,
844
- details: { resourceId, page }
646
+ details: { threadId }
845
647
  },
846
648
  error
847
649
  );
848
650
  }
849
651
  }
850
- async getMessagesPaginated(args) {
851
- const { threadId, resourceId, selectBy, format = "v1" } = args;
852
- const page = selectBy?.pagination?.page || 0;
853
- const perPageInput = selectBy?.pagination?.perPage;
854
- const perPage = perPageInput !== void 0 ? perPageInput : resolveMessageLimit({ last: selectBy?.last, defaultLimit: 20 });
652
+ async listThreadsByResourceId(args) {
653
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
654
+ const perPage = normalizePerPage(perPageInput, 100);
655
+ if (page < 0) {
656
+ throw new MastraError(
657
+ {
658
+ id: "STORAGE_CLICKHOUSE_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
659
+ domain: ErrorDomain.STORAGE,
660
+ category: ErrorCategory.USER,
661
+ details: { page }
662
+ },
663
+ new Error("page must be >= 0")
664
+ );
665
+ }
666
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
667
+ const { field, direction } = this.parseOrderBy(orderBy);
855
668
  try {
856
- if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
857
- const offset = page * perPage;
858
- const dateRange = selectBy?.pagination?.dateRange;
859
- const fromDate = dateRange?.start;
860
- const toDate = dateRange?.end;
861
- const messages = [];
862
- if (selectBy?.include?.length) {
863
- const include = selectBy.include;
864
- const unionQueries = [];
865
- const params = [];
866
- let paramIdx = 1;
867
- for (const inc of include) {
868
- const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
869
- const searchId = inc.threadId || threadId;
870
- unionQueries.push(`
871
- SELECT * FROM (
872
- WITH numbered_messages AS (
873
- SELECT
874
- id, content, role, type, "createdAt", thread_id, "resourceId",
875
- ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
876
- FROM "${TABLE_MESSAGES}"
877
- WHERE thread_id = {var_thread_id_${paramIdx}:String}
878
- ),
879
- target_positions AS (
880
- SELECT row_num as target_pos
881
- FROM numbered_messages
882
- WHERE id = {var_include_id_${paramIdx}:String}
883
- )
884
- SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId"
885
- FROM numbered_messages m
886
- CROSS JOIN target_positions t
887
- WHERE m.row_num BETWEEN (t.target_pos - {var_withPreviousMessages_${paramIdx}:Int64}) AND (t.target_pos + {var_withNextMessages_${paramIdx}:Int64})
888
- ) AS query_${paramIdx}
889
- `);
890
- params.push(
891
- { [`var_thread_id_${paramIdx}`]: searchId },
892
- { [`var_include_id_${paramIdx}`]: id },
893
- { [`var_withPreviousMessages_${paramIdx}`]: withPreviousMessages },
894
- { [`var_withNextMessages_${paramIdx}`]: withNextMessages }
895
- );
896
- paramIdx++;
897
- }
898
- const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" DESC';
899
- const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
900
- const includeResult = await this.client.query({
901
- query: finalQuery,
902
- query_params: mergedParams,
903
- clickhouse_settings: {
904
- date_time_input_format: "best_effort",
905
- date_time_output_format: "iso",
906
- use_client_time_zone: 1,
907
- output_format_json_quote_64bit_integers: 0
908
- }
909
- });
910
- const rows2 = await includeResult.json();
911
- const includedMessages = transformRows(rows2.data);
912
- const seen = /* @__PURE__ */ new Set();
913
- const dedupedMessages = includedMessages.filter((message) => {
914
- if (seen.has(message.id)) return false;
915
- seen.add(message.id);
916
- return true;
917
- });
918
- messages.push(...dedupedMessages);
919
- }
920
- let countQuery = `SELECT count() as total FROM ${TABLE_MESSAGES} WHERE thread_id = {threadId:String}`;
921
- const countParams = { threadId };
922
- if (fromDate) {
923
- countQuery += ` AND createdAt >= parseDateTime64BestEffort({fromDate:String}, 3)`;
924
- countParams.fromDate = fromDate.toISOString();
925
- }
926
- if (toDate) {
927
- countQuery += ` AND createdAt <= parseDateTime64BestEffort({toDate:String}, 3)`;
928
- countParams.toDate = toDate.toISOString();
929
- }
930
669
  const countResult = await this.client.query({
931
- query: countQuery,
932
- query_params: countParams,
670
+ query: `SELECT count(DISTINCT id) as total FROM ${TABLE_THREADS} WHERE resourceId = {resourceId:String}`,
671
+ query_params: { resourceId },
933
672
  clickhouse_settings: {
934
673
  date_time_input_format: "best_effort",
935
674
  date_time_output_format: "iso",
@@ -939,58 +678,46 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
939
678
  });
940
679
  const countData = await countResult.json();
941
680
  const total = countData.data[0].total;
942
- if (total === 0 && messages.length === 0) {
681
+ if (total === 0) {
943
682
  return {
944
- messages: [],
683
+ threads: [],
945
684
  total: 0,
946
685
  page,
947
- perPage,
686
+ perPage: perPageForResponse,
948
687
  hasMore: false
949
688
  };
950
689
  }
951
- const excludeIds = messages.map((m) => m.id);
952
- let dataQuery = `
953
- SELECT
954
- id,
955
- content,
956
- role,
957
- type,
958
- toDateTime64(createdAt, 3) as createdAt,
959
- thread_id AS "threadId",
960
- resourceId
961
- FROM ${TABLE_MESSAGES}
962
- WHERE thread_id = {threadId:String}
963
- `;
964
- const dataParams = { threadId };
965
- if (fromDate) {
966
- dataQuery += ` AND createdAt >= parseDateTime64BestEffort({fromDate:String}, 3)`;
967
- dataParams.fromDate = fromDate.toISOString();
968
- }
969
- if (toDate) {
970
- dataQuery += ` AND createdAt <= parseDateTime64BestEffort({toDate:String}, 3)`;
971
- dataParams.toDate = toDate.toISOString();
972
- }
973
- if (excludeIds.length > 0) {
974
- dataQuery += ` AND id NOT IN ({excludeIds:Array(String)})`;
975
- dataParams.excludeIds = excludeIds;
976
- }
977
- if (selectBy?.last) {
978
- dataQuery += `
979
- ORDER BY createdAt DESC
980
- LIMIT {limit:Int64}
981
- `;
982
- dataParams.limit = perPage;
983
- } else {
984
- dataQuery += `
985
- ORDER BY createdAt ASC
986
- LIMIT {limit:Int64} OFFSET {offset:Int64}
987
- `;
988
- dataParams.limit = perPage;
989
- dataParams.offset = offset;
990
- }
991
- const result = await this.client.query({
992
- query: dataQuery,
993
- query_params: dataParams,
690
+ const dataResult = await this.client.query({
691
+ query: `
692
+ WITH ranked_threads AS (
693
+ SELECT
694
+ id,
695
+ resourceId,
696
+ title,
697
+ metadata,
698
+ toDateTime64(createdAt, 3) as createdAt,
699
+ toDateTime64(updatedAt, 3) as updatedAt,
700
+ ROW_NUMBER() OVER (PARTITION BY id ORDER BY updatedAt DESC) as row_num
701
+ FROM ${TABLE_THREADS}
702
+ WHERE resourceId = {resourceId:String}
703
+ )
704
+ SELECT
705
+ id,
706
+ resourceId,
707
+ title,
708
+ metadata,
709
+ createdAt,
710
+ updatedAt
711
+ FROM ranked_threads
712
+ WHERE row_num = 1
713
+ ORDER BY "${field}" ${direction === "DESC" ? "DESC" : "ASC"}
714
+ LIMIT {perPage:Int64} OFFSET {offset:Int64}
715
+ `,
716
+ query_params: {
717
+ resourceId,
718
+ perPage,
719
+ offset
720
+ },
994
721
  clickhouse_settings: {
995
722
  date_time_input_format: "best_effort",
996
723
  date_time_output_format: "iso",
@@ -998,35 +725,28 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
998
725
  output_format_json_quote_64bit_integers: 0
999
726
  }
1000
727
  });
1001
- const rows = await result.json();
1002
- const paginatedMessages = transformRows(rows.data);
1003
- messages.push(...paginatedMessages);
1004
- if (selectBy?.last) {
1005
- messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
1006
- }
728
+ const rows = await dataResult.json();
729
+ const threads = transformRows(rows.data).map((thread) => ({
730
+ ...thread,
731
+ metadata: parseMetadata(thread.metadata)
732
+ }));
1007
733
  return {
1008
- messages: format === "v2" ? messages : messages,
734
+ threads,
1009
735
  total,
1010
736
  page,
1011
- perPage,
737
+ perPage: perPageForResponse,
1012
738
  hasMore: offset + perPage < total
1013
739
  };
1014
740
  } catch (error) {
1015
- const mastraError = new MastraError(
741
+ throw new MastraError(
1016
742
  {
1017
- id: "CLICKHOUSE_STORAGE_GET_MESSAGES_PAGINATED_FAILED",
743
+ id: "CLICKHOUSE_STORAGE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
1018
744
  domain: ErrorDomain.STORAGE,
1019
745
  category: ErrorCategory.THIRD_PARTY,
1020
- details: {
1021
- threadId,
1022
- resourceId: resourceId ?? ""
1023
- }
746
+ details: { resourceId, page }
1024
747
  },
1025
748
  error
1026
749
  );
1027
- this.logger?.trackException?.(mastraError);
1028
- this.logger?.error?.(mastraError.toString());
1029
- return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
1030
750
  }
1031
751
  }
1032
752
  async updateMessages(args) {
@@ -1109,7 +829,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
1109
829
  UPDATE ${setClauses.join(", ")}
1110
830
  WHERE id = {var_id_${paramIdx}:String}
1111
831
  `;
1112
- console.log("Updating message:", id, "with query:", updateQuery, "values:", values);
832
+ console.info("Updating message:", id, "with query:", updateQuery, "values:", values);
1113
833
  updatePromises.push(
1114
834
  this.client.command({
1115
835
  query: updateQuery,
@@ -1168,7 +888,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
1168
888
  }
1169
889
  }
1170
890
  if (needsRetry) {
1171
- console.log("Update not applied correctly, retrying with DELETE + INSERT for message:", id);
891
+ console.info("Update not applied correctly, retrying with DELETE + INSERT for message:", id);
1172
892
  await this.client.command({
1173
893
  query: `DELETE FROM ${TABLE_MESSAGES} WHERE id = {messageId:String}`,
1174
894
  query_params: { messageId: id },
@@ -1226,7 +946,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
1226
946
  const now = (/* @__PURE__ */ new Date()).toISOString().replace("Z", "");
1227
947
  const threadUpdatePromises = Array.from(threadIdsToUpdate).map(async (threadId) => {
1228
948
  const threadResult = await this.client.query({
1229
- query: `SELECT id, resourceId, title, metadata, createdAt FROM ${TABLE_THREADS} WHERE id = {threadId:String}`,
949
+ query: `SELECT id, resourceId, title, metadata, createdAt FROM ${TABLE_THREADS} WHERE id = {threadId:String} ORDER BY updatedAt DESC LIMIT 1`,
1230
950
  query_params: { threadId },
1231
951
  clickhouse_settings: {
1232
952
  date_time_input_format: "best_effort",
@@ -1255,7 +975,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
1255
975
  id: existingThread.id,
1256
976
  resourceId: existingThread.resourceId,
1257
977
  title: existingThread.title,
1258
- metadata: existingThread.metadata,
978
+ metadata: typeof existingThread.metadata === "string" ? existingThread.metadata : serializeMetadata(existingThread.metadata),
1259
979
  createdAt: existingThread.createdAt,
1260
980
  updatedAt: now
1261
981
  }
@@ -1314,7 +1034,7 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
1314
1034
  async getResourceById({ resourceId }) {
1315
1035
  try {
1316
1036
  const result = await this.client.query({
1317
- query: `SELECT id, workingMemory, metadata, createdAt, updatedAt FROM ${TABLE_RESOURCES} WHERE id = {resourceId:String}`,
1037
+ query: `SELECT id, workingMemory, metadata, createdAt, updatedAt FROM ${TABLE_RESOURCES} WHERE id = {resourceId:String} ORDER BY updatedAt DESC LIMIT 1`,
1318
1038
  query_params: { resourceId },
1319
1039
  clickhouse_settings: {
1320
1040
  date_time_input_format: "best_effort",
@@ -1486,6 +1206,9 @@ var StoreOperationsClickhouse = class extends StoreOperations {
1486
1206
  const columns = Object.entries(schema).map(([name, def]) => {
1487
1207
  const constraints = [];
1488
1208
  if (!def.nullable) constraints.push("NOT NULL");
1209
+ if (name === "metadata" && def.type === "text" && def.nullable) {
1210
+ constraints.push("DEFAULT '{}'");
1211
+ }
1489
1212
  const columnTtl = this.ttl?.[tableName]?.columns?.[name];
1490
1213
  return `"${name}" ${COLUMN_TYPES[def.type]} ${constraints.join(" ")} ${columnTtl ? `TTL toDateTime(${columnTtl.ttlKey ?? "createdAt"}) + INTERVAL ${columnTtl.interval} ${columnTtl.unit}` : ""}`;
1491
1214
  }).join(",\n");
@@ -1504,8 +1227,8 @@ var StoreOperationsClickhouse = class extends StoreOperations {
1504
1227
  ${columns}
1505
1228
  )
1506
1229
  ENGINE = ${TABLE_ENGINES[tableName] ?? "MergeTree()"}
1507
- PRIMARY KEY (createdAt, ${tableName === TABLE_EVALS ? "run_id" : "id"})
1508
- ORDER BY (createdAt, ${tableName === TABLE_EVALS ? "run_id" : "id"})
1230
+ PRIMARY KEY (createdAt, ${"id"})
1231
+ ORDER BY (createdAt, ${"id"})
1509
1232
  ${this.ttl?.[tableName]?.row ? `TTL toDateTime(createdAt) + INTERVAL ${this.ttl[tableName].row.interval} ${this.ttl[tableName].row.unit}` : ""}
1510
1233
  SETTINGS index_granularity = 8192
1511
1234
  `;
@@ -1620,7 +1343,7 @@ var StoreOperationsClickhouse = class extends StoreOperations {
1620
1343
  use_client_time_zone: 1
1621
1344
  }
1622
1345
  });
1623
- console.log("INSERT RESULT", result);
1346
+ console.info("INSERT RESULT", result);
1624
1347
  } catch (error) {
1625
1348
  throw new MastraError(
1626
1349
  {
@@ -1734,7 +1457,7 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1734
1457
  const input = safelyParseJSON(row.input);
1735
1458
  const output = safelyParseJSON(row.output);
1736
1459
  const additionalContext = safelyParseJSON(row.additionalContext);
1737
- const runtimeContext = safelyParseJSON(row.runtimeContext);
1460
+ const requestContext = safelyParseJSON(row.requestContext);
1738
1461
  const entity = safelyParseJSON(row.entity);
1739
1462
  return {
1740
1463
  ...row,
@@ -1745,7 +1468,7 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1745
1468
  input,
1746
1469
  output,
1747
1470
  additionalContext,
1748
- runtimeContext,
1471
+ requestContext,
1749
1472
  entity,
1750
1473
  createdAt: new Date(row.createdAt),
1751
1474
  updatedAt: new Date(row.updatedAt)
@@ -1783,9 +1506,23 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1783
1506
  }
1784
1507
  }
1785
1508
  async saveScore(score) {
1509
+ let parsedScore;
1510
+ try {
1511
+ parsedScore = saveScorePayloadSchema.parse(score);
1512
+ } catch (error) {
1513
+ throw new MastraError(
1514
+ {
1515
+ id: "CLICKHOUSE_STORAGE_SAVE_SCORE_FAILED_INVALID_SCORE_PAYLOAD",
1516
+ domain: ErrorDomain.STORAGE,
1517
+ category: ErrorCategory.USER,
1518
+ details: { scoreId: score.id }
1519
+ },
1520
+ error
1521
+ );
1522
+ }
1786
1523
  try {
1787
1524
  const record = {
1788
- ...score
1525
+ ...parsedScore
1789
1526
  };
1790
1527
  await this.client.insert({
1791
1528
  table: TABLE_SCORERS,
@@ -1810,7 +1547,7 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1810
1547
  );
1811
1548
  }
1812
1549
  }
1813
- async getScoresByRunId({
1550
+ async listScoresByRunId({
1814
1551
  runId,
1815
1552
  pagination
1816
1553
  }) {
@@ -1826,24 +1563,28 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1826
1563
  const countObj = countRows[0];
1827
1564
  total = Number(countObj.count);
1828
1565
  }
1566
+ const { page, perPage: perPageInput } = pagination;
1829
1567
  if (!total) {
1830
1568
  return {
1831
1569
  pagination: {
1832
1570
  total: 0,
1833
- page: pagination.page,
1834
- perPage: pagination.perPage,
1571
+ page,
1572
+ perPage: perPageInput,
1835
1573
  hasMore: false
1836
1574
  },
1837
1575
  scores: []
1838
1576
  };
1839
1577
  }
1840
- const offset = pagination.page * pagination.perPage;
1578
+ const perPage = normalizePerPage(perPageInput, 100);
1579
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1580
+ const limitValue = perPageInput === false ? total : perPage;
1581
+ const end = perPageInput === false ? total : start + perPage;
1841
1582
  const result = await this.client.query({
1842
1583
  query: `SELECT * FROM ${TABLE_SCORERS} WHERE runId = {var_runId:String} ORDER BY createdAt DESC LIMIT {var_limit:Int64} OFFSET {var_offset:Int64}`,
1843
1584
  query_params: {
1844
1585
  var_runId: runId,
1845
- var_limit: pagination.perPage,
1846
- var_offset: offset
1586
+ var_limit: limitValue,
1587
+ var_offset: start
1847
1588
  },
1848
1589
  format: "JSONEachRow",
1849
1590
  clickhouse_settings: {
@@ -1858,9 +1599,9 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1858
1599
  return {
1859
1600
  pagination: {
1860
1601
  total,
1861
- page: pagination.page,
1862
- perPage: pagination.perPage,
1863
- hasMore: total > (pagination.page + 1) * pagination.perPage
1602
+ page,
1603
+ perPage: perPageForResponse,
1604
+ hasMore: end < total
1864
1605
  },
1865
1606
  scores
1866
1607
  };
@@ -1876,7 +1617,7 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1876
1617
  );
1877
1618
  }
1878
1619
  }
1879
- async getScoresByScorerId({
1620
+ async listScoresByScorerId({
1880
1621
  scorerId,
1881
1622
  entityId,
1882
1623
  entityType,
@@ -1910,24 +1651,28 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1910
1651
  const countObj = countRows[0];
1911
1652
  total = Number(countObj.count);
1912
1653
  }
1654
+ const { page, perPage: perPageInput } = pagination;
1913
1655
  if (!total) {
1914
1656
  return {
1915
1657
  pagination: {
1916
1658
  total: 0,
1917
- page: pagination.page,
1918
- perPage: pagination.perPage,
1659
+ page,
1660
+ perPage: perPageInput,
1919
1661
  hasMore: false
1920
1662
  },
1921
1663
  scores: []
1922
1664
  };
1923
1665
  }
1924
- const offset = pagination.page * pagination.perPage;
1666
+ const perPage = normalizePerPage(perPageInput, 100);
1667
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1668
+ const limitValue = perPageInput === false ? total : perPage;
1669
+ const end = perPageInput === false ? total : start + perPage;
1925
1670
  const result = await this.client.query({
1926
1671
  query: `SELECT * FROM ${TABLE_SCORERS} WHERE ${whereClause} ORDER BY createdAt DESC LIMIT {var_limit:Int64} OFFSET {var_offset:Int64}`,
1927
1672
  query_params: {
1928
1673
  var_scorerId: scorerId,
1929
- var_limit: pagination.perPage,
1930
- var_offset: offset,
1674
+ var_limit: limitValue,
1675
+ var_offset: start,
1931
1676
  var_entityId: entityId,
1932
1677
  var_entityType: entityType,
1933
1678
  var_source: source
@@ -1945,9 +1690,9 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1945
1690
  return {
1946
1691
  pagination: {
1947
1692
  total,
1948
- page: pagination.page,
1949
- perPage: pagination.perPage,
1950
- hasMore: total > (pagination.page + 1) * pagination.perPage
1693
+ page,
1694
+ perPage: perPageForResponse,
1695
+ hasMore: end < total
1951
1696
  },
1952
1697
  scores
1953
1698
  };
@@ -1963,7 +1708,7 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1963
1708
  );
1964
1709
  }
1965
1710
  }
1966
- async getScoresByEntityId({
1711
+ async listScoresByEntityId({
1967
1712
  entityId,
1968
1713
  entityType,
1969
1714
  pagination
@@ -1980,25 +1725,29 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
1980
1725
  const countObj = countRows[0];
1981
1726
  total = Number(countObj.count);
1982
1727
  }
1728
+ const { page, perPage: perPageInput } = pagination;
1983
1729
  if (!total) {
1984
1730
  return {
1985
1731
  pagination: {
1986
1732
  total: 0,
1987
- page: pagination.page,
1988
- perPage: pagination.perPage,
1733
+ page,
1734
+ perPage: perPageInput,
1989
1735
  hasMore: false
1990
1736
  },
1991
1737
  scores: []
1992
1738
  };
1993
1739
  }
1994
- const offset = pagination.page * pagination.perPage;
1740
+ const perPage = normalizePerPage(perPageInput, 100);
1741
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1742
+ const limitValue = perPageInput === false ? total : perPage;
1743
+ const end = perPageInput === false ? total : start + perPage;
1995
1744
  const result = await this.client.query({
1996
1745
  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}`,
1997
1746
  query_params: {
1998
1747
  var_entityId: entityId,
1999
1748
  var_entityType: entityType,
2000
- var_limit: pagination.perPage,
2001
- var_offset: offset
1749
+ var_limit: limitValue,
1750
+ var_offset: start
2002
1751
  },
2003
1752
  format: "JSONEachRow",
2004
1753
  clickhouse_settings: {
@@ -2013,9 +1762,9 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
2013
1762
  return {
2014
1763
  pagination: {
2015
1764
  total,
2016
- page: pagination.page,
2017
- perPage: pagination.perPage,
2018
- hasMore: total > (pagination.page + 1) * pagination.perPage
1765
+ page,
1766
+ perPage: perPageForResponse,
1767
+ hasMore: end < total
2019
1768
  },
2020
1769
  scores
2021
1770
  };
@@ -2031,76 +1780,51 @@ var ScoresStorageClickhouse = class extends ScoresStorage {
2031
1780
  );
2032
1781
  }
2033
1782
  }
2034
- };
2035
- var TracesStorageClickhouse = class extends TracesStorage {
2036
- client;
2037
- operations;
2038
- constructor({ client, operations }) {
2039
- super();
2040
- this.client = client;
2041
- this.operations = operations;
2042
- }
2043
- async getTracesPaginated(args) {
2044
- const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
2045
- const fromDate = dateRange?.start;
2046
- const toDate = dateRange?.end;
2047
- const currentOffset = page * perPage;
2048
- const queryArgs = {};
2049
- const conditions = [];
2050
- if (name) {
2051
- conditions.push(`name LIKE CONCAT({var_name:String}, '%')`);
2052
- queryArgs.var_name = name;
2053
- }
2054
- if (scope) {
2055
- conditions.push(`scope = {var_scope:String}`);
2056
- queryArgs.var_scope = scope;
2057
- }
2058
- if (attributes) {
2059
- Object.entries(attributes).forEach(([key, value]) => {
2060
- conditions.push(`JSONExtractString(attributes, '${key}') = {var_attr_${key}:String}`);
2061
- queryArgs[`var_attr_${key}`] = value;
2062
- });
2063
- }
2064
- if (filters) {
2065
- Object.entries(filters).forEach(([key, value]) => {
2066
- conditions.push(`${key} = {var_col_${key}:${TABLE_SCHEMAS.mastra_traces?.[key]?.type ?? "text"}}`);
2067
- queryArgs[`var_col_${key}`] = value;
2068
- });
2069
- }
2070
- if (fromDate) {
2071
- conditions.push(`createdAt >= parseDateTime64BestEffort({var_from_date:String})`);
2072
- queryArgs.var_from_date = fromDate.toISOString();
2073
- }
2074
- if (toDate) {
2075
- conditions.push(`createdAt <= parseDateTime64BestEffort({var_to_date:String})`);
2076
- queryArgs.var_to_date = toDate.toISOString();
2077
- }
2078
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1783
+ async listScoresBySpan({
1784
+ traceId,
1785
+ spanId,
1786
+ pagination
1787
+ }) {
2079
1788
  try {
2080
1789
  const countResult = await this.client.query({
2081
- query: `SELECT COUNT(*) as count FROM ${TABLE_TRACES} ${whereClause}`,
2082
- query_params: queryArgs,
2083
- clickhouse_settings: {
2084
- date_time_input_format: "best_effort",
2085
- date_time_output_format: "iso",
2086
- use_client_time_zone: 1,
2087
- output_format_json_quote_64bit_integers: 0
2088
- }
1790
+ query: `SELECT COUNT(*) as count FROM ${TABLE_SCORERS} WHERE traceId = {var_traceId:String} AND spanId = {var_spanId:String}`,
1791
+ query_params: {
1792
+ var_traceId: traceId,
1793
+ var_spanId: spanId
1794
+ },
1795
+ format: "JSONEachRow"
2089
1796
  });
2090
- const countData = await countResult.json();
2091
- const total = Number(countData.data?.[0]?.count ?? 0);
2092
- if (total === 0) {
1797
+ const countRows = await countResult.json();
1798
+ let total = 0;
1799
+ if (Array.isArray(countRows) && countRows.length > 0 && countRows[0]) {
1800
+ const countObj = countRows[0];
1801
+ total = Number(countObj.count);
1802
+ }
1803
+ const { page, perPage: perPageInput } = pagination;
1804
+ if (!total) {
2093
1805
  return {
2094
- traces: [],
2095
- total: 0,
2096
- page,
2097
- perPage,
2098
- hasMore: false
1806
+ pagination: {
1807
+ total: 0,
1808
+ page,
1809
+ perPage: perPageInput,
1810
+ hasMore: false
1811
+ },
1812
+ scores: []
2099
1813
  };
2100
1814
  }
1815
+ const perPage = normalizePerPage(perPageInput, 100);
1816
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1817
+ const limitValue = perPageInput === false ? total : perPage;
1818
+ const end = perPageInput === false ? total : start + perPage;
2101
1819
  const result = await this.client.query({
2102
- query: `SELECT *, toDateTime64(createdAt, 3) as createdAt FROM ${TABLE_TRACES} ${whereClause} ORDER BY "createdAt" DESC LIMIT {var_limit:UInt32} OFFSET {var_offset:UInt32}`,
2103
- query_params: { ...queryArgs, var_limit: perPage, var_offset: currentOffset },
1820
+ 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}`,
1821
+ query_params: {
1822
+ var_traceId: traceId,
1823
+ var_spanId: spanId,
1824
+ var_limit: limitValue,
1825
+ var_offset: start
1826
+ },
1827
+ format: "JSONEachRow",
2104
1828
  clickhouse_settings: {
2105
1829
  date_time_input_format: "best_effort",
2106
1830
  date_time_output_format: "iso",
@@ -2108,172 +1832,29 @@ var TracesStorageClickhouse = class extends TracesStorage {
2108
1832
  output_format_json_quote_64bit_integers: 0
2109
1833
  }
2110
1834
  });
2111
- if (!result) {
2112
- return {
2113
- traces: [],
2114
- total,
2115
- page,
2116
- perPage,
2117
- hasMore: false
2118
- };
2119
- }
2120
- const resp = await result.json();
2121
- const rows = resp.data;
2122
- const traces = rows.map((row) => ({
2123
- id: row.id,
2124
- parentSpanId: row.parentSpanId,
2125
- traceId: row.traceId,
2126
- name: row.name,
2127
- scope: row.scope,
2128
- kind: row.kind,
2129
- status: safelyParseJSON(row.status),
2130
- events: safelyParseJSON(row.events),
2131
- links: safelyParseJSON(row.links),
2132
- attributes: safelyParseJSON(row.attributes),
2133
- startTime: row.startTime,
2134
- endTime: row.endTime,
2135
- other: safelyParseJSON(row.other),
2136
- createdAt: row.createdAt
2137
- }));
1835
+ const rows = await result.json();
1836
+ const scores = Array.isArray(rows) ? rows.map((row) => this.transformScoreRow(row)) : [];
2138
1837
  return {
2139
- traces,
2140
- total,
2141
- page,
2142
- perPage,
2143
- hasMore: currentOffset + traces.length < total
2144
- };
2145
- } catch (error) {
2146
- if (error?.message?.includes("no such table") || error?.message?.includes("does not exist")) {
2147
- return {
2148
- traces: [],
2149
- total: 0,
1838
+ pagination: {
1839
+ total,
2150
1840
  page,
2151
- perPage,
2152
- hasMore: false
2153
- };
2154
- }
2155
- throw new MastraError(
2156
- {
2157
- id: "CLICKHOUSE_STORAGE_GET_TRACES_PAGINATED_FAILED",
2158
- domain: ErrorDomain.STORAGE,
2159
- category: ErrorCategory.THIRD_PARTY,
2160
- details: {
2161
- name: name ?? null,
2162
- scope: scope ?? null,
2163
- page,
2164
- perPage,
2165
- attributes: attributes ? JSON.stringify(attributes) : null,
2166
- filters: filters ? JSON.stringify(filters) : null,
2167
- dateRange: dateRange ? JSON.stringify(dateRange) : null
2168
- }
1841
+ perPage: perPageForResponse,
1842
+ hasMore: end < total
2169
1843
  },
2170
- error
2171
- );
2172
- }
2173
- }
2174
- async getTraces({
2175
- name,
2176
- scope,
2177
- page,
2178
- perPage,
2179
- attributes,
2180
- filters,
2181
- fromDate,
2182
- toDate
2183
- }) {
2184
- const limit = perPage;
2185
- const offset = page * perPage;
2186
- const args = {};
2187
- const conditions = [];
2188
- if (name) {
2189
- conditions.push(`name LIKE CONCAT({var_name:String}, '%')`);
2190
- args.var_name = name;
2191
- }
2192
- if (scope) {
2193
- conditions.push(`scope = {var_scope:String}`);
2194
- args.var_scope = scope;
2195
- }
2196
- if (attributes) {
2197
- Object.entries(attributes).forEach(([key, value]) => {
2198
- conditions.push(`JSONExtractString(attributes, '${key}') = {var_attr_${key}:String}`);
2199
- args[`var_attr_${key}`] = value;
2200
- });
2201
- }
2202
- if (filters) {
2203
- Object.entries(filters).forEach(([key, value]) => {
2204
- conditions.push(`${key} = {var_col_${key}:${TABLE_SCHEMAS.mastra_traces?.[key]?.type ?? "text"}}`);
2205
- args[`var_col_${key}`] = value;
2206
- });
2207
- }
2208
- if (fromDate) {
2209
- conditions.push(`createdAt >= {var_from_date:DateTime64(3)}`);
2210
- args.var_from_date = fromDate.getTime() / 1e3;
2211
- }
2212
- if (toDate) {
2213
- conditions.push(`createdAt <= {var_to_date:DateTime64(3)}`);
2214
- args.var_to_date = toDate.getTime() / 1e3;
2215
- }
2216
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2217
- try {
2218
- const result = await this.client.query({
2219
- query: `SELECT *, toDateTime64(createdAt, 3) as createdAt FROM ${TABLE_TRACES} ${whereClause} ORDER BY "createdAt" DESC LIMIT ${limit} OFFSET ${offset}`,
2220
- query_params: args,
2221
- clickhouse_settings: {
2222
- // Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
2223
- date_time_input_format: "best_effort",
2224
- date_time_output_format: "iso",
2225
- use_client_time_zone: 1,
2226
- output_format_json_quote_64bit_integers: 0
2227
- }
2228
- });
2229
- if (!result) {
2230
- return [];
2231
- }
2232
- const resp = await result.json();
2233
- const rows = resp.data;
2234
- return rows.map((row) => ({
2235
- id: row.id,
2236
- parentSpanId: row.parentSpanId,
2237
- traceId: row.traceId,
2238
- name: row.name,
2239
- scope: row.scope,
2240
- kind: row.kind,
2241
- status: safelyParseJSON(row.status),
2242
- events: safelyParseJSON(row.events),
2243
- links: safelyParseJSON(row.links),
2244
- attributes: safelyParseJSON(row.attributes),
2245
- startTime: row.startTime,
2246
- endTime: row.endTime,
2247
- other: safelyParseJSON(row.other),
2248
- createdAt: row.createdAt
2249
- }));
1844
+ scores
1845
+ };
2250
1846
  } catch (error) {
2251
- if (error?.message?.includes("no such table") || error?.message?.includes("does not exist")) {
2252
- return [];
2253
- }
2254
1847
  throw new MastraError(
2255
1848
  {
2256
- id: "CLICKHOUSE_STORAGE_GET_TRACES_FAILED",
1849
+ id: "CLICKHOUSE_STORAGE_GET_SCORES_BY_SPAN_FAILED",
2257
1850
  domain: ErrorDomain.STORAGE,
2258
1851
  category: ErrorCategory.THIRD_PARTY,
2259
- details: {
2260
- name: name ?? null,
2261
- scope: scope ?? null,
2262
- page,
2263
- perPage,
2264
- attributes: attributes ? JSON.stringify(attributes) : null,
2265
- filters: filters ? JSON.stringify(filters) : null,
2266
- fromDate: fromDate?.toISOString() ?? null,
2267
- toDate: toDate?.toISOString() ?? null
2268
- }
1852
+ details: { traceId, spanId }
2269
1853
  },
2270
1854
  error
2271
1855
  );
2272
1856
  }
2273
1857
  }
2274
- async batchTraceInsert(args) {
2275
- await this.operations.batchInsert({ tableName: TABLE_TRACES, records: args.records });
2276
- }
2277
1858
  };
2278
1859
  var WorkflowsStorageClickhouse = class extends WorkflowsStorage {
2279
1860
  client;
@@ -2288,7 +1869,7 @@ var WorkflowsStorageClickhouse = class extends WorkflowsStorage {
2288
1869
  // runId,
2289
1870
  // stepId,
2290
1871
  // result,
2291
- // runtimeContext,
1872
+ // requestContext,
2292
1873
  }) {
2293
1874
  throw new Error("Method not implemented.");
2294
1875
  }
@@ -2393,13 +1974,14 @@ var WorkflowsStorageClickhouse = class extends WorkflowsStorage {
2393
1974
  resourceId: row.resourceId
2394
1975
  };
2395
1976
  }
2396
- async getWorkflowRuns({
1977
+ async listWorkflowRuns({
2397
1978
  workflowName,
2398
1979
  fromDate,
2399
1980
  toDate,
2400
- limit,
2401
- offset,
2402
- resourceId
1981
+ page,
1982
+ perPage,
1983
+ resourceId,
1984
+ status
2403
1985
  } = {}) {
2404
1986
  try {
2405
1987
  const conditions = [];
@@ -2408,6 +1990,10 @@ var WorkflowsStorageClickhouse = class extends WorkflowsStorage {
2408
1990
  conditions.push(`workflow_name = {var_workflow_name:String}`);
2409
1991
  values.var_workflow_name = workflowName;
2410
1992
  }
1993
+ if (status) {
1994
+ conditions.push(`JSONExtractString(snapshot, 'status') = {var_status:String}`);
1995
+ values.var_status = status;
1996
+ }
2411
1997
  if (resourceId) {
2412
1998
  const hasResourceId = await this.operations.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
2413
1999
  if (hasResourceId) {
@@ -2426,10 +2012,13 @@ var WorkflowsStorageClickhouse = class extends WorkflowsStorage {
2426
2012
  values.var_to_date = toDate.getTime() / 1e3;
2427
2013
  }
2428
2014
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2429
- const limitClause = limit !== void 0 ? `LIMIT ${limit}` : "";
2430
- const offsetClause = offset !== void 0 ? `OFFSET ${offset}` : "";
2015
+ const usePagination = perPage !== void 0 && page !== void 0;
2016
+ const normalizedPerPage = usePagination ? normalizePerPage(perPage, Number.MAX_SAFE_INTEGER) : 0;
2017
+ const offset = usePagination ? page * normalizedPerPage : 0;
2018
+ const limitClause = usePagination ? `LIMIT ${normalizedPerPage}` : "";
2019
+ const offsetClause = usePagination ? `OFFSET ${offset}` : "";
2431
2020
  let total = 0;
2432
- if (limit !== void 0 && offset !== void 0) {
2021
+ if (usePagination) {
2433
2022
  const countResult = await this.client.query({
2434
2023
  query: `SELECT COUNT(*) as count FROM ${TABLE_WORKFLOW_SNAPSHOT} ${TABLE_ENGINES[TABLE_WORKFLOW_SNAPSHOT].startsWith("ReplacingMergeTree") ? "FINAL" : ""} ${whereClause}`,
2435
2024
  query_params: values,
@@ -2465,7 +2054,7 @@ var WorkflowsStorageClickhouse = class extends WorkflowsStorage {
2465
2054
  } catch (error) {
2466
2055
  throw new MastraError(
2467
2056
  {
2468
- id: "CLICKHOUSE_STORAGE_GET_WORKFLOW_RUNS_FAILED",
2057
+ id: "CLICKHOUSE_STORAGE_LIST_WORKFLOW_RUNS_FAILED",
2469
2058
  domain: ErrorDomain.STORAGE,
2470
2059
  category: ErrorCategory.THIRD_PARTY,
2471
2060
  details: { workflowName: workflowName ?? "", resourceId: resourceId ?? "" }
@@ -2531,7 +2120,7 @@ var ClickhouseStore = class extends MastraStorage {
2531
2120
  ttl = {};
2532
2121
  stores;
2533
2122
  constructor(config) {
2534
- super({ name: "ClickhouseStore" });
2123
+ super({ id: config.id, name: "ClickhouseStore" });
2535
2124
  this.db = createClient({
2536
2125
  url: config.url,
2537
2126
  username: config.username,
@@ -2548,15 +2137,11 @@ var ClickhouseStore = class extends MastraStorage {
2548
2137
  const operations = new StoreOperationsClickhouse({ client: this.db, ttl: this.ttl });
2549
2138
  const workflows = new WorkflowsStorageClickhouse({ client: this.db, operations });
2550
2139
  const scores = new ScoresStorageClickhouse({ client: this.db, operations });
2551
- const legacyEvals = new LegacyEvalsStorageClickhouse({ client: this.db, operations });
2552
- const traces = new TracesStorageClickhouse({ client: this.db, operations });
2553
2140
  const memory = new MemoryStorageClickhouse({ client: this.db, operations });
2554
2141
  this.stores = {
2555
2142
  operations,
2556
2143
  workflows,
2557
2144
  scores,
2558
- legacyEvals,
2559
- traces,
2560
2145
  memory
2561
2146
  };
2562
2147
  }
@@ -2566,15 +2151,10 @@ var ClickhouseStore = class extends MastraStorage {
2566
2151
  resourceWorkingMemory: true,
2567
2152
  hasColumn: true,
2568
2153
  createTable: true,
2569
- deleteMessages: false
2154
+ deleteMessages: false,
2155
+ listScoresBySpan: true
2570
2156
  };
2571
2157
  }
2572
- async getEvalsByAgentName(agentName, type) {
2573
- return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2574
- }
2575
- async getEvals(options) {
2576
- return this.stores.legacyEvals.getEvals(options);
2577
- }
2578
2158
  async batchInsert({ tableName, records }) {
2579
2159
  await this.stores.operations.batchInsert({ tableName, records });
2580
2160
  }
@@ -2642,9 +2222,9 @@ var ClickhouseStore = class extends MastraStorage {
2642
2222
  runId,
2643
2223
  stepId,
2644
2224
  result,
2645
- runtimeContext
2225
+ requestContext
2646
2226
  }) {
2647
- return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
2227
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2648
2228
  }
2649
2229
  async updateWorkflowState({
2650
2230
  workflowName,
@@ -2667,15 +2247,8 @@ var ClickhouseStore = class extends MastraStorage {
2667
2247
  }) {
2668
2248
  return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2669
2249
  }
2670
- async getWorkflowRuns({
2671
- workflowName,
2672
- fromDate,
2673
- toDate,
2674
- limit,
2675
- offset,
2676
- resourceId
2677
- } = {}) {
2678
- return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
2250
+ async listWorkflowRuns(args = {}) {
2251
+ return this.stores.workflows.listWorkflowRuns(args);
2679
2252
  }
2680
2253
  async getWorkflowRunById({
2681
2254
  runId,
@@ -2683,21 +2256,9 @@ var ClickhouseStore = class extends MastraStorage {
2683
2256
  }) {
2684
2257
  return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
2685
2258
  }
2686
- async getTraces(args) {
2687
- return this.stores.traces.getTraces(args);
2688
- }
2689
- async getTracesPaginated(args) {
2690
- return this.stores.traces.getTracesPaginated(args);
2691
- }
2692
- async batchTraceInsert(args) {
2693
- return this.stores.traces.batchTraceInsert(args);
2694
- }
2695
2259
  async getThreadById({ threadId }) {
2696
2260
  return this.stores.memory.getThreadById({ threadId });
2697
2261
  }
2698
- async getThreadsByResourceId({ resourceId }) {
2699
- return this.stores.memory.getThreadsByResourceId({ resourceId });
2700
- }
2701
2262
  async saveThread({ thread }) {
2702
2263
  return this.stores.memory.saveThread({ thread });
2703
2264
  }
@@ -2711,29 +2272,9 @@ var ClickhouseStore = class extends MastraStorage {
2711
2272
  async deleteThread({ threadId }) {
2712
2273
  return this.stores.memory.deleteThread({ threadId });
2713
2274
  }
2714
- async getThreadsByResourceIdPaginated(args) {
2715
- return this.stores.memory.getThreadsByResourceIdPaginated(args);
2716
- }
2717
- async getMessages({
2718
- threadId,
2719
- resourceId,
2720
- selectBy,
2721
- format
2722
- }) {
2723
- return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format });
2724
- }
2725
- async getMessagesById({
2726
- messageIds,
2727
- format
2728
- }) {
2729
- return this.stores.memory.getMessagesById({ messageIds, format });
2730
- }
2731
2275
  async saveMessages(args) {
2732
2276
  return this.stores.memory.saveMessages(args);
2733
2277
  }
2734
- async getMessagesPaginated(args) {
2735
- return this.stores.memory.getMessagesPaginated(args);
2736
- }
2737
2278
  async updateMessages(args) {
2738
2279
  return this.stores.memory.updateMessages(args);
2739
2280
  }
@@ -2756,27 +2297,34 @@ var ClickhouseStore = class extends MastraStorage {
2756
2297
  async saveScore(_score) {
2757
2298
  return this.stores.scores.saveScore(_score);
2758
2299
  }
2759
- async getScoresByRunId({
2300
+ async listScoresByRunId({
2760
2301
  runId,
2761
2302
  pagination
2762
2303
  }) {
2763
- return this.stores.scores.getScoresByRunId({ runId, pagination });
2304
+ return this.stores.scores.listScoresByRunId({ runId, pagination });
2764
2305
  }
2765
- async getScoresByEntityId({
2306
+ async listScoresByEntityId({
2766
2307
  entityId,
2767
2308
  entityType,
2768
2309
  pagination
2769
2310
  }) {
2770
- return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
2311
+ return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
2771
2312
  }
2772
- async getScoresByScorerId({
2313
+ async listScoresByScorerId({
2773
2314
  scorerId,
2774
2315
  pagination,
2775
2316
  entityId,
2776
2317
  entityType,
2777
2318
  source
2778
2319
  }) {
2779
- return this.stores.scores.getScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
2320
+ return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
2321
+ }
2322
+ async listScoresBySpan({
2323
+ traceId,
2324
+ spanId,
2325
+ pagination
2326
+ }) {
2327
+ return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
2780
2328
  }
2781
2329
  async close() {
2782
2330
  await this.db.close();