@mastra/clickhouse 1.27.0 → 1.28.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/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +50 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +50 -19
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/preview-compat.d.ts +1 -0
- package/dist/storage/domains/observability/v-next/preview-compat.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/span-query.d.ts +1 -0
- package/dist/storage/domains/observability/v-next/span-query.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/thread-query.d.ts +1 -0
- package/dist/storage/domains/observability/v-next/thread-query.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts +3 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/docs/SKILL.md
CHANGED
|
@@ -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.
|
|
6
|
+
version: "1.28.0-alpha.1"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## When to use
|
package/dist/index.cjs
CHANGED
|
@@ -781,6 +781,7 @@ var ClickhouseDB = class extends _mastra_core_base.MastraBase {
|
|
|
781
781
|
const rawUpdatedAt = filteredRecord.updatedAt || /* @__PURE__ */ new Date();
|
|
782
782
|
if ("createdAt" in filteredRecord || (await this.getTableColumns(tableName)).has("createdAt")) filteredRecord.createdAt = rawCreatedAt instanceof Date ? rawCreatedAt.toISOString() : rawCreatedAt;
|
|
783
783
|
if ("updatedAt" in filteredRecord || (await this.getTableColumns(tableName)).has("updatedAt")) filteredRecord.updatedAt = rawUpdatedAt instanceof Date ? rawUpdatedAt.toISOString() : rawUpdatedAt;
|
|
784
|
+
for (const [key, value] of Object.entries(filteredRecord)) if (_mastra_core_storage.TABLE_SCHEMAS[tableName]?.[key]?.type === "timestamp" && typeof value === "number") filteredRecord[key] = new Date(value).toISOString();
|
|
784
785
|
await this.client.insert({
|
|
785
786
|
table: tableName,
|
|
786
787
|
values: [filteredRecord],
|
|
@@ -2293,12 +2294,12 @@ var ObservabilityStorageClickhouse = class extends _mastra_core_storage.Observab
|
|
|
2293
2294
|
}
|
|
2294
2295
|
});
|
|
2295
2296
|
const data = { ...updates };
|
|
2296
|
-
if (data.endedAt instanceof Date) data.endedAt = data.endedAt.
|
|
2297
|
-
if (data.startedAt instanceof Date) data.startedAt = data.startedAt.
|
|
2297
|
+
if (data.endedAt instanceof Date) data.endedAt = data.endedAt.toISOString();
|
|
2298
|
+
if (data.startedAt instanceof Date) data.startedAt = data.startedAt.toISOString();
|
|
2298
2299
|
const updated = {
|
|
2299
2300
|
...existing,
|
|
2300
2301
|
...data,
|
|
2301
|
-
updatedAt: Date.
|
|
2302
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2302
2303
|
};
|
|
2303
2304
|
await this.client.insert({
|
|
2304
2305
|
table: _mastra_core_storage.TABLE_SPANS,
|
|
@@ -2536,7 +2537,7 @@ var ObservabilityStorageClickhouse = class extends _mastra_core_storage.Observab
|
|
|
2536
2537
|
}
|
|
2537
2538
|
async batchUpdateSpans(args) {
|
|
2538
2539
|
try {
|
|
2539
|
-
const now = Date.
|
|
2540
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2540
2541
|
if (args.records.length === 0) return;
|
|
2541
2542
|
const keyParams = {};
|
|
2542
2543
|
const keyTuples = args.records.map((record, i) => {
|
|
@@ -2569,8 +2570,8 @@ var ObservabilityStorageClickhouse = class extends _mastra_core_storage.Observab
|
|
|
2569
2570
|
const existing = current.get(key);
|
|
2570
2571
|
if (!existing) continue;
|
|
2571
2572
|
const updates = { ...record.updates };
|
|
2572
|
-
if (updates.startedAt instanceof Date) updates.startedAt = updates.startedAt.
|
|
2573
|
-
if (updates.endedAt instanceof Date) updates.endedAt = updates.endedAt.
|
|
2573
|
+
if (updates.startedAt instanceof Date) updates.startedAt = updates.startedAt.toISOString();
|
|
2574
|
+
if (updates.endedAt instanceof Date) updates.endedAt = updates.endedAt.toISOString();
|
|
2574
2575
|
current.set(key, {
|
|
2575
2576
|
...existing,
|
|
2576
2577
|
...updates,
|
|
@@ -6928,7 +6929,17 @@ const TRACE_STATUS_SQL = `if(isNotNull(r.error), 'error', 'success')`;
|
|
|
6928
6929
|
const timeToFirstChunkSupported = "timeToFirstChunkMs" in (_mastra_core_storage.TRACE_QUERY_FIELD_REGISTRY?.trace ?? {});
|
|
6929
6930
|
/** Core before the sort rejects `orderBy` on the field, so the sort is only declared when core plans it. */
|
|
6930
6931
|
const timeToFirstChunkSortSupported = _mastra_core_storage.TRACE_QUERY_ORDER_FIELDS?.includes("timeToFirstChunkMs") === true;
|
|
6931
|
-
|
|
6932
|
+
/** Same rule for time to first token: returned and sorted only when core knows the field. */
|
|
6933
|
+
const timeToFirstTokenSupported = "timeToFirstTokenMs" in (_mastra_core_storage.TRACE_QUERY_FIELD_REGISTRY?.trace ?? {});
|
|
6934
|
+
const timeToFirstTokenSortSupported = _mastra_core_storage.TRACE_QUERY_ORDER_FIELDS?.includes("timeToFirstTokenMs") === true;
|
|
6935
|
+
const timingFeatures = [
|
|
6936
|
+
...timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [],
|
|
6937
|
+
...timeToFirstChunkSupported && timeToFirstChunkSortSupported ? ["trace-query-time-to-first-chunk-sort"] : [],
|
|
6938
|
+
...timeToFirstTokenSupported ? ["trace-query-time-to-first-token"] : [],
|
|
6939
|
+
...timeToFirstTokenSupported && timeToFirstTokenSortSupported ? ["trace-query-time-to-first-token-sort"] : []
|
|
6940
|
+
];
|
|
6941
|
+
/** Order fields holding numbers that can be empty; the rest are timestamps. */
|
|
6942
|
+
const NUMERIC_ORDER_FIELDS = /* @__PURE__ */ new Set(["timeToFirstChunkMs", "timeToFirstTokenMs"]);
|
|
6932
6943
|
function durationMsSql(startedAt, endedAt) {
|
|
6933
6944
|
return `dateDiff('millisecond', ${startedAt}, ${endedAt})`;
|
|
6934
6945
|
}
|
|
@@ -6981,6 +6992,10 @@ const TRACE_FIELDS = {
|
|
|
6981
6992
|
sql: "r.timeToFirstChunkMs",
|
|
6982
6993
|
parameterType: "Float64"
|
|
6983
6994
|
},
|
|
6995
|
+
timeToFirstTokenMs: {
|
|
6996
|
+
sql: "r.timeToFirstTokenMs",
|
|
6997
|
+
parameterType: "Float64"
|
|
6998
|
+
},
|
|
6984
6999
|
entityId: {
|
|
6985
7000
|
sql: "r.entityId",
|
|
6986
7001
|
parameterType: "String"
|
|
@@ -7047,6 +7062,10 @@ const SPAN_FIELDS = {
|
|
|
7047
7062
|
sql: "s.timeToFirstChunkMs",
|
|
7048
7063
|
parameterType: "Float64"
|
|
7049
7064
|
},
|
|
7065
|
+
timeToFirstTokenMs: {
|
|
7066
|
+
sql: "s.timeToFirstTokenMs",
|
|
7067
|
+
parameterType: "Float64"
|
|
7068
|
+
},
|
|
7050
7069
|
status: {
|
|
7051
7070
|
sql: "s.status",
|
|
7052
7071
|
parameterType: "String"
|
|
@@ -7259,6 +7278,7 @@ const TRACE_SELECT = `
|
|
|
7259
7278
|
r.entityType AS entityType,
|
|
7260
7279
|
r.environment AS environment,
|
|
7261
7280
|
r.timeToFirstChunkMs AS timeToFirstChunkMs,
|
|
7281
|
+
r.timeToFirstTokenMs AS timeToFirstTokenMs,
|
|
7262
7282
|
${TRACE_STATUS_SQL} AS status`;
|
|
7263
7283
|
var ParameterBuilder = class {
|
|
7264
7284
|
params = {};
|
|
@@ -7275,7 +7295,7 @@ function fieldDefinition(registry, field) {
|
|
|
7275
7295
|
return definition;
|
|
7276
7296
|
}
|
|
7277
7297
|
function resolveOrderField(field) {
|
|
7278
|
-
if (field === "startedAt" || field === "endedAt" || field
|
|
7298
|
+
if (field === "startedAt" || field === "endedAt" || NUMERIC_ORDER_FIELDS.has(field)) return field;
|
|
7279
7299
|
throw new Error(`Unsupported trusted trace-query field: ${field}`);
|
|
7280
7300
|
}
|
|
7281
7301
|
function isMetadataField(field) {
|
|
@@ -7465,6 +7485,7 @@ function compileClickHouseTraceScope(selection, relationCollections, parameters,
|
|
|
7465
7485
|
endedAt,
|
|
7466
7486
|
${durationMsSql("startedAt", "endedAt")} AS durationMs,
|
|
7467
7487
|
timeToFirstChunkMs,
|
|
7488
|
+
timeToFirstTokenMs,
|
|
7468
7489
|
if(isNotNull(error), 'error', 'success') AS status,
|
|
7469
7490
|
error,
|
|
7470
7491
|
entityType,
|
|
@@ -7580,7 +7601,7 @@ function traceOrder(plan) {
|
|
|
7580
7601
|
function keysetCursorCondition(plan, order, parameters) {
|
|
7581
7602
|
if (plan.paginationMode !== "keyset" || !plan.cursor) return "";
|
|
7582
7603
|
if (plan.cursor.sortValue === null) return `(isNull(sortValue) AND traceId > ${parameters.add(plan.cursor.traceId, "String")})`;
|
|
7583
|
-
const numeric = order.field
|
|
7604
|
+
const numeric = NUMERIC_ORDER_FIELDS.has(order.field);
|
|
7584
7605
|
const comparison = order.direction === "ASC" ? ">" : "<";
|
|
7585
7606
|
const sortValue = parameters.add(plan.cursor.sortValue, numeric ? "Float64" : "DateTime64(3, 'UTC')");
|
|
7586
7607
|
return `(sortValue ${comparison} ${sortValue} OR (sortValue = ${sortValue} AND traceId > ${parameters.add(plan.cursor.traceId, "String")})${numeric ? " OR isNull(sortValue)" : ""})`;
|
|
@@ -7594,7 +7615,7 @@ function compileClickHouseTraceQueryKeys(plan) {
|
|
|
7594
7615
|
if (plan.paginationMode === "delta") throw new Error("Delta trace queries have no keys statement");
|
|
7595
7616
|
const parameters = new ParameterBuilder();
|
|
7596
7617
|
const order = traceOrder(plan);
|
|
7597
|
-
const ctes = compileClickHouseTraceCandidates(plan, "r.traceId AS traceId, r.dedupeKey AS dedupeKey, r.startedAt AS startedAt, r.endedAt AS endedAt, r.timeToFirstChunkMs AS timeToFirstChunkMs", parameters, QUERY_TRACES_SCOPE);
|
|
7618
|
+
const ctes = compileClickHouseTraceCandidates(plan, "r.traceId AS traceId, r.dedupeKey AS dedupeKey, r.startedAt AS startedAt, r.endedAt AS endedAt, r.timeToFirstChunkMs AS timeToFirstChunkMs, r.timeToFirstTokenMs AS timeToFirstTokenMs", parameters, QUERY_TRACES_SCOPE);
|
|
7598
7619
|
const cursor = keysetCursorCondition(plan, order, parameters);
|
|
7599
7620
|
const limit = plan.paginationMode === "page" ? `LIMIT ${parameters.add(plan.perPage, "UInt64")} OFFSET ${parameters.add(plan.page * plan.perPage, "UInt64")}` : `LIMIT ${parameters.add(plan.limit + 1, "UInt64")}`;
|
|
7600
7621
|
return {
|
|
@@ -7995,7 +8016,8 @@ async function queryTraces(client, plan, timeoutMs, strategy = null) {
|
|
|
7995
8016
|
entityType: row.entityType == null ? null : String(row.entityType),
|
|
7996
8017
|
environment: row.environment == null ? null : String(row.environment),
|
|
7997
8018
|
status: row.status,
|
|
7998
|
-
...timeToFirstChunkSupported && { timeToFirstChunkMs: row.timeToFirstChunkMs == null ? null : Number(row.timeToFirstChunkMs) }
|
|
8019
|
+
...timeToFirstChunkSupported && { timeToFirstChunkMs: row.timeToFirstChunkMs == null ? null : Number(row.timeToFirstChunkMs) },
|
|
8020
|
+
...timeToFirstTokenSupported && { timeToFirstTokenMs: row.timeToFirstTokenMs == null ? null : Number(row.timeToFirstTokenMs) }
|
|
7999
8021
|
});
|
|
8000
8022
|
if (plan.paginationMode === "delta") {
|
|
8001
8023
|
const rows = await run(compileClickHouseTraceQuery(plan, deltaHead));
|
|
@@ -8018,7 +8040,7 @@ async function queryTraces(client, plan, timeoutMs, strategy = null) {
|
|
|
8018
8040
|
});
|
|
8019
8041
|
}
|
|
8020
8042
|
const keys = await run(compileClickHouseTraceQueryKeys(plan));
|
|
8021
|
-
const sortValue = (value) => plan.orderBy.field
|
|
8043
|
+
const sortValue = (value) => !NUMERIC_ORDER_FIELDS.has(plan.orderBy.field) ? asIsoTimestamp(value) : value == null ? null : Number(value);
|
|
8022
8044
|
let total = Number(keys[0]?.__total ?? 0);
|
|
8023
8045
|
if (plan.paginationMode === "page" && keys.length === 0 && plan.page > 0) {
|
|
8024
8046
|
const [stats] = await run(compileClickHouseTraceQueryTotal(plan));
|
|
@@ -8121,6 +8143,7 @@ const displayFields = [
|
|
|
8121
8143
|
"provider",
|
|
8122
8144
|
"durationMs",
|
|
8123
8145
|
"timeToFirstChunkMs",
|
|
8146
|
+
"timeToFirstTokenMs",
|
|
8124
8147
|
"status"
|
|
8125
8148
|
];
|
|
8126
8149
|
var Parameters = class {
|
|
@@ -8149,7 +8172,7 @@ function afterCursor$1(plan, parameters) {
|
|
|
8149
8172
|
const equal = [];
|
|
8150
8173
|
if (cursor.sortValue === null) equal.push(`isNull(${field})`);
|
|
8151
8174
|
else {
|
|
8152
|
-
const numeric = plan.orderBy.field === "timeToFirstChunkMs";
|
|
8175
|
+
const numeric = plan.orderBy.field === "timeToFirstChunkMs" || plan.orderBy.field === "timeToFirstTokenMs";
|
|
8153
8176
|
const value = parameters.add(cursor.sortValue, numeric ? "Float64" : "DateTime64(3, 'UTC')");
|
|
8154
8177
|
terms.push(`${field} ${plan.orderBy.direction === "asc" ? ">" : "<"} ${value}`);
|
|
8155
8178
|
if (numeric) terms.push(`isNull(${field})`);
|
|
@@ -8245,6 +8268,7 @@ const TRACE_BRANCHES_SPAN_FIELD_COLUMNS = {
|
|
|
8245
8268
|
"startedAt",
|
|
8246
8269
|
"endedAt",
|
|
8247
8270
|
"timeToFirstChunkMs",
|
|
8271
|
+
"timeToFirstTokenMs",
|
|
8248
8272
|
"threadId",
|
|
8249
8273
|
"runId",
|
|
8250
8274
|
"sessionId",
|
|
@@ -8405,12 +8429,13 @@ async function querySpans(client, plan, timeoutMs) {
|
|
|
8405
8429
|
const hydrated = page.flatMap((identity) => {
|
|
8406
8430
|
const row = byIdentity.get(_mastra_core_storage.spanQueryIdentityKey(identity));
|
|
8407
8431
|
if (!row) return [];
|
|
8408
|
-
const { inputPreview: _input, outputPreview: _output, errorPreview: _error, timeToFirstChunkMs, ...metadata } = row;
|
|
8432
|
+
const { inputPreview: _input, outputPreview: _output, errorPreview: _error, timeToFirstChunkMs, timeToFirstTokenMs, ...metadata } = row;
|
|
8409
8433
|
return [{
|
|
8410
8434
|
...metadata,
|
|
8411
8435
|
...identity,
|
|
8412
8436
|
durationMs: Number(row.durationMs),
|
|
8413
|
-
...timeToFirstChunkSupported && { timeToFirstChunkMs: timeToFirstChunkMs == null ? null : Number(timeToFirstChunkMs) }
|
|
8437
|
+
...timeToFirstChunkSupported && { timeToFirstChunkMs: timeToFirstChunkMs == null ? null : Number(timeToFirstChunkMs) },
|
|
8438
|
+
...timeToFirstTokenSupported && { timeToFirstTokenMs: timeToFirstTokenMs == null ? null : Number(timeToFirstTokenMs) }
|
|
8414
8439
|
}];
|
|
8415
8440
|
});
|
|
8416
8441
|
let metrics = [];
|
|
@@ -8533,7 +8558,11 @@ function compileClickHouseThreadRowsQuery(plan, strategy = "full") {
|
|
|
8533
8558
|
const after = afterCursor(plan, parameters);
|
|
8534
8559
|
const qualify = plan.timeRange.mode === "traces" ? "s.inWindow > 0" : `s.${plan.timeRange.field} >= ${from} AND s.${plan.timeRange.field} < ${to}`;
|
|
8535
8560
|
const filtered = predicateFields(plan.where);
|
|
8536
|
-
const firstContext = [
|
|
8561
|
+
const firstContext = [
|
|
8562
|
+
...contextFields,
|
|
8563
|
+
"timeToFirstChunkMs",
|
|
8564
|
+
"timeToFirstTokenMs"
|
|
8565
|
+
].filter((field) => field === "resourceId" || filtered.has(field));
|
|
8537
8566
|
const firstFields = [
|
|
8538
8567
|
"startedAt",
|
|
8539
8568
|
"traceId",
|
|
@@ -8557,7 +8586,7 @@ function compileClickHouseThreadRowsQuery(plan, strategy = "full") {
|
|
|
8557
8586
|
...firstContext,
|
|
8558
8587
|
...filtered.has("status") ? ["status"] : []
|
|
8559
8588
|
];
|
|
8560
|
-
const rootExpression = (field) => field === "timeToFirstChunkMs" ?
|
|
8589
|
+
const rootExpression = (field) => field === "timeToFirstChunkMs" || field === "timeToFirstTokenMs" ? `if(spanType = 'agent_run', ${field}, NULL)` : field === "status" ? "if(isNull(error), 'success', 'error')" : field;
|
|
8561
8590
|
const sortedRoots = `roots AS (
|
|
8562
8591
|
SELECT organizationId, traceId, ${rootDataFields.map((field) => `${rootExpression(field)} AS ${field}`).join(", ")}
|
|
8563
8592
|
FROM ${TABLE_TRACE_ROOTS} ${scope.length || strategy === "candidates" ? `WHERE ${[...scope, ...strategy === "candidates" ? [candidateTracesFilter] : []].join(" AND ")}` : ""}
|
|
@@ -8661,6 +8690,7 @@ async function queryThreadRows(client, plan, timeoutMs, strategy = "auto") {
|
|
|
8661
8690
|
for (const batch of batches([...roots.values()])) stored.push(...await run({
|
|
8662
8691
|
query: `SELECT organizationId, traceId, spanId, startedAt, endedAt,
|
|
8663
8692
|
${contextFields.join(", ")}, if(spanType = 'agent_run', timeToFirstChunkMs, NULL) AS timeToFirstChunkMs,
|
|
8693
|
+
if(spanType = 'agent_run', timeToFirstTokenMs, NULL) AS timeToFirstTokenMs,
|
|
8664
8694
|
if(isNull(error), 'success', 'error') AS status, ${PREVIEW_COLUMNS.join(", ")}
|
|
8665
8695
|
FROM ${TABLE_TRACE_ROOTS} WHERE ${rootWhere}
|
|
8666
8696
|
ORDER BY ${ROOT_VERSION_ORDER} LIMIT 1 BY organizationId, traceId, spanId`,
|
|
@@ -8694,6 +8724,7 @@ async function queryThreadRows(client, plan, timeoutMs, strategy = "auto") {
|
|
|
8694
8724
|
endedAt: iso(row.endedAt),
|
|
8695
8725
|
traceCount: Number(row.traceCount),
|
|
8696
8726
|
timeToFirstChunkMs: first.timeToFirstChunkMs,
|
|
8727
|
+
...timeToFirstTokenSupported && { timeToFirstTokenMs: first.timeToFirstTokenMs },
|
|
8697
8728
|
inputPreview: resolveStoredPreviews(first).inputPreview,
|
|
8698
8729
|
outputPreview: resolveStoredPreviews(last).outputPreview,
|
|
8699
8730
|
errorPreview: resolveStoredPreviews(last).errorPreview
|
|
@@ -10350,7 +10381,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
|
|
|
10350
10381
|
"trace-query-tenant-scope",
|
|
10351
10382
|
"feedback",
|
|
10352
10383
|
"trace-query-context-ids",
|
|
10353
|
-
...
|
|
10384
|
+
...timingFeatures,
|
|
10354
10385
|
"trace-query-root-span-fields",
|
|
10355
10386
|
"trace-query-root-entity-id",
|
|
10356
10387
|
"trace-aggregate",
|
|
@@ -10375,7 +10406,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
|
|
|
10375
10406
|
"trace-query-tenant-scope",
|
|
10376
10407
|
"feedback",
|
|
10377
10408
|
"trace-query-context-ids",
|
|
10378
|
-
...
|
|
10409
|
+
...timingFeatures,
|
|
10379
10410
|
"trace-query-root-span-fields",
|
|
10380
10411
|
"trace-query-root-entity-id",
|
|
10381
10412
|
"trace-aggregate",
|