@mastra/clickhouse 1.14.0 → 1.15.0-alpha.0

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 CHANGED
@@ -1,5 +1,38 @@
1
1
  # @mastra/clickhouse
2
2
 
3
+ ## 1.15.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Memory list reads now surface database errors instead of silently returning empty results. ([#17910](https://github.com/mastra-ai/mastra/pull/17910))
8
+
9
+ Previously, the paginated memory reads (`listThreads`, `listMessages`, `listMessagesByResourceId`, and `listMessagesById`) caught backend failures, logged them, and returned an empty payload like `{ threads: [], total: 0, hasMore: false }`. A transient outage (locked table, dropped connection) was therefore indistinguishable from a genuinely empty result, so an agent reading conversation history during a brief failure would treat it as "no history" and could overwrite real state. These methods now re-throw the failure as a `MastraError`. Validation (USER) errors and genuinely empty results are unchanged.
10
+
11
+ **Behavior change**
12
+
13
+ Callers that previously received an empty result on a backend failure will now receive a thrown `MastraError`. If you call these read methods directly (rather than through an agent, which already surfaces errors), wrap them so a transient outage doesn't crash the caller:
14
+
15
+ ```ts
16
+ try {
17
+ const { threads } = await storage.listThreads({ resourceId });
18
+ // ...use threads
19
+ } catch (error) {
20
+ // a real backend failure. Decide whether to retry, surface, or degrade.
21
+ // An empty thread list no longer hides here; it only means "no threads".
22
+ }
23
+ ```
24
+
25
+ ### Patch Changes
26
+
27
+ - Fixed the ClickHouse lightweight trace list: responses no longer carry the `input`, `output` and `attributes` payload blobs, and delta polling now works. ([#20677](https://github.com/mastra-ai/mastra/pull/20677))
28
+
29
+ `listTracesLight` rows now carry a short `inputPreview` in place of the full input, plus the span `metadata` and a computed `status`, so Studio's configurable trace columns keep working — in both page and delta mode. Response payloads stay small as prompts grow. There is no schema change and no migration.
30
+
31
+ Requires `@mastra/core` >= 1.57.0, which ships the shared `buildInputPreview` and `computeTraceStatus` helpers this store now imports (peer dependency bumped accordingly).
32
+
33
+ - Updated dependencies [[`e7109ee`](https://github.com/mastra-ai/mastra/commit/e7109ee6f731bacc79c885906f3c7dca8d8f013a), [`772c0c8`](https://github.com/mastra-ai/mastra/commit/772c0c897cec383258de2e6178147f8014767c7b), [`578bf2e`](https://github.com/mastra-ai/mastra/commit/578bf2e6a88e9d5b8bf502204e15a95dfbb679ae), [`06b2d87`](https://github.com/mastra-ai/mastra/commit/06b2d87e63bcdd0ed59215c6789692b9b12de376), [`ac01d63`](https://github.com/mastra-ai/mastra/commit/ac01d6355974aec73fdb8781449ed12bac582094), [`a810a05`](https://github.com/mastra-ai/mastra/commit/a810a058f62ad407cfc1701e0be36ae91145d7cf), [`f8da216`](https://github.com/mastra-ai/mastra/commit/f8da21633e7eb0e31c9ce0fc30567870d19416d3), [`6104347`](https://github.com/mastra-ai/mastra/commit/61043473ba6bfd0a25156824e853e13165562e6c), [`45bfb88`](https://github.com/mastra-ai/mastra/commit/45bfb88fd52f1dd3be20e2a38905777c96499c90), [`e3b9307`](https://github.com/mastra-ai/mastra/commit/e3b9307098daefbfae2a52ae2ef51bc9fc701190), [`d6834c5`](https://github.com/mastra-ai/mastra/commit/d6834c5a7866b16734d23900163c2414ed70d791), [`c52d346`](https://github.com/mastra-ai/mastra/commit/c52d3462ec831a5d95926ecd3d3373f5928ad2e5), [`0023e79`](https://github.com/mastra-ai/mastra/commit/0023e7919431078280abd11c89d1edeae35fcc69), [`c2ad51e`](https://github.com/mastra-ai/mastra/commit/c2ad51e2467f901eecba8c9f4a45e22a50bd7c18), [`3dc97ea`](https://github.com/mastra-ai/mastra/commit/3dc97ea415fad353b48a13095fad1835933cc12a), [`3d01cd3`](https://github.com/mastra-ai/mastra/commit/3d01cd387321b6f9c5cac31d487c84bf51b19c78), [`7bf3086`](https://github.com/mastra-ai/mastra/commit/7bf308663f0115ca74ad20554ade740f06640859), [`a8dd139`](https://github.com/mastra-ai/mastra/commit/a8dd1391a9fe9a6632c25809ef236980afa9a020), [`e5786be`](https://github.com/mastra-ai/mastra/commit/e5786be02bb903073082bd9d6da880ebaacc343f), [`2093fbd`](https://github.com/mastra-ai/mastra/commit/2093fbd53bb744bae19ec89f6d73db9a66fbe8a7), [`e7a5da4`](https://github.com/mastra-ai/mastra/commit/e7a5da4ef8e4dd452d2f232961b4e682a85ffe43), [`7b4393d`](https://github.com/mastra-ai/mastra/commit/7b4393d557411fdcf07b0e30e5acaf7cc85154ae)]:
34
+ - @mastra/core@1.58.0-alpha.1
35
+
3
36
  ## 1.14.0
4
37
 
5
38
  ### Minor Changes
@@ -3,7 +3,7 @@ name: mastra-clickhouse
3
3
  description: Documentation for @mastra/clickhouse. Use when working with @mastra/clickhouse APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/clickhouse"
6
- version: "1.14.0"
6
+ version: "1.15.0-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.14.0",
2
+ "version": "1.15.0-alpha.0",
3
3
  "package": "@mastra/clickhouse",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -1270,6 +1270,7 @@ var MemoryStorageClickhouse = class extends _mastra_core_storage.MemoryStorage {
1270
1270
  hasMore: metadataFilter && perPageForResponse !== false ? offset + paginatedCount < total : perPageForResponse === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total
1271
1271
  };
1272
1272
  } catch (error) {
1273
+ if (error instanceof _mastra_core_error.MastraError && error.category === _mastra_core_error.ErrorCategory.USER) throw error;
1273
1274
  const mastraError = new _mastra_core_error.MastraError({
1274
1275
  id: (0, _mastra_core_storage.createStorageErrorId)("CLICKHOUSE", "LIST_MESSAGES", "FAILED"),
1275
1276
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -1281,13 +1282,7 @@ var MemoryStorageClickhouse = class extends _mastra_core_storage.MemoryStorage {
1281
1282
  }, error);
1282
1283
  this.logger?.error?.(mastraError.toString());
1283
1284
  this.logger?.trackException?.(mastraError);
1284
- return {
1285
- messages: [],
1286
- total: 0,
1287
- page,
1288
- perPage: perPageForResponse,
1289
- hasMore: false
1290
- };
1285
+ throw mastraError;
1291
1286
  }
1292
1287
  }
1293
1288
  _sortMessages(messages, field, direction) {
@@ -3873,6 +3868,7 @@ function rowToSpanRecord(row) {
3873
3868
  function rowToLightSpanRecord(row) {
3874
3869
  const startedAt = toDate(row.startedAt);
3875
3870
  const endedAt = row.isEvent ? startedAt : toDateOrNull(row.endedAt);
3871
+ const error = parseJson(row.error) ?? void 0;
3876
3872
  return {
3877
3873
  traceId: row.traceId,
3878
3874
  spanId: row.spanId,
@@ -3885,7 +3881,13 @@ function rowToLightSpanRecord(row) {
3885
3881
  entityType: nullableEntityType(row.entityType),
3886
3882
  entityId: nullableString(row.entityId),
3887
3883
  entityName: nullableString(row.entityName),
3888
- error: parseJson(row.error) ?? void 0,
3884
+ error,
3885
+ status: (0, _mastra_core_storage.computeTraceStatus)({
3886
+ error,
3887
+ endedAt
3888
+ }),
3889
+ metadata: parseJson(row.metadataRaw) ?? void 0,
3890
+ inputPreview: (0, _mastra_core_storage.buildInputPreview)(row.input ?? null),
3889
3891
  createdAt: startedAt,
3890
3892
  updatedAt: null
3891
3893
  };
@@ -6208,93 +6210,48 @@ async function getRootSpan(client, args) {
6208
6210
  return { span: rowToSpanRecord(rows[0]) };
6209
6211
  }
6210
6212
  /**
6211
- * Shared page-mode helper used by listTracesLight.
6213
+ * Columns a trace list renders. `input` is selected only so the row mapper can
6214
+ * derive a short `inputPreview` at read time (see `rowToLightSpanRecord`); the
6215
+ * raw blob itself never leaves the store.
6212
6216
  */
6213
- async function listTraceRows(client, args, selectClause, mapRows) {
6214
- const { filters, pagination, orderBy } = _mastra_core_storage.listTracesArgsSchema.parse(args);
6215
- const page = pagination?.page ?? 0;
6216
- const perPage = pagination?.perPage ?? 10;
6217
- const { conditions, params } = buildTraceFilterConditions(filters, "r");
6218
- if (filters?.hasChildError != null) if (filters.hasChildError) conditions.push(`EXISTS (
6219
- SELECT 1 FROM ${TABLE_SPAN_EVENTS} c
6220
- WHERE c.traceId = r.traceId
6221
- AND c.parentSpanId IS NOT NULL
6222
- AND c.error IS NOT NULL
6223
- )`);
6224
- else conditions.push(`NOT EXISTS (
6225
- SELECT 1 FROM ${TABLE_SPAN_EVENTS} c
6226
- WHERE c.traceId = r.traceId
6227
- AND c.parentSpanId IS NOT NULL
6228
- AND c.error IS NOT NULL
6229
- )`);
6230
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
6231
- const orderClause = buildTraceOrderByClause(orderBy);
6232
- const countRows = await (await client.query({
6233
- query: `
6234
- SELECT count() as cnt FROM (
6235
- SELECT dedupeKey
6236
- FROM ${TABLE_TRACE_ROOTS} r
6237
- ${whereClause}
6238
- ORDER BY dedupeKey
6239
- LIMIT 1 BY dedupeKey
6240
- )
6241
- `,
6242
- query_params: params,
6243
- format: "JSONEachRow",
6244
- clickhouse_settings: CH_SETTINGS
6245
- })).json();
6246
- const total = Number(countRows[0]?.cnt ?? 0);
6247
- if (total === 0) return {
6248
- pagination: {
6249
- total: 0,
6250
- page,
6251
- perPage,
6252
- hasMore: false
6253
- },
6254
- spans: []
6255
- };
6256
- const rows = await (await client.query({
6257
- query: `
6258
- SELECT ${selectClause} FROM (
6259
- SELECT ${selectClause}
6260
- FROM ${TABLE_TRACE_ROOTS} r
6261
- ${whereClause}
6262
- ORDER BY dedupeKey
6263
- LIMIT 1 BY dedupeKey
6264
- )
6265
- ORDER BY ${orderClause}
6266
- LIMIT {limit:UInt32}
6267
- OFFSET {offset:UInt32}
6268
- `,
6269
- query_params: {
6270
- ...params,
6271
- limit: perPage,
6272
- offset: page * perPage
6273
- },
6274
- format: "JSONEachRow",
6275
- clickhouse_settings: CH_SETTINGS
6276
- })).json();
6277
- return {
6278
- pagination: {
6279
- total,
6280
- page,
6281
- perPage,
6282
- hasMore: (page + 1) * perPage < total
6283
- },
6284
- spans: mapRows(rows)
6285
- };
6286
- }
6217
+ const LIGHT_TRACE_ROOT_FIELDS = [
6218
+ "traceId",
6219
+ "spanId",
6220
+ "parentSpanId",
6221
+ "name",
6222
+ "spanType",
6223
+ "isEvent",
6224
+ "startedAt",
6225
+ "endedAt",
6226
+ "entityType",
6227
+ "entityId",
6228
+ "entityName",
6229
+ "error",
6230
+ "metadataRaw",
6231
+ "input"
6232
+ ];
6233
+ const FULL_PROJECTION = {
6234
+ innerSelect: "*",
6235
+ outerSelect: "*",
6236
+ deltaSelect: "r.* EXCEPT(startedAt, traceId, dedupeKey)"
6237
+ };
6238
+ const LIGHT_PROJECTION = {
6239
+ innerSelect: ["dedupeKey", ...LIGHT_TRACE_ROOT_FIELDS].join(", "),
6240
+ outerSelect: LIGHT_TRACE_ROOT_FIELDS.join(", "),
6241
+ deltaSelect: LIGHT_TRACE_ROOT_FIELDS.filter((field) => field !== "startedAt" && field !== "traceId").map((field) => `r.${field}`).join(", ")
6242
+ };
6287
6243
  /**
6288
- * List traces with optional filtering, pagination, and ordering.
6244
+ * Shared implementation behind listTraces and listTracesLight.
6289
6245
  *
6290
6246
  * Reads from trace_roots (root spans only).
6291
- * Uses two-stage query for ReplacingMergeTree deduplication:
6247
+ * Page mode uses a two-stage query for ReplacingMergeTree deduplication:
6292
6248
  * Inner: filter + deterministic ORDER BY + LIMIT 1 BY dedupeKey
6293
6249
  * Outer: final ordering + pagination
6250
+ * Delta mode joins the append-only delta table and returns only rows past the cursor.
6294
6251
  *
6295
6252
  * hasChildError is handled via EXISTS subquery against span_events.
6296
6253
  */
6297
- async function listTraces(client, args, strategy) {
6254
+ async function listTraceRows(client, args, strategy, projection, mapRows) {
6298
6255
  const { mode, filters, pagination, orderBy, after, limit } = _mastra_core_storage.listTracesArgsSchema.parse(args);
6299
6256
  const page = pagination?.page ?? 0;
6300
6257
  const perPage = pagination?.perPage ?? 10;
@@ -6324,10 +6281,11 @@ async function listTraces(client, args, strategy) {
6324
6281
  },
6325
6282
  deltaCursor: streamHeadCursor
6326
6283
  };
6327
- const rows = await queryTracesAfterCursor(client, whereClause, params, limit, validateCursorId(after));
6284
+ const afterCursor = validateCursorId(after);
6285
+ const rows = await queryTracesAfterCursor(client, projection.deltaSelect, whereClause, params, limit, afterCursor);
6328
6286
  const visibleRows = rows.slice(0, limit);
6329
6287
  return {
6330
- spans: (0, _mastra_core_storage.toTraceSpans)(visibleRows.map(rowToSpanRecord)),
6288
+ spans: mapRows(visibleRows),
6331
6289
  delta: {
6332
6290
  limit,
6333
6291
  hasMore: rows.length > limit
@@ -6362,10 +6320,10 @@ async function listTraces(client, args, strategy) {
6362
6320
  spans: [],
6363
6321
  ...deltaCursorEnabled ? { deltaCursor: currentDeltaCursor } : {}
6364
6322
  };
6365
- const spans = (await (await client.query({
6323
+ const rows = await (await client.query({
6366
6324
  query: `
6367
- SELECT * FROM (
6368
- SELECT *
6325
+ SELECT ${projection.outerSelect} FROM (
6326
+ SELECT ${projection.innerSelect}
6369
6327
  FROM ${TABLE_TRACE_ROOTS} r
6370
6328
  ${whereClause}
6371
6329
  ORDER BY dedupeKey
@@ -6382,7 +6340,7 @@ async function listTraces(client, args, strategy) {
6382
6340
  },
6383
6341
  format: "JSONEachRow",
6384
6342
  clickhouse_settings: CH_SETTINGS
6385
- })).json()).map(rowToSpanRecord);
6343
+ })).json();
6386
6344
  return {
6387
6345
  pagination: {
6388
6346
  total,
@@ -6390,32 +6348,27 @@ async function listTraces(client, args, strategy) {
6390
6348
  perPage,
6391
6349
  hasMore: (page + 1) * perPage < total
6392
6350
  },
6393
- spans: (0, _mastra_core_storage.toTraceSpans)(spans),
6351
+ spans: mapRows(rows),
6394
6352
  ...deltaCursorEnabled ? { deltaCursor: currentDeltaCursor } : {}
6395
6353
  };
6396
6354
  }
6397
- const LIGHT_TRACE_ROOT_COLUMNS = [
6398
- "traceId",
6399
- "spanId",
6400
- "parentSpanId",
6401
- "name",
6402
- "spanType",
6403
- "isEvent",
6404
- "startedAt",
6405
- "endedAt",
6406
- "entityType",
6407
- "entityId",
6408
- "entityName",
6409
- "error"
6410
- ].join(", ");
6411
- async function listTracesLight(client, args) {
6412
- return listTraceRows(client, args, LIGHT_TRACE_ROOT_COLUMNS, (rows) => rows.map(rowToLightSpanRecord));
6355
+ /** List traces with optional filtering, pagination, and ordering. */
6356
+ async function listTraces(client, args, strategy) {
6357
+ return listTraceRows(client, args, strategy, FULL_PROJECTION, (rows) => (0, _mastra_core_storage.toTraceSpans)(rows.map(rowToSpanRecord)));
6358
+ }
6359
+ /**
6360
+ * List traces projecting only the columns a trace list renders.
6361
+ * Skips the attributes/output blobs and reduces `input` to a short preview in
6362
+ * the mapper, so the response payload stays flat as traces grow.
6363
+ */
6364
+ async function listTracesLight(client, args, strategy) {
6365
+ return listTraceRows(client, args, strategy, LIGHT_PROJECTION, (rows) => rows.map(rowToLightSpanRecord));
6413
6366
  }
6414
- async function queryTracesAfterCursor(client, whereClause, params, limit, cursorId) {
6367
+ async function queryTracesAfterCursor(client, deltaSelect, whereClause, params, limit, cursorId) {
6415
6368
  return await (await client.query({
6416
6369
  query: `
6417
6370
  SELECT
6418
- r.* EXCEPT(startedAt, traceId, dedupeKey),
6371
+ ${deltaSelect},
6419
6372
  r.startedAt AS startedAt,
6420
6373
  r.traceId AS traceId,
6421
6374
  r.dedupeKey AS dedupeKey,
@@ -7392,7 +7345,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
7392
7345
  }
7393
7346
  async listTracesLight(args) {
7394
7347
  try {
7395
- return await listTracesLight(this.#client, args);
7348
+ return await listTracesLight(this.#client, args, this.#deltaCursorStrategy);
7396
7349
  } catch (error) {
7397
7350
  if (error instanceof _mastra_core_error.MastraError) throw error;
7398
7351
  throw new _mastra_core_error.MastraError({