@mastra/clickhouse 1.25.1 → 1.26.0-alpha.1

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
@@ -3815,9 +3815,27 @@ function readPreview(preview, payload, jsonEncoded = false) {
3815
3815
  }
3816
3816
  /** Older response builders may shorten previews or turn empty strings into null. */
3817
3817
  function buildSpanQueryResponse(...args) {
3818
- if (canGeneratePreviews) return coreStorage.buildSpanQueryResponse(...args);
3819
- const [plan, selected, payloads, metrics] = args;
3820
- const response = coreStorage.buildSpanQueryResponse(plan, selected, [], metrics);
3818
+ const [plan, selected, payloads, metrics = []] = args;
3819
+ const compatibleSelected = coreStorage.SPAN_QUERY_FIELD_REGISTRY ? selected : selected.map((row) => ({
3820
+ organizationId: row.organizationId,
3821
+ resourceId: row.resourceId,
3822
+ traceId: row.traceId,
3823
+ spanId: row.spanId,
3824
+ parentSpanId: row.parentSpanId,
3825
+ name: row.name,
3826
+ spanType: row.spanType,
3827
+ status: row.status,
3828
+ startedAt: row.startedAt,
3829
+ endedAt: row.endedAt,
3830
+ durationMs: row.durationMs,
3831
+ entityType: row.entityType,
3832
+ entityId: row.entityId,
3833
+ entityName: row.entityName,
3834
+ model: row.model,
3835
+ provider: row.provider
3836
+ }));
3837
+ if (canGeneratePreviews) return coreStorage.buildSpanQueryResponse(plan, compatibleSelected, payloads, metrics);
3838
+ const response = coreStorage.buildSpanQueryResponse(plan, compatibleSelected, [], metrics);
3821
3839
  const byIdentity = new Map(payloads.map((payload) => [coreStorage.spanQueryIdentityKey(payload), payload]));
3822
3840
  for (const span of response.spans) {
3823
3841
  const payload = byIdentity.get(coreStorage.spanQueryIdentityKey(span));
@@ -4769,6 +4787,7 @@ function buildMetricsFilterConditions(filters, tableAlias) {
4769
4787
  assertNoDeprecatedSourceFilter(filters.source, "executionSource", "metrics");
4770
4788
  addCommonFilterFields(filters, tableAlias, out);
4771
4789
  addIn(col("traceId"), filters.traceIds, "traceIds", out);
4790
+ addIn(col("experimentId"), filters.experimentIds, "experimentIds", out);
4772
4791
  addIn(col("name"), filters.name, "metricNames", out);
4773
4792
  addEq(col("provider"), filters.provider, "provider", "String", out);
4774
4793
  addEq(col("model"), filters.model, "model", "String", out);
@@ -6962,6 +6981,73 @@ const SPAN_FIELDS = {
6962
6981
  parameterType: "String"
6963
6982
  }
6964
6983
  };
6984
+ const SPAN_QUERY_FIELDS = {
6985
+ ...SPAN_FIELDS,
6986
+ traceId: {
6987
+ sql: "s.traceId",
6988
+ parameterType: "String"
6989
+ },
6990
+ spanId: {
6991
+ sql: "s.spanId",
6992
+ parameterType: "String"
6993
+ },
6994
+ parentSpanId: {
6995
+ sql: "s.parentSpanId",
6996
+ parameterType: "String"
6997
+ },
6998
+ threadId: {
6999
+ sql: "s.threadId",
7000
+ parameterType: "String"
7001
+ },
7002
+ resourceId: {
7003
+ sql: "s.resourceId",
7004
+ parameterType: "String"
7005
+ },
7006
+ requestId: {
7007
+ sql: "s.requestId",
7008
+ parameterType: "String"
7009
+ },
7010
+ serviceName: {
7011
+ sql: "s.serviceName",
7012
+ parameterType: "String"
7013
+ },
7014
+ experimentId: {
7015
+ sql: "s.experimentId",
7016
+ parameterType: "String"
7017
+ },
7018
+ environment: {
7019
+ sql: "s.environment",
7020
+ parameterType: "String"
7021
+ },
7022
+ executionSource: {
7023
+ sql: "s.executionSource",
7024
+ parameterType: "String"
7025
+ },
7026
+ parentEntityType: {
7027
+ sql: "s.parentEntityType",
7028
+ parameterType: "String"
7029
+ },
7030
+ parentEntityId: {
7031
+ sql: "s.parentEntityId",
7032
+ parameterType: "String"
7033
+ },
7034
+ parentEntityName: {
7035
+ sql: "s.parentEntityName",
7036
+ parameterType: "String"
7037
+ },
7038
+ rootEntityType: {
7039
+ sql: "s.rootEntityType",
7040
+ parameterType: "String"
7041
+ },
7042
+ rootEntityId: {
7043
+ sql: "s.rootEntityId",
7044
+ parameterType: "String"
7045
+ },
7046
+ rootEntityName: {
7047
+ sql: "s.rootEntityName",
7048
+ parameterType: "String"
7049
+ }
7050
+ };
6965
7051
  const SCORE_FIELDS = {
6966
7052
  scorerId: {
6967
7053
  sql: "s.scorerId",
@@ -7833,11 +7919,11 @@ async function queryThreads(client, plan, timeoutMs) {
7833
7919
  }) : null }
7834
7920
  });
7835
7921
  }
7836
- /** Compile a span-row filter with exactly the same rules as trace span predicates. */
7922
+ /** Compile a direct span-query filter using its dedicated field mapping. */
7837
7923
  function compileSpanQueryPredicate(predicate) {
7838
7924
  const parameters = new ParameterBuilder();
7839
7925
  return {
7840
- sql: compileScalarPredicate(predicate, SPAN_FIELDS, parameters),
7926
+ sql: compileScalarPredicate(predicate, SPAN_QUERY_FIELDS, parameters),
7841
7927
  params: parameters.params
7842
7928
  };
7843
7929
  }
@@ -7851,7 +7937,6 @@ const identityFields = [
7851
7937
  ];
7852
7938
  const identities = identityFields.join(", ");
7853
7939
  const identitySetColumns = "isNull(organizationId), ifNull(organizationId, ''), isNull(resourceId), ifNull(resourceId, ''), traceId, spanId";
7854
- const identitySetKey = `tuple(${identitySetColumns})`;
7855
7940
  const displayFields = [
7856
7941
  "parentSpanId",
7857
7942
  "name",
@@ -7859,6 +7944,24 @@ const displayFields = [
7859
7944
  "entityType",
7860
7945
  "entityId",
7861
7946
  "entityName",
7947
+ "entityVersionId",
7948
+ "parentEntityType",
7949
+ "parentEntityId",
7950
+ "parentEntityName",
7951
+ "parentEntityVersionId",
7952
+ "rootEntityType",
7953
+ "rootEntityId",
7954
+ "rootEntityName",
7955
+ "rootEntityVersionId",
7956
+ "threadId",
7957
+ "runId",
7958
+ "sessionId",
7959
+ "userId",
7960
+ "requestId",
7961
+ "serviceName",
7962
+ "experimentId",
7963
+ "environment",
7964
+ "executionSource",
7862
7965
  "startedAt",
7863
7966
  "endedAt",
7864
7967
  "model",
@@ -7937,15 +8040,11 @@ function compileClickHouseSpanQuery(plan) {
7937
8040
  const expressions = selectionFields.map(fieldExpression);
7938
8041
  const after = afterCursor(plan, parameters);
7939
8042
  return {
7940
- query: `WITH candidate_ids AS (
7941
- SELECT ${identitySetKey} AS identity FROM ${TABLE_SPAN_EVENTS}
7942
- PREWHERE endedAt >= ${from}
7943
- WHERE startedAt >= ${from} AND startedAt < ${to} ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
7944
- ), candidates AS (
8043
+ query: `WITH candidates AS (
7945
8044
  SELECT ${identities}, ${selectionFields.map((field, index) => `${expressions[index]} AS ${field}`).join(", ")}
7946
8045
  FROM ${TABLE_SPAN_EVENTS} e
7947
8046
  PREWHERE e.endedAt >= ${from}
7948
- WHERE ${identitySetKey} IN (SELECT identity FROM candidate_ids) ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
8047
+ WHERE e.startedAt >= ${from} AND e.startedAt < ${to} ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
7949
8048
  ORDER BY ${identities}, e.endedAt DESC
7950
8049
  LIMIT 1 BY ${identities}
7951
8050
  )
@@ -7963,6 +8062,7 @@ function compileClickHouseSpanQuery(plan) {
7963
8062
  }
7964
8063
  };
7965
8064
  }
8065
+ const LEGACY_PAYLOAD_BATCH_ROWS = 32;
7966
8066
  function iso(value) {
7967
8067
  return new Date(value.includes("T") ? value : `${value.replace(" ", "T")}Z`).toISOString();
7968
8068
  }
@@ -7996,34 +8096,25 @@ async function querySpans(client, plan, timeoutMs) {
7996
8096
  });
7997
8097
  const missingKeys = new Set(rowsWithPreviews.filter(needsPreviewPayloads).map(coreStorage.spanQueryIdentityKey));
7998
8098
  const missing = page.filter((row) => missingKeys.has(coreStorage.spanQueryIdentityKey(row)));
7999
- const previewPayloads = /* @__PURE__ */ new Map();
8000
- if (missing.length) {
8099
+ const storedByIdentity = new Map(rowsWithPreviews.map((row) => [coreStorage.spanQueryIdentityKey(row), row]));
8100
+ for (let start = 0; start < missing.length; start += LEGACY_PAYLOAD_BATCH_ROWS) {
8001
8101
  const rows = await run({
8002
8102
  query: `SELECT ${identities}, data.1 AS input, data.2 AS output, data.3 AS error
8003
8103
  FROM (SELECT ${identities}, any(tuple(input, output, error)) AS data
8004
8104
  FROM ${TABLE_SPAN_EVENTS} e WHERE ${payloadWhere} GROUP BY ${identities})`,
8005
- query_params: { page: pageParameter(missing) }
8105
+ query_params: { page: pageParameter(missing.slice(start, start + LEGACY_PAYLOAD_BATCH_ROWS)) }
8006
8106
  });
8007
- for (const row of rows) previewPayloads.set(coreStorage.spanQueryIdentityKey(row), row);
8107
+ for (const row of rows) {
8108
+ const stored = storedByIdentity.get(coreStorage.spanQueryIdentityKey(row));
8109
+ if (stored) Object.assign(stored, resolveStoredPreviews(stored, row));
8110
+ }
8008
8111
  }
8009
8112
  const payloads = rowsWithPreviews.map((row) => ({
8010
8113
  ...row,
8011
- ...resolveStoredPreviews(row, previewPayloads.get(coreStorage.spanQueryIdentityKey(row)))
8114
+ ...resolveStoredPreviews(row)
8012
8115
  }));
8013
- const metricWhere = `${identitySetKey} IN {page:Array(Tuple(UInt8, String, UInt8, String, String, String))}`;
8014
- const metrics = await run({
8015
- query: `SELECT ${identities}, data.1 AS name, data.2 AS estimatedCost,
8016
- data.3 AS costUnit, data.4 AS allocation, data.5 AS costError
8017
- FROM (SELECT ${identities}, metricId, argMax(tuple(name, estimatedCost, costUnit,
8018
- JSONExtractString(costMetadata, 'allocation'), JSONHas(costMetadata, 'error')), timestamp) AS data
8019
- FROM ${TABLE_METRIC_EVENTS} WHERE (${metricWhere}) AND name LIKE 'mastra_model_%'
8020
- GROUP BY ${identities}, metricId)
8021
- LIMIT ${coreStorage.SPAN_QUERY_MAX_COST_METRICS + 1}`,
8022
- query_params: { page: page.map((row) => new TupleParam(identityValues(row))) }
8023
- });
8024
- if (metrics.length > coreStorage.SPAN_QUERY_MAX_COST_METRICS) throw new coreStorage.TraceQueryResourceLimitError();
8025
8116
  const byIdentity = new Map(payloads.map((row) => [coreStorage.spanQueryIdentityKey(row), row]));
8026
- const result = buildSpanQueryResponse(plan, page.flatMap((identity) => {
8117
+ const hydrated = page.flatMap((identity) => {
8027
8118
  const row = byIdentity.get(coreStorage.spanQueryIdentityKey(identity));
8028
8119
  if (!row) return [];
8029
8120
  const { inputPreview: _input, outputPreview: _output, errorPreview: _error, ...metadata } = row;
@@ -8032,7 +8123,22 @@ async function querySpans(client, plan, timeoutMs) {
8032
8123
  ...identity,
8033
8124
  durationMs: Number(row.durationMs)
8034
8125
  }];
8035
- }), payloads, metrics);
8126
+ });
8127
+ let metrics = [];
8128
+ if (!coreStorage.SPAN_QUERY_FIELD_REGISTRY) {
8129
+ metrics = await run({
8130
+ query: `SELECT ${identities}, data.1 AS name, data.2 AS estimatedCost,
8131
+ data.3 AS costUnit, data.4 AS allocation, data.5 AS costError
8132
+ FROM (SELECT ${identities}, metricId, argMax(tuple(name, estimatedCost, costUnit,
8133
+ JSONExtractString(costMetadata, 'allocation'), JSONHas(costMetadata, 'error')), timestamp) AS data
8134
+ FROM ${TABLE_METRIC_EVENTS} WHERE (${`tuple(${identitySetColumns}) IN {page:Array(Tuple(UInt8, String, UInt8, String, String, String))}`}) AND name LIKE 'mastra_model_%'
8135
+ GROUP BY ${identities}, metricId)
8136
+ LIMIT ${coreStorage.SPAN_QUERY_MAX_COST_METRICS + 1}`,
8137
+ query_params: { page: page.map((row) => new TupleParam(identityValues(row))) }
8138
+ });
8139
+ if (metrics.length > coreStorage.SPAN_QUERY_MAX_COST_METRICS) throw new coreStorage.TraceQueryResourceLimitError();
8140
+ }
8141
+ const result = buildSpanQueryResponse(plan, hydrated, payloads, metrics);
8036
8142
  const last = page.at(-1);
8037
8143
  result.page.next = selected.length > plan.limit ? coreStorage.encodeSpanQueryCursor(plan, {
8038
8144
  organizationId: last.organizationId,
@@ -9191,7 +9297,7 @@ function buildBranchCursor(row) {
9191
9297
  }
9192
9298
  //#endregion
9193
9299
  //#region src/storage/domains/observability/v-next/index.ts
9194
- const spanQueryFeatures = typeof coreStorage.planSpanQuery === "function" ? ["span-query"] : [];
9300
+ const spanQueryFeatures = typeof coreStorage.planSpanQuery === "function" ? ["span-query", "span-query-context-fields"] : [];
9195
9301
  function buildSignalMigrationRequiredMessage(args) {
9196
9302
  const tableList = args.tables.map((table) => ` - ${table.table} (${table.engine})`).join("\n");
9197
9303
  return `