@mastra/duckdb 1.15.0-alpha.2 → 1.15.0-alpha.3
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/{features-vjVgmb36.js → features-Clv6RO_w.js} +6 -2
- package/dist/{features-vjVgmb36.js.map → features-Clv6RO_w.js.map} +1 -1
- package/dist/{features-BAGbFa2n.cjs → features-DxaUwIC2.cjs} +23 -1
- package/dist/{features-BAGbFa2n.cjs.map → features-DxaUwIC2.cjs.map} +1 -1
- package/dist/index.cjs +10 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/{observability-HUYFWVy-.js → observability-C1o-hqrj.js} +321 -47
- package/dist/observability-C1o-hqrj.js.map +1 -0
- package/dist/{observability-DJs6G-BH.cjs → observability-D70dyGYt.cjs} +321 -47
- package/dist/observability-D70dyGYt.cjs.map +1 -0
- package/dist/storage/domains/observability/index.d.ts +4 -1
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/preview-compat.d.ts +1 -0
- package/dist/storage/domains/observability/preview-compat.d.ts.map +1 -1
- package/dist/storage/domains/observability/span-query.d.ts +1 -0
- package/dist/storage/domains/observability/span-query.d.ts.map +1 -1
- package/dist/storage/domains/observability/thread-query.d.ts +49 -0
- package/dist/storage/domains/observability/thread-query.d.ts.map +1 -0
- package/dist/storage/domains/observability/trace-aggregate.d.ts.map +1 -1
- package/dist/storage/domains/observability/trace-query.d.ts +1 -0
- package/dist/storage/domains/observability/trace-query.d.ts.map +1 -1
- package/dist/storage/features.d.ts +4 -0
- package/dist/storage/features.d.ts.map +1 -1
- package/dist/storage/index.d.ts +4 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +4 -5
- package/dist/observability-DJs6G-BH.cjs.map +0 -1
- package/dist/observability-HUYFWVy-.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_features = require("./features-
|
|
1
|
+
const require_features = require("./features-DxaUwIC2.cjs");
|
|
2
2
|
let _mastra_core_error = require("@mastra/core/error");
|
|
3
3
|
let _mastra_core_storage = require("@mastra/core/storage");
|
|
4
4
|
_mastra_core_storage = require_features.__toESM(_mastra_core_storage, 1);
|
|
@@ -2876,6 +2876,10 @@ const TRACE_FIELDS = {
|
|
|
2876
2876
|
sql: durationMsSql("r.startedAt", "r.endedAt"),
|
|
2877
2877
|
parameterType: "scalar"
|
|
2878
2878
|
},
|
|
2879
|
+
timeToFirstChunkMs: {
|
|
2880
|
+
sql: "r.timeToFirstChunkMs",
|
|
2881
|
+
parameterType: "scalar"
|
|
2882
|
+
},
|
|
2879
2883
|
entityName: {
|
|
2880
2884
|
sql: "r.entityName",
|
|
2881
2885
|
parameterType: "scalar"
|
|
@@ -2884,6 +2888,14 @@ const TRACE_FIELDS = {
|
|
|
2884
2888
|
sql: "r.entityType",
|
|
2885
2889
|
parameterType: "scalar"
|
|
2886
2890
|
},
|
|
2891
|
+
name: {
|
|
2892
|
+
sql: "r.name",
|
|
2893
|
+
parameterType: "scalar"
|
|
2894
|
+
},
|
|
2895
|
+
spanType: {
|
|
2896
|
+
sql: "r.spanType",
|
|
2897
|
+
parameterType: "scalar"
|
|
2898
|
+
},
|
|
2887
2899
|
environment: {
|
|
2888
2900
|
sql: "r.environment",
|
|
2889
2901
|
parameterType: "scalar"
|
|
@@ -2926,6 +2938,10 @@ const SPAN_FIELDS = {
|
|
|
2926
2938
|
sql: "s.durationMs",
|
|
2927
2939
|
parameterType: "scalar"
|
|
2928
2940
|
},
|
|
2941
|
+
timeToFirstChunkMs: {
|
|
2942
|
+
sql: "s.timeToFirstChunkMs",
|
|
2943
|
+
parameterType: "scalar"
|
|
2944
|
+
},
|
|
2929
2945
|
status: {
|
|
2930
2946
|
sql: "s.status",
|
|
2931
2947
|
parameterType: "scalar"
|
|
@@ -3135,6 +3151,7 @@ const TRACE_SELECT = `
|
|
|
3135
3151
|
r.resourceId AS resourceId,
|
|
3136
3152
|
r.startedAt AS startedAt,
|
|
3137
3153
|
r.endedAt AS endedAt,
|
|
3154
|
+
r.timeToFirstChunkMs AS timeToFirstChunkMs,
|
|
3138
3155
|
r.entityName AS entityName,
|
|
3139
3156
|
r.entityType AS entityType,
|
|
3140
3157
|
r.environment AS environment,
|
|
@@ -3370,8 +3387,11 @@ const ROOT_PUSHDOWN_FIELDS = /* @__PURE__ */ new Set([
|
|
|
3370
3387
|
"userId",
|
|
3371
3388
|
"organizationId",
|
|
3372
3389
|
"endedAt",
|
|
3390
|
+
"timeToFirstChunkMs",
|
|
3373
3391
|
"entityName",
|
|
3374
3392
|
"entityType",
|
|
3393
|
+
"name",
|
|
3394
|
+
"spanType",
|
|
3375
3395
|
"environment"
|
|
3376
3396
|
]);
|
|
3377
3397
|
function isRootPushdownPredicate(predicate) {
|
|
@@ -3497,6 +3517,7 @@ function compileDuckDBTraceScope(relatedCollections, scope, timeRange, rootPredi
|
|
|
3497
3517
|
startedAt,
|
|
3498
3518
|
endedAt,
|
|
3499
3519
|
${durationMsSql("startedAt", "endedAt")} AS durationMs,
|
|
3520
|
+
timeToFirstChunkMs,
|
|
3500
3521
|
CASE WHEN error IS NOT NULL THEN 'error' ELSE 'success' END AS status,
|
|
3501
3522
|
error,
|
|
3502
3523
|
entityType,
|
|
@@ -3812,6 +3833,29 @@ async function fillMissingTracePreviews(db, rows) {
|
|
|
3812
3833
|
for (const [preview, column] of TRACE_PREVIEW_PAYLOADS) if (needsPreview(row[preview])) row[preview] = previewFromPayload(payload?.[column] ?? null);
|
|
3813
3834
|
}
|
|
3814
3835
|
}
|
|
3836
|
+
function traceFromRow(row) {
|
|
3837
|
+
return {
|
|
3838
|
+
traceId: String(row.traceId),
|
|
3839
|
+
rootSpanId: String(row.rootSpanId),
|
|
3840
|
+
name: row.name,
|
|
3841
|
+
entityId: row.entityId ?? null,
|
|
3842
|
+
parentSpanId: row.parentSpanId ?? null,
|
|
3843
|
+
createdAt: asIsoTimestamp(row.startedAt),
|
|
3844
|
+
metadata: parseJson(row.metadata) ?? null,
|
|
3845
|
+
inputPreview: apiPreview(row.inputPreview),
|
|
3846
|
+
outputPreview: apiPreview(row.outputPreview),
|
|
3847
|
+
errorPreview: apiPreview(row.errorPreview),
|
|
3848
|
+
threadId: row.threadId == null ? null : String(row.threadId),
|
|
3849
|
+
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
3850
|
+
startedAt: asIsoTimestamp(row.startedAt),
|
|
3851
|
+
endedAt: asIsoTimestamp(row.endedAt),
|
|
3852
|
+
entityName: row.entityName == null ? null : String(row.entityName),
|
|
3853
|
+
entityType: row.entityType == null ? null : String(row.entityType),
|
|
3854
|
+
environment: row.environment == null ? null : String(row.environment),
|
|
3855
|
+
status: row.status,
|
|
3856
|
+
...require_features.timeToFirstChunkSupported && { timeToFirstChunkMs: row.timeToFirstChunkMs == null ? null : Number(row.timeToFirstChunkMs) }
|
|
3857
|
+
};
|
|
3858
|
+
}
|
|
3815
3859
|
async function queryTraces(db, plan) {
|
|
3816
3860
|
if (plan.paginationMode === "delta") assertDeltaPollingEnabled();
|
|
3817
3861
|
if (plan.paginationMode === "page") {
|
|
@@ -3819,26 +3863,7 @@ async function queryTraces(db, plan) {
|
|
|
3819
3863
|
const rows = await db.query(query.sql, query.values);
|
|
3820
3864
|
const total = Number(rows[0]?.total ?? 0);
|
|
3821
3865
|
await fillMissingTracePreviews(db, rows);
|
|
3822
|
-
const traces = rows.filter((row) => row.traceId != null).map(
|
|
3823
|
-
traceId: String(row.traceId),
|
|
3824
|
-
rootSpanId: String(row.rootSpanId),
|
|
3825
|
-
name: row.name,
|
|
3826
|
-
entityId: row.entityId ?? null,
|
|
3827
|
-
parentSpanId: row.parentSpanId ?? null,
|
|
3828
|
-
createdAt: asIsoTimestamp(row.startedAt),
|
|
3829
|
-
metadata: parseJson(row.metadata) ?? null,
|
|
3830
|
-
inputPreview: apiPreview(row.inputPreview),
|
|
3831
|
-
outputPreview: apiPreview(row.outputPreview),
|
|
3832
|
-
errorPreview: apiPreview(row.errorPreview),
|
|
3833
|
-
threadId: row.threadId == null ? null : String(row.threadId),
|
|
3834
|
-
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
3835
|
-
startedAt: asIsoTimestamp(row.startedAt),
|
|
3836
|
-
endedAt: asIsoTimestamp(row.endedAt),
|
|
3837
|
-
entityName: row.entityName == null ? null : String(row.entityName),
|
|
3838
|
-
entityType: row.entityType == null ? null : String(row.entityType),
|
|
3839
|
-
environment: row.environment == null ? null : String(row.environment),
|
|
3840
|
-
status: row.status
|
|
3841
|
-
}));
|
|
3866
|
+
const traces = rows.filter((row) => row.traceId != null).map(traceFromRow);
|
|
3842
3867
|
return _mastra_core_storage.traceQueryResponseSchema.parse({
|
|
3843
3868
|
traces,
|
|
3844
3869
|
...deltaPollingFeatureEnabled() && typeof _mastra_core_storage.encodeTraceQueryDeltaCursor === "function" ? { deltaCursor: _mastra_core_storage.encodeTraceQueryDeltaCursor(plan, "duckdb", String(rows[0]?.streamHead ?? 0)) } : {},
|
|
@@ -3866,26 +3891,7 @@ async function queryTraces(db, plan) {
|
|
|
3866
3891
|
});
|
|
3867
3892
|
}
|
|
3868
3893
|
await fillMissingTracePreviews(db, visibleRows);
|
|
3869
|
-
const traces = visibleRows.map(
|
|
3870
|
-
traceId: String(row.traceId),
|
|
3871
|
-
rootSpanId: String(row.rootSpanId),
|
|
3872
|
-
name: row.name,
|
|
3873
|
-
entityId: row.entityId ?? null,
|
|
3874
|
-
parentSpanId: row.parentSpanId ?? null,
|
|
3875
|
-
createdAt: asIsoTimestamp(row.startedAt),
|
|
3876
|
-
metadata: parseJson(row.metadata) ?? null,
|
|
3877
|
-
inputPreview: apiPreview(row.inputPreview),
|
|
3878
|
-
outputPreview: apiPreview(row.outputPreview),
|
|
3879
|
-
errorPreview: apiPreview(row.errorPreview),
|
|
3880
|
-
threadId: row.threadId == null ? null : String(row.threadId),
|
|
3881
|
-
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
3882
|
-
startedAt: asIsoTimestamp(row.startedAt),
|
|
3883
|
-
endedAt: asIsoTimestamp(row.endedAt),
|
|
3884
|
-
entityName: row.entityName == null ? null : String(row.entityName),
|
|
3885
|
-
entityType: row.entityType == null ? null : String(row.entityType),
|
|
3886
|
-
environment: row.environment == null ? null : String(row.environment),
|
|
3887
|
-
status: row.status
|
|
3888
|
-
}));
|
|
3894
|
+
const traces = visibleRows.map(traceFromRow);
|
|
3889
3895
|
if (plan.paginationMode === "delta") {
|
|
3890
3896
|
const previous = _mastra_core_storage.getTraceQueryDeltaWatermark(plan, "duckdb") ?? "0";
|
|
3891
3897
|
const head = String(rows[0]?.streamHead ?? 0);
|
|
@@ -3926,6 +3932,12 @@ async function queryThreads(db, plan) {
|
|
|
3926
3932
|
function compileSpanQueryPredicate(predicate) {
|
|
3927
3933
|
return compileScalarPredicate(predicate, SPAN_QUERY_FIELDS);
|
|
3928
3934
|
}
|
|
3935
|
+
function compileThreadQueryPredicate(predicate) {
|
|
3936
|
+
return compileScalarPredicate(predicate, Object.fromEntries(Object.entries(_mastra_core_storage.THREAD_QUERY_FIELD_REGISTRY).map(([field, rule]) => [field, {
|
|
3937
|
+
sql: `s.${field}`,
|
|
3938
|
+
parameterType: rule.valueKind === "timestamp" ? "timestamp" : "scalar"
|
|
3939
|
+
}])));
|
|
3940
|
+
}
|
|
3929
3941
|
//#endregion
|
|
3930
3942
|
//#region src/storage/domains/observability/span-query.ts
|
|
3931
3943
|
const identityFields = [
|
|
@@ -3969,7 +3981,8 @@ const fields = [
|
|
|
3969
3981
|
"serviceName",
|
|
3970
3982
|
"experimentId",
|
|
3971
3983
|
"environment",
|
|
3972
|
-
"executionSource"
|
|
3984
|
+
"executionSource",
|
|
3985
|
+
"timeToFirstChunkMs"
|
|
3973
3986
|
];
|
|
3974
3987
|
function keys(rows, values, alias = "") {
|
|
3975
3988
|
return rows.map((row) => `(${identityFields.map((field) => {
|
|
@@ -4073,10 +4086,11 @@ async function querySpans(db, plan) {
|
|
|
4073
4086
|
};
|
|
4074
4087
|
const compiled = compileDuckDBSpanQuery(plan);
|
|
4075
4088
|
const rows = await query(compiled.sql, compiled.values);
|
|
4076
|
-
const selected = rows.map(({ cursorId: _cursorId, startedAt, endedAt, ...row }) => ({
|
|
4089
|
+
const selected = rows.map(({ cursorId: _cursorId, startedAt, endedAt, timeToFirstChunkMs, ...row }) => ({
|
|
4077
4090
|
...row,
|
|
4078
4091
|
startedAt: startedAt.toISOString(),
|
|
4079
|
-
endedAt: endedAt.toISOString()
|
|
4092
|
+
endedAt: endedAt.toISOString(),
|
|
4093
|
+
...require_features.timeToFirstChunkSupported && { timeToFirstChunkMs: timeToFirstChunkMs == null ? null : Number(timeToFirstChunkMs) }
|
|
4080
4094
|
}));
|
|
4081
4095
|
const page = rows.slice(0, plan.limit);
|
|
4082
4096
|
if (!page.length) return buildSpanQueryResponse(plan, [], []);
|
|
@@ -4127,11 +4141,264 @@ async function querySpans(db, plan) {
|
|
|
4127
4141
|
return buildSpanQueryResponse(plan, hydrated, payloads, metrics);
|
|
4128
4142
|
}
|
|
4129
4143
|
//#endregion
|
|
4144
|
+
//#region src/storage/domains/observability/thread-query.ts
|
|
4145
|
+
const contextFields = [
|
|
4146
|
+
"resourceId",
|
|
4147
|
+
"userId",
|
|
4148
|
+
"entityType",
|
|
4149
|
+
"entityId",
|
|
4150
|
+
"entityName",
|
|
4151
|
+
"entityVersionId",
|
|
4152
|
+
"runId",
|
|
4153
|
+
"sessionId",
|
|
4154
|
+
"requestId",
|
|
4155
|
+
"serviceName",
|
|
4156
|
+
"experimentId",
|
|
4157
|
+
"environment",
|
|
4158
|
+
"executionSource"
|
|
4159
|
+
];
|
|
4160
|
+
function predicateFields(predicate, fields = /* @__PURE__ */ new Set()) {
|
|
4161
|
+
if (!predicate) return fields;
|
|
4162
|
+
if (predicate.type === "boolean") for (const arg of predicate.args) predicateFields(arg, fields);
|
|
4163
|
+
else if (predicate.type === "not") predicateFields(predicate.arg, fields);
|
|
4164
|
+
else fields.add(predicate.field);
|
|
4165
|
+
return fields;
|
|
4166
|
+
}
|
|
4167
|
+
function canUseThreadCandidates(probe) {
|
|
4168
|
+
return Number(probe.threadCount) <= 16384 && Number(probe.traceCount) <= 1e5 && Number(probe.threadBytes) + Number(probe.traceBytes) <= 4 * 1024 * 1024;
|
|
4169
|
+
}
|
|
4170
|
+
function compileDuckDBThreadRowsQuery(plan, strategy = "full") {
|
|
4171
|
+
const values = [];
|
|
4172
|
+
const scope = [];
|
|
4173
|
+
if (plan.scope) {
|
|
4174
|
+
values.push(plan.scope.organizationId);
|
|
4175
|
+
scope.push("organizationId = ?");
|
|
4176
|
+
if (plan.scope.resourceId !== void 0) {
|
|
4177
|
+
values.push(plan.scope.resourceId);
|
|
4178
|
+
scope.push("resourceId = ?");
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4181
|
+
const identity = (field) => `(organizationId IS NULL, COALESCE(organizationId, ''), ${field})`;
|
|
4182
|
+
const threadFilter = `${identity("threadId")} IN (SELECT ${identity("threadId")} FROM candidate_threads)`;
|
|
4183
|
+
const endWindow = plan.timeRange.mode === "threads" && plan.timeRange.field === "endedAt";
|
|
4184
|
+
const scopedEvents = `scoped_events AS NOT MATERIALIZED (
|
|
4185
|
+
SELECT * FROM span_events WHERE parentSpanId IS NULL ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
|
|
4186
|
+
)`;
|
|
4187
|
+
const candidates = `window_traces AS MATERIALIZED (
|
|
4188
|
+
SELECT DISTINCT organizationId, traceId FROM scoped_events
|
|
4189
|
+
WHERE ${endWindow ? "endedAt" : "timestamp"} >= CAST(? AS TIMESTAMP) AND ${endWindow ? "endedAt" : "timestamp"} < CAST(? AS TIMESTAMP)
|
|
4190
|
+
${endWindow ? "" : "AND eventType = 'start'"}
|
|
4191
|
+
), candidate_threads AS MATERIALIZED (
|
|
4192
|
+
SELECT DISTINCT organizationId, threadId FROM scoped_events
|
|
4193
|
+
WHERE threadId IS NOT NULL AND ${identity("traceId")} IN (SELECT ${identity("traceId")} FROM window_traces)
|
|
4194
|
+
${strategy === "probe" ? "LIMIT 16385" : ""}
|
|
4195
|
+
), candidate_traces AS MATERIALIZED (
|
|
4196
|
+
SELECT DISTINCT organizationId, traceId FROM scoped_events WHERE ${threadFilter}
|
|
4197
|
+
${strategy === "probe" ? "LIMIT 100001" : ""}
|
|
4198
|
+
)`;
|
|
4199
|
+
if (strategy !== "full") values.push(plan.timeRange.from, plan.timeRange.to);
|
|
4200
|
+
if (strategy === "probe") return {
|
|
4201
|
+
sql: `WITH ${scopedEvents}, ${candidates}
|
|
4202
|
+
SELECT (SELECT count(*) FROM candidate_threads) AS threadCount,
|
|
4203
|
+
(SELECT COALESCE(sum(octet_length(encode(COALESCE(organizationId, ''))) + octet_length(encode(threadId))), 0) FROM candidate_threads) AS threadBytes,
|
|
4204
|
+
count(*) AS traceCount, COALESCE(sum(octet_length(encode(COALESCE(organizationId, ''))) + octet_length(encode(traceId))), 0) AS traceBytes
|
|
4205
|
+
FROM candidate_traces`,
|
|
4206
|
+
values
|
|
4207
|
+
};
|
|
4208
|
+
values.push(plan.timeRange.from, plan.timeRange.to);
|
|
4209
|
+
const qualify = plan.timeRange.mode === "traces" ? "s.inWindow" : `s.${plan.timeRange.field} >= CAST(? AS TIMESTAMP) AND s.${plan.timeRange.field} < CAST(? AS TIMESTAMP)`;
|
|
4210
|
+
if (plan.timeRange.mode === "threads") values.push(plan.timeRange.from, plan.timeRange.to);
|
|
4211
|
+
const predicate = plan.where ? compileThreadQueryPredicate(plan.where) : {
|
|
4212
|
+
sql: "TRUE",
|
|
4213
|
+
values: []
|
|
4214
|
+
};
|
|
4215
|
+
values.push(...predicate.values);
|
|
4216
|
+
let after = "TRUE";
|
|
4217
|
+
if (plan.cursor) {
|
|
4218
|
+
const cursor = plan.cursor;
|
|
4219
|
+
const terms = [`s.${plan.orderBy.field} ${plan.orderBy.direction === "asc" ? ">" : "<"} CAST(? AS TIMESTAMP)`];
|
|
4220
|
+
values.push(cursor.sortValue);
|
|
4221
|
+
const ids = ["organizationId", "threadId"];
|
|
4222
|
+
for (let i = 0; i < ids.length; i++) {
|
|
4223
|
+
const field = ids[i];
|
|
4224
|
+
if (cursor[field] === null) continue;
|
|
4225
|
+
const equal = [`s.${plan.orderBy.field} = CAST(? AS TIMESTAMP)`];
|
|
4226
|
+
values.push(cursor.sortValue);
|
|
4227
|
+
for (const prior of ids.slice(0, i)) {
|
|
4228
|
+
equal.push(`s.${prior} IS NOT DISTINCT FROM ?`);
|
|
4229
|
+
values.push(cursor[prior]);
|
|
4230
|
+
}
|
|
4231
|
+
values.push(cursor[field]);
|
|
4232
|
+
terms.push(`(${equal.join(" AND ")} AND (s.${field} > ? OR s.${field} IS NULL))`);
|
|
4233
|
+
}
|
|
4234
|
+
after = `(${terms.join(" OR ")})`;
|
|
4235
|
+
}
|
|
4236
|
+
values.push(plan.limit + 1);
|
|
4237
|
+
const filtered = predicateFields(plan.where);
|
|
4238
|
+
const firstContext = [...contextFields, "timeToFirstChunkMs"].filter((field) => field === "resourceId" || filtered.has(field));
|
|
4239
|
+
const contextExpression = (field) => field === "executionSource" ? "source AS executionSource" : field === "timeToFirstChunkMs" ? "CASE WHEN spanType = 'agent_run' THEN timeToFirstChunkMs END AS timeToFirstChunkMs" : field;
|
|
4240
|
+
const lastFields = [
|
|
4241
|
+
"traceId",
|
|
4242
|
+
"spanId",
|
|
4243
|
+
"cursorId",
|
|
4244
|
+
"resourceId",
|
|
4245
|
+
"endedAt",
|
|
4246
|
+
...filtered.has("status") ? ["status"] : []
|
|
4247
|
+
];
|
|
4248
|
+
return {
|
|
4249
|
+
sql: `WITH ${scopedEvents}, ${strategy === "candidates" ? `${candidates}, ` : ""}root_events AS (
|
|
4250
|
+
SELECT organizationId, threadId, traceId, spanId, cursorId, endedAt,
|
|
4251
|
+
${firstContext.map(contextExpression).join(", ")},
|
|
4252
|
+
min(timestamp) FILTER (WHERE eventType = 'start') OVER (PARTITION BY organizationId, traceId, spanId) AS startedAt
|
|
4253
|
+
${filtered.has("status") ? ", CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status" : ""}
|
|
4254
|
+
FROM scoped_events ${strategy === "candidates" ? `WHERE ${identity("traceId")} IN (SELECT ${identity("traceId")} FROM candidate_traces)` : ""}
|
|
4255
|
+
), current_roots AS (
|
|
4256
|
+
SELECT *, row_number() OVER (PARTITION BY organizationId, traceId ORDER BY startedAt ASC, spanId, cursorId DESC) AS rootRank
|
|
4257
|
+
FROM root_events
|
|
4258
|
+
), ranked AS (
|
|
4259
|
+
SELECT *, row_number() OVER first_order AS rank,
|
|
4260
|
+
max(endedAt) OVER population AS lastActivity, count(*) OVER population AS traceCount,
|
|
4261
|
+
bool_or(startedAt >= CAST(? AS TIMESTAMP) AND startedAt < CAST(? AS TIMESTAMP)) OVER population AS inWindow,
|
|
4262
|
+
${lastFields.map((field) => `first_value(${field}) OVER last_order AS last${field[0].toUpperCase()}${field.slice(1)}`).join(", ")}
|
|
4263
|
+
FROM current_roots WHERE rootRank = 1 AND endedAt IS NOT NULL AND startedAt IS NOT NULL AND threadId IS NOT NULL ${strategy === "candidates" ? `AND ${threadFilter}` : ""}
|
|
4264
|
+
WINDOW population AS (PARTITION BY organizationId, threadId),
|
|
4265
|
+
first_order AS (PARTITION BY organizationId, threadId ORDER BY startedAt, traceId),
|
|
4266
|
+
last_order AS (PARTITION BY organizationId, threadId ORDER BY startedAt DESC, traceId DESC)
|
|
4267
|
+
), rows AS (
|
|
4268
|
+
SELECT organizationId, threadId, traceId AS firstTraceId, spanId AS firstSpanId, cursorId AS firstCursorId,
|
|
4269
|
+
endedAt AS firstEndedAt, startedAt, lastActivity AS endedAt, traceCount, inWindow,
|
|
4270
|
+
${firstContext.join(", ")},
|
|
4271
|
+
${lastFields.map((field) => `last${field[0].toUpperCase()}${field.slice(1)}${field === "status" ? " AS status" : ""}`).join(", ")}
|
|
4272
|
+
FROM ranked WHERE rank = 1
|
|
4273
|
+
) SELECT * FROM rows s WHERE ${qualify} AND (${predicate.sql}) AND ${after}
|
|
4274
|
+
ORDER BY s.${plan.orderBy.field} ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"}, s.organizationId ASC NULLS LAST, s.threadId ASC LIMIT ?`,
|
|
4275
|
+
values
|
|
4276
|
+
};
|
|
4277
|
+
}
|
|
4278
|
+
async function queryThreadRows(db, plan, strategy = "auto") {
|
|
4279
|
+
const deadline = performance.now() + _mastra_core_storage.TRACE_QUERY_DEFAULT_TIMEOUT_MS;
|
|
4280
|
+
const run = async (sql, values) => {
|
|
4281
|
+
const remaining = Math.floor(deadline - performance.now());
|
|
4282
|
+
if (remaining <= 0) throw new _mastra_core_storage.TraceQueryExecutionError();
|
|
4283
|
+
try {
|
|
4284
|
+
return await db.query(sql, values, remaining);
|
|
4285
|
+
} catch (error) {
|
|
4286
|
+
if (error instanceof require_features.DuckDBQueryTimeoutError) throw new _mastra_core_storage.TraceQueryExecutionError();
|
|
4287
|
+
if (error instanceof Error && /out of memory/i.test(error.message)) throw new _mastra_core_storage.TraceQueryResourceLimitError();
|
|
4288
|
+
throw error;
|
|
4289
|
+
}
|
|
4290
|
+
};
|
|
4291
|
+
if (strategy === "auto") {
|
|
4292
|
+
const probeQuery = compileDuckDBThreadRowsQuery(plan, "probe");
|
|
4293
|
+
const [probe] = await run(probeQuery.sql, probeQuery.values);
|
|
4294
|
+
if (Number(probe.threadCount) === 0) return {
|
|
4295
|
+
threads: [],
|
|
4296
|
+
page: { next: null }
|
|
4297
|
+
};
|
|
4298
|
+
strategy = canUseThreadCandidates(probe) ? "candidates" : "full";
|
|
4299
|
+
}
|
|
4300
|
+
const compiled = compileDuckDBThreadRowsQuery(plan, strategy);
|
|
4301
|
+
const selected = await run(compiled.sql, compiled.values);
|
|
4302
|
+
const page = selected.slice(0, plan.limit);
|
|
4303
|
+
if (!page.length) return {
|
|
4304
|
+
threads: [],
|
|
4305
|
+
page: { next: null }
|
|
4306
|
+
};
|
|
4307
|
+
const values = [];
|
|
4308
|
+
const keys = page.flatMap((row) => ["first", "last"].map((which) => {
|
|
4309
|
+
const entries = {
|
|
4310
|
+
organizationId: row.organizationId,
|
|
4311
|
+
resourceId: which === "first" ? row.resourceId : row.lastResourceId,
|
|
4312
|
+
traceId: row[`${which}TraceId`],
|
|
4313
|
+
spanId: row[`${which}SpanId`],
|
|
4314
|
+
cursorId: row[`${which}CursorId`],
|
|
4315
|
+
endedAt: row[`${which}EndedAt`]
|
|
4316
|
+
};
|
|
4317
|
+
return `(${Object.entries(entries).map(([field, value]) => {
|
|
4318
|
+
values.push(value);
|
|
4319
|
+
return `${field} ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} ?`;
|
|
4320
|
+
}).join(" AND ")})`;
|
|
4321
|
+
}));
|
|
4322
|
+
const payloads = await run(`SELECT organizationId, traceId, cursorId, spanType,
|
|
4323
|
+
${contextFields.map((field) => field === "executionSource" ? "source AS executionSource" : field).join(", ")},
|
|
4324
|
+
CASE WHEN spanType = 'agent_run' THEN timeToFirstChunkMs END AS timeToFirstChunkMs,
|
|
4325
|
+
CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
|
|
4326
|
+
${[
|
|
4327
|
+
"input",
|
|
4328
|
+
"output",
|
|
4329
|
+
"error"
|
|
4330
|
+
].map((field) => `${field}Preview, CASE WHEN ${missingPreviewSql(`${field}Preview`)} THEN CAST(${field === "error" ? field : payloadColumnSql(field)} AS VARCHAR) END AS ${field}`).join(", ")}
|
|
4331
|
+
FROM span_events WHERE ${keys.join(" OR ")}`, values);
|
|
4332
|
+
const key = (org, trace, version) => JSON.stringify([
|
|
4333
|
+
org,
|
|
4334
|
+
trace,
|
|
4335
|
+
String(version)
|
|
4336
|
+
]);
|
|
4337
|
+
const byRoot = new Map(payloads.map((row) => [key(row.organizationId, row.traceId, row.cursorId), row]));
|
|
4338
|
+
const agents = page.filter((row) => byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId))?.spanType === "agent_run");
|
|
4339
|
+
const models = /* @__PURE__ */ new Map();
|
|
4340
|
+
if (agents.length) {
|
|
4341
|
+
const modelValues = [];
|
|
4342
|
+
const rows = await run(`WITH generations AS (
|
|
4343
|
+
SELECT organizationId, traceId, spanId, endedAt, cursorId, attributes,
|
|
4344
|
+
min(timestamp) FILTER (WHERE eventType = 'start') OVER (PARTITION BY organizationId, traceId, spanId) AS startedAt
|
|
4345
|
+
FROM span_events WHERE spanType = 'model_generation' AND (${agents.map((row) => `(${Object.entries({
|
|
4346
|
+
organizationId: row.organizationId,
|
|
4347
|
+
resourceId: row.resourceId,
|
|
4348
|
+
traceId: row.firstTraceId,
|
|
4349
|
+
parentSpanId: row.firstSpanId
|
|
4350
|
+
}).map(([field, value]) => {
|
|
4351
|
+
modelValues.push(value);
|
|
4352
|
+
return `${field} ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} ?`;
|
|
4353
|
+
}).join(" AND ")})`).join(" OR ")})
|
|
4354
|
+
) SELECT organizationId, traceId,
|
|
4355
|
+
CASE WHEN json_type(attributes, '$.model') = 'VARCHAR' THEN json_extract_string(attributes, '$.model') END AS model,
|
|
4356
|
+
CASE WHEN json_type(attributes, '$.provider') = 'VARCHAR' THEN json_extract_string(attributes, '$.provider') END AS provider
|
|
4357
|
+
FROM generations WHERE endedAt IS NOT NULL
|
|
4358
|
+
QUALIFY row_number() OVER (PARTITION BY organizationId, traceId ORDER BY startedAt, spanId, cursorId DESC) = 1`, modelValues);
|
|
4359
|
+
for (const row of rows) models.set(JSON.stringify([row.organizationId, row.traceId]), row);
|
|
4360
|
+
}
|
|
4361
|
+
const threads = page.flatMap((row) => {
|
|
4362
|
+
const first = byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId));
|
|
4363
|
+
const last = byRoot.get(key(row.organizationId, row.lastTraceId, row.lastCursorId));
|
|
4364
|
+
if (!first || !last) return [];
|
|
4365
|
+
const model = models.get(JSON.stringify([row.organizationId, row.firstTraceId]));
|
|
4366
|
+
return [_mastra_core_storage.threadQueryRowSchema.parse({
|
|
4367
|
+
organizationId: row.organizationId,
|
|
4368
|
+
threadId: row.threadId,
|
|
4369
|
+
firstTraceId: row.firstTraceId,
|
|
4370
|
+
lastTraceId: row.lastTraceId,
|
|
4371
|
+
...Object.fromEntries(contextFields.map((field) => [field, first[field]])),
|
|
4372
|
+
status: last.status,
|
|
4373
|
+
startedAt: row.startedAt.toISOString(),
|
|
4374
|
+
endedAt: row.endedAt.toISOString(),
|
|
4375
|
+
traceCount: Number(row.traceCount),
|
|
4376
|
+
timeToFirstChunkMs: first.timeToFirstChunkMs,
|
|
4377
|
+
model: model?.model ?? null,
|
|
4378
|
+
provider: model?.provider ?? null,
|
|
4379
|
+
inputPreview: readPreview(first.inputPreview, first.input, true),
|
|
4380
|
+
outputPreview: readPreview(last.outputPreview, last.output, true),
|
|
4381
|
+
errorPreview: readPreview(last.errorPreview, last.error, true)
|
|
4382
|
+
})];
|
|
4383
|
+
});
|
|
4384
|
+
const last = page.at(-1);
|
|
4385
|
+
return {
|
|
4386
|
+
threads,
|
|
4387
|
+
page: { next: selected.length > plan.limit ? _mastra_core_storage.encodeThreadQueryCursor(plan, {
|
|
4388
|
+
organizationId: last.organizationId,
|
|
4389
|
+
threadId: last.threadId,
|
|
4390
|
+
sortValue: last[plan.orderBy.field].toISOString()
|
|
4391
|
+
}) : null }
|
|
4392
|
+
};
|
|
4393
|
+
}
|
|
4394
|
+
//#endregion
|
|
4130
4395
|
//#region src/storage/domains/observability/trace-aggregate.ts
|
|
4131
4396
|
/** Trace-root column expressions (alias `r`) for each groupable dimension; same values `where` sees. */
|
|
4132
4397
|
const DIMENSION_SQL = {
|
|
4133
4398
|
entityType: "r.entityType",
|
|
4134
4399
|
entityName: "r.entityName",
|
|
4400
|
+
name: "r.name",
|
|
4401
|
+
spanType: "r.spanType",
|
|
4135
4402
|
environment: "r.environment",
|
|
4136
4403
|
status: TRACE_STATUS_SQL,
|
|
4137
4404
|
serviceName: "r.serviceName",
|
|
@@ -5900,12 +6167,15 @@ var ObservabilityStorageDuckDB = class ObservabilityStorageDuckDB extends _mastr
|
|
|
5900
6167
|
"trace-query",
|
|
5901
6168
|
"trace-aggregate",
|
|
5902
6169
|
...require_features.spanQueryFeatures,
|
|
6170
|
+
...typeof _mastra_core_storage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
|
|
5903
6171
|
"trace-query-root-duration",
|
|
5904
6172
|
"trace-query-discovery",
|
|
5905
6173
|
"thread-query",
|
|
5906
6174
|
"trace-query-tenant-scope",
|
|
5907
6175
|
"feedback",
|
|
5908
|
-
"trace-query-context-ids"
|
|
6176
|
+
"trace-query-context-ids",
|
|
6177
|
+
...require_features.timeToFirstChunkFeatures,
|
|
6178
|
+
"trace-query-root-span-fields"
|
|
5909
6179
|
];
|
|
5910
6180
|
return [
|
|
5911
6181
|
"metrics",
|
|
@@ -5920,12 +6190,15 @@ var ObservabilityStorageDuckDB = class ObservabilityStorageDuckDB extends _mastr
|
|
|
5920
6190
|
"trace-query",
|
|
5921
6191
|
"trace-aggregate",
|
|
5922
6192
|
...require_features.spanQueryFeatures,
|
|
6193
|
+
...typeof _mastra_core_storage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
|
|
5923
6194
|
"trace-query-root-duration",
|
|
5924
6195
|
"trace-query-discovery",
|
|
5925
6196
|
"thread-query",
|
|
5926
6197
|
"trace-query-tenant-scope",
|
|
5927
6198
|
"feedback",
|
|
5928
|
-
"trace-query-context-ids"
|
|
6199
|
+
"trace-query-context-ids",
|
|
6200
|
+
...require_features.timeToFirstChunkFeatures,
|
|
6201
|
+
"trace-query-root-span-fields"
|
|
5929
6202
|
];
|
|
5930
6203
|
}
|
|
5931
6204
|
async createSpan(args) {
|
|
@@ -5971,6 +6244,7 @@ var ObservabilityStorageDuckDB = class ObservabilityStorageDuckDB extends _mastr
|
|
|
5971
6244
|
return getTraceQueryValues(this.db, plan);
|
|
5972
6245
|
}
|
|
5973
6246
|
async queryThreads(plan) {
|
|
6247
|
+
if (plan.result === "threadRows") return queryThreadRows(this.db, plan);
|
|
5974
6248
|
return queryThreads(this.db, plan);
|
|
5975
6249
|
}
|
|
5976
6250
|
async listTracesLight(args) {
|
|
@@ -6086,4 +6360,4 @@ var ObservabilityStorageDuckDB = class ObservabilityStorageDuckDB extends _mastr
|
|
|
6086
6360
|
//#endregion
|
|
6087
6361
|
exports.ObservabilityStorageDuckDB = ObservabilityStorageDuckDB;
|
|
6088
6362
|
|
|
6089
|
-
//# sourceMappingURL=observability-
|
|
6363
|
+
//# sourceMappingURL=observability-D70dyGYt.cjs.map
|