@mastra/pg 1.32.0-alpha.2 → 1.32.0-alpha.4
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 +303 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +303 -21
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +4 -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 +49 -0
- package/dist/storage/domains/observability/v-next/thread-query.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/trace-aggregate.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts +13 -0
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/dist/storage/domains/skills/index.d.ts.map +1 -1
- package/package.json +10 -11
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -19209,6 +19209,28 @@ async function getScorePercentiles(client, schema, args) {
|
|
|
19209
19209
|
//#endregion
|
|
19210
19210
|
//#region src/storage/domains/observability/v-next/trace-query.ts
|
|
19211
19211
|
const TRACE_STATUS_SQL = `CASE WHEN r."error" IS NOT NULL THEN 'error' ELSE 'success' END`;
|
|
19212
|
+
/** Core versions without the field reject it in strict query results, so it is only returned when core knows it. */
|
|
19213
|
+
const timeToFirstChunkSupported = "timeToFirstChunkMs" in _mastra_core_storage.TRACE_QUERY_FIELD_REGISTRY.trace;
|
|
19214
|
+
/** Core before the sort rejects `orderBy` on the field, so the sort is only declared when core plans it. */
|
|
19215
|
+
const timeToFirstChunkSortSupported = _mastra_core_storage.TRACE_QUERY_ORDER_FIELDS?.includes("timeToFirstChunkMs") === true;
|
|
19216
|
+
const timeToFirstChunkFeatures = [...timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [], ...timeToFirstChunkSortSupported ? ["trace-query-time-to-first-chunk-sort"] : []];
|
|
19217
|
+
/**
|
|
19218
|
+
* Keyset bounds for a cursor's sort value: terms for rows strictly past it in `direction`, and the
|
|
19219
|
+
* condition for rows level with it. Empty values sort last in both directions, so they are past
|
|
19220
|
+
* every value and level only with each other.
|
|
19221
|
+
*/
|
|
19222
|
+
function keysetSortBounds(field, direction, sortValue, values) {
|
|
19223
|
+
if (sortValue === null) return {
|
|
19224
|
+
past: [],
|
|
19225
|
+
level: `${field} IS NULL`
|
|
19226
|
+
};
|
|
19227
|
+
values.push(sortValue);
|
|
19228
|
+
const parameter = `$${values.length}::${typeof sortValue === "number" ? "float8" : "timestamptz"}`;
|
|
19229
|
+
return {
|
|
19230
|
+
past: [`${field} ${direction === "asc" ? ">" : "<"} ${parameter}`, `${field} IS NULL`],
|
|
19231
|
+
level: `${field} = ${parameter}`
|
|
19232
|
+
};
|
|
19233
|
+
}
|
|
19212
19234
|
function durationMsSql(startedAt, endedAt) {
|
|
19213
19235
|
return `EXTRACT(EPOCH FROM (${endedAt} - ${startedAt}))::numeric * 1000`;
|
|
19214
19236
|
}
|
|
@@ -19223,8 +19245,11 @@ const TRACE_FIELDS = {
|
|
|
19223
19245
|
startedAt: "r.\"startedAt\"",
|
|
19224
19246
|
endedAt: "r.\"endedAt\"",
|
|
19225
19247
|
durationMs: durationMsSql("r.\"startedAt\"", "r.\"endedAt\""),
|
|
19248
|
+
timeToFirstChunkMs: "r.\"timeToFirstChunkMs\"",
|
|
19226
19249
|
entityName: "r.\"entityName\"",
|
|
19227
19250
|
entityType: "r.\"entityType\"",
|
|
19251
|
+
name: "r.\"name\"",
|
|
19252
|
+
spanType: "r.\"spanType\"",
|
|
19228
19253
|
environment: "r.\"environment\"",
|
|
19229
19254
|
status: TRACE_STATUS_SQL,
|
|
19230
19255
|
tags: "r.\"tags\""
|
|
@@ -19237,6 +19262,7 @@ const SPAN_FIELDS = {
|
|
|
19237
19262
|
startedAt: "s.\"startedAt\"",
|
|
19238
19263
|
endedAt: "s.\"endedAt\"",
|
|
19239
19264
|
durationMs: "s.\"durationMs\"",
|
|
19265
|
+
timeToFirstChunkMs: "s.\"timeToFirstChunkMs\"",
|
|
19240
19266
|
status: "s.\"status\"",
|
|
19241
19267
|
error: "s.\"error\"",
|
|
19242
19268
|
entityType: "s.\"entityType\"",
|
|
@@ -19306,6 +19332,7 @@ const TRACE_SELECT = `
|
|
|
19306
19332
|
r."resourceId" AS "resourceId",
|
|
19307
19333
|
r."startedAt" AS "startedAt",
|
|
19308
19334
|
r."endedAt" AS "endedAt",
|
|
19335
|
+
r."timeToFirstChunkMs" AS "timeToFirstChunkMs",
|
|
19309
19336
|
r."entityName" AS "entityName",
|
|
19310
19337
|
r."entityType" AS "entityType",
|
|
19311
19338
|
r."environment" AS "environment",
|
|
@@ -19429,11 +19456,11 @@ function compileScalarPredicate(predicate, registry, parameterOffset, allowMetad
|
|
|
19429
19456
|
gte: ">="
|
|
19430
19457
|
};
|
|
19431
19458
|
if (predicate.operator === "eq") return {
|
|
19432
|
-
sql: `${field} IS NOT
|
|
19459
|
+
sql: `${field} IS NOT NULL AND ${field} = ${parameter}`,
|
|
19433
19460
|
values: [...fieldValues, predicate.value]
|
|
19434
19461
|
};
|
|
19435
19462
|
if (predicate.operator === "ne") return {
|
|
19436
|
-
sql: `${field} IS
|
|
19463
|
+
sql: `${field} IS NULL OR ${field} <> ${parameter}`,
|
|
19437
19464
|
values: [...fieldValues, predicate.value]
|
|
19438
19465
|
};
|
|
19439
19466
|
const operator = operators[predicate.operator];
|
|
@@ -19522,6 +19549,8 @@ const ROOT_PUSHDOWN_FIELDS = /* @__PURE__ */ new Set([
|
|
|
19522
19549
|
"endedAt",
|
|
19523
19550
|
"entityName",
|
|
19524
19551
|
"entityType",
|
|
19552
|
+
"name",
|
|
19553
|
+
"spanType",
|
|
19525
19554
|
"environment"
|
|
19526
19555
|
]);
|
|
19527
19556
|
function isRootPushdownPredicate(predicate) {
|
|
@@ -19671,6 +19700,7 @@ function compilePostgresTraceScope(schema, selection, relationCollections, scope
|
|
|
19671
19700
|
WHEN s."isPending" THEN NULL
|
|
19672
19701
|
ELSE ${durationMsSql("s.\"startedAt\"", "s.\"endedAt\"")}
|
|
19673
19702
|
END AS "durationMs",
|
|
19703
|
+
s."timeToFirstChunkMs",
|
|
19674
19704
|
CASE WHEN s."error" IS NOT NULL THEN 'error' ELSE 'success' END AS "status",
|
|
19675
19705
|
s."error",
|
|
19676
19706
|
s."entityType",
|
|
@@ -19792,8 +19822,8 @@ LIMIT $${values.length}`,
|
|
|
19792
19822
|
values
|
|
19793
19823
|
};
|
|
19794
19824
|
}
|
|
19795
|
-
const orderField = plan.orderBy.field
|
|
19796
|
-
const direction = plan.orderBy.direction === "asc" ? "ASC" : "DESC"
|
|
19825
|
+
const orderField = `"${plan.orderBy.field}"`;
|
|
19826
|
+
const direction = `${plan.orderBy.direction === "asc" ? "ASC" : "DESC"} NULLS LAST`;
|
|
19797
19827
|
if (plan.paginationMode === "page") {
|
|
19798
19828
|
values.push(plan.perPage, plan.page * plan.perPage);
|
|
19799
19829
|
return {
|
|
@@ -19807,10 +19837,9 @@ LIMIT $${values.length - 1} OFFSET $${values.length}`,
|
|
|
19807
19837
|
}
|
|
19808
19838
|
let pageCondition = "";
|
|
19809
19839
|
if (plan.cursor) {
|
|
19810
|
-
const
|
|
19811
|
-
|
|
19812
|
-
pageCondition = `WHERE (${
|
|
19813
|
-
values.push(plan.cursor.sortValue, plan.cursor.traceId);
|
|
19840
|
+
const { past, level } = keysetSortBounds(orderField, plan.orderBy.direction, plan.cursor.sortValue, values);
|
|
19841
|
+
values.push(plan.cursor.traceId);
|
|
19842
|
+
pageCondition = `WHERE (${[...past, `(${level} AND "traceId" > $${values.length})`].join(" OR ")})`;
|
|
19814
19843
|
}
|
|
19815
19844
|
values.push(plan.limit + 1);
|
|
19816
19845
|
return {
|
|
@@ -20045,6 +20074,7 @@ function traceRowToResult(row) {
|
|
|
20045
20074
|
resourceId: row.resourceId == null ? null : String(row.resourceId),
|
|
20046
20075
|
startedAt: asIsoTimestamp$1(row.startedAt),
|
|
20047
20076
|
endedAt: asIsoTimestamp$1(row.endedAt),
|
|
20077
|
+
...timeToFirstChunkSupported && { timeToFirstChunkMs: row.timeToFirstChunkMs == null ? null : Number(row.timeToFirstChunkMs) },
|
|
20048
20078
|
entityName: row.entityName == null ? null : String(row.entityName),
|
|
20049
20079
|
entityType: row.entityType == null ? null : String(row.entityType),
|
|
20050
20080
|
environment: row.environment == null ? null : String(row.environment),
|
|
@@ -20142,7 +20172,7 @@ async function queryTraces(client, schema, plan, timeoutMs) {
|
|
|
20142
20172
|
traces,
|
|
20143
20173
|
page: { next: rows.length > plan.limit && last ? _mastra_core_storage.encodeTraceQueryCursor(plan, {
|
|
20144
20174
|
result: "traces",
|
|
20145
|
-
sortValue: last[plan.orderBy.field],
|
|
20175
|
+
sortValue: last[plan.orderBy.field] ?? null,
|
|
20146
20176
|
traceId: last.traceId
|
|
20147
20177
|
}) : null }
|
|
20148
20178
|
});
|
|
@@ -20164,6 +20194,9 @@ async function queryThreads(client, schema, plan, timeoutMs) {
|
|
|
20164
20194
|
function compileSpanQueryPredicate(predicate, offset) {
|
|
20165
20195
|
return compileScalarPredicate(predicate, SPAN_QUERY_FIELDS, offset);
|
|
20166
20196
|
}
|
|
20197
|
+
function compileThreadQueryPredicate(predicate, offset) {
|
|
20198
|
+
return compileScalarPredicate(predicate, Object.fromEntries(Object.keys(_mastra_core_storage.THREAD_QUERY_FIELD_REGISTRY).map((field) => [field, `s."${field}"`])), offset);
|
|
20199
|
+
}
|
|
20167
20200
|
//#endregion
|
|
20168
20201
|
//#region src/storage/domains/observability/v-next/span-query.ts
|
|
20169
20202
|
const identityFields = [
|
|
@@ -20197,7 +20230,8 @@ const fields = [
|
|
|
20197
20230
|
"serviceName",
|
|
20198
20231
|
"experimentId",
|
|
20199
20232
|
"environment",
|
|
20200
|
-
"executionSource"
|
|
20233
|
+
"executionSource",
|
|
20234
|
+
"timeToFirstChunkMs"
|
|
20201
20235
|
];
|
|
20202
20236
|
const identities = identityFields.map((field) => `"${field}"`).join(", ");
|
|
20203
20237
|
const identityOrder = identityFields.map((field) => `"${field}" COLLATE "C" ASC NULLS LAST`).join(", ");
|
|
@@ -20210,11 +20244,8 @@ function selectedKeys(rows, values) {
|
|
|
20210
20244
|
function afterCursor(plan, values) {
|
|
20211
20245
|
if (!plan.cursor) return "TRUE";
|
|
20212
20246
|
const cursor = plan.cursor;
|
|
20213
|
-
|
|
20214
|
-
const
|
|
20215
|
-
const field = `s."${plan.orderBy.field}"`;
|
|
20216
|
-
const terms = [`${field} ${plan.orderBy.direction === "asc" ? ">" : "<"} ${timestamp}`];
|
|
20217
|
-
const equal = [`${field} = ${timestamp}`];
|
|
20247
|
+
const { past: terms, level } = keysetSortBounds(`s."${plan.orderBy.field}"`, plan.orderBy.direction, cursor.sortValue, values);
|
|
20248
|
+
const equal = [level];
|
|
20218
20249
|
for (const key of identityFields) {
|
|
20219
20250
|
const ref = `s."${key}" COLLATE "C"`;
|
|
20220
20251
|
const value = cursor[key];
|
|
@@ -20280,7 +20311,7 @@ function compilePostgresSpanQuery(schema, plan) {
|
|
|
20280
20311
|
"version"
|
|
20281
20312
|
].map((field) => `s."${field}"`).join(", ")}
|
|
20282
20313
|
FROM candidates s WHERE s."startedAt" >= $1 AND s."startedAt" < $2 AND (${predicate.sql}) AND ${after}
|
|
20283
|
-
ORDER BY s."${plan.orderBy.field}" ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"}, ${identityOrder}
|
|
20314
|
+
ORDER BY s."${plan.orderBy.field}" ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"} NULLS LAST, ${identityOrder}
|
|
20284
20315
|
LIMIT $${values.length}`,
|
|
20285
20316
|
values
|
|
20286
20317
|
};
|
|
@@ -20313,8 +20344,9 @@ async function querySpans(client, schema, plan, timeoutMs) {
|
|
|
20313
20344
|
return runWithPostgresTraceQueryTimeout(client, timeoutMs, async (tx) => {
|
|
20314
20345
|
const query = compilePostgresSpanQuery(schema, plan);
|
|
20315
20346
|
const rows = await tx.any(query.text, query.values);
|
|
20316
|
-
const selected = rows.map(({ version: _version, startedAt, endedAt, ...row }) => ({
|
|
20347
|
+
const selected = rows.map(({ version: _version, startedAt, endedAt, timeToFirstChunkMs, ...row }) => ({
|
|
20317
20348
|
...row,
|
|
20349
|
+
...timeToFirstChunkSupported && { timeToFirstChunkMs },
|
|
20318
20350
|
startedAt: startedAt.toISOString(),
|
|
20319
20351
|
endedAt: endedAt.toISOString()
|
|
20320
20352
|
}));
|
|
@@ -20361,11 +20393,245 @@ async function querySpans(client, schema, plan, timeoutMs) {
|
|
|
20361
20393
|
}, { repeatableRead: true });
|
|
20362
20394
|
}
|
|
20363
20395
|
//#endregion
|
|
20396
|
+
//#region src/storage/domains/observability/v-next/thread-query.ts
|
|
20397
|
+
const contextFields = [
|
|
20398
|
+
"resourceId",
|
|
20399
|
+
"userId",
|
|
20400
|
+
"entityType",
|
|
20401
|
+
"entityId",
|
|
20402
|
+
"entityName",
|
|
20403
|
+
"entityVersionId",
|
|
20404
|
+
"runId",
|
|
20405
|
+
"sessionId",
|
|
20406
|
+
"requestId",
|
|
20407
|
+
"serviceName",
|
|
20408
|
+
"experimentId",
|
|
20409
|
+
"environment",
|
|
20410
|
+
"executionSource"
|
|
20411
|
+
];
|
|
20412
|
+
function predicateFields(predicate, fields = /* @__PURE__ */ new Set()) {
|
|
20413
|
+
if (!predicate) return fields;
|
|
20414
|
+
if (predicate.type === "boolean") for (const arg of predicate.args) predicateFields(arg, fields);
|
|
20415
|
+
else if (predicate.type === "not") predicateFields(predicate.arg, fields);
|
|
20416
|
+
else fields.add(predicate.field);
|
|
20417
|
+
return fields;
|
|
20418
|
+
}
|
|
20419
|
+
function canUseThreadCandidates(probe) {
|
|
20420
|
+
return Number(probe.threadCount) <= 16384 && Number(probe.traceCount) <= 1e5 && Number(probe.threadBytes) + Number(probe.traceBytes) <= 4 * 1024 * 1024;
|
|
20421
|
+
}
|
|
20422
|
+
function compilePostgresThreadRowsQuery(schema, plan, strategy = "full") {
|
|
20423
|
+
const values = [plan.timeRange.from, plan.timeRange.to];
|
|
20424
|
+
const scope = [];
|
|
20425
|
+
if (plan.scope) {
|
|
20426
|
+
values.push(plan.scope.organizationId);
|
|
20427
|
+
scope.push(`"organizationId" = $${values.length}`);
|
|
20428
|
+
if (plan.scope.resourceId !== void 0) {
|
|
20429
|
+
values.push(plan.scope.resourceId);
|
|
20430
|
+
scope.push(`"resourceId" = $${values.length}`);
|
|
20431
|
+
}
|
|
20432
|
+
}
|
|
20433
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
20434
|
+
const timestamp = plan.timeRange.mode === "threads" ? plan.timeRange.field : "startedAt";
|
|
20435
|
+
const identity = (field) => `"organizationId" IS NULL, COALESCE("organizationId", ''), "${field}"`;
|
|
20436
|
+
const threadFilter = `(${identity("threadId")}) IN (SELECT ${identity("threadId")} FROM candidate_threads)`;
|
|
20437
|
+
const scopedRoots = `scoped_roots AS NOT MATERIALIZED (
|
|
20438
|
+
SELECT * FROM ${table} WHERE "parentSpanId" IS NULL ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
|
|
20439
|
+
)`;
|
|
20440
|
+
const candidates = `candidate_threads AS MATERIALIZED (
|
|
20441
|
+
SELECT DISTINCT "organizationId", "threadId" FROM scoped_roots
|
|
20442
|
+
WHERE "threadId" IS NOT NULL AND "${timestamp}" >= $1 AND "${timestamp}" < $2
|
|
20443
|
+
${strategy === "probe" ? "LIMIT 16385" : ""}
|
|
20444
|
+
), candidate_traces AS MATERIALIZED (
|
|
20445
|
+
SELECT DISTINCT "organizationId", "traceId" FROM scoped_roots WHERE ${threadFilter}
|
|
20446
|
+
${strategy === "probe" ? "LIMIT 100001" : ""}
|
|
20447
|
+
)`;
|
|
20448
|
+
if (strategy === "probe") return {
|
|
20449
|
+
text: `WITH ${scopedRoots}, ${candidates}
|
|
20450
|
+
SELECT (SELECT count(*) FROM candidate_threads) AS "threadCount",
|
|
20451
|
+
(SELECT COALESCE(sum(octet_length(COALESCE("organizationId", '')) + octet_length("threadId")), 0) FROM candidate_threads) AS "threadBytes",
|
|
20452
|
+
count(*) AS "traceCount", COALESCE(sum(octet_length(COALESCE("organizationId", '')) + octet_length("traceId")), 0) AS "traceBytes"
|
|
20453
|
+
FROM candidate_traces`,
|
|
20454
|
+
values
|
|
20455
|
+
};
|
|
20456
|
+
const predicate = plan.where ? compileThreadQueryPredicate(plan.where, values.length + 1) : {
|
|
20457
|
+
sql: "TRUE",
|
|
20458
|
+
values: []
|
|
20459
|
+
};
|
|
20460
|
+
values.push(...predicate.values);
|
|
20461
|
+
let after = "TRUE";
|
|
20462
|
+
if (plan.cursor) {
|
|
20463
|
+
values.push(plan.cursor.sortValue);
|
|
20464
|
+
const stamp = `$${values.length}::timestamptz`;
|
|
20465
|
+
const field = `s."${plan.orderBy.field}"`;
|
|
20466
|
+
const terms = [`${field} ${plan.orderBy.direction === "asc" ? ">" : "<"} ${stamp}`];
|
|
20467
|
+
const equal = [`${field} = ${stamp}`];
|
|
20468
|
+
for (const key of ["organizationId", "threadId"]) {
|
|
20469
|
+
const ref = `s."${key}" COLLATE "C"`;
|
|
20470
|
+
if (plan.cursor[key] === null) equal.push(`${ref} IS NULL`);
|
|
20471
|
+
else {
|
|
20472
|
+
values.push(plan.cursor[key]);
|
|
20473
|
+
const value = `$${values.length}::text COLLATE "C"`;
|
|
20474
|
+
terms.push(`(${equal.join(" AND ")} AND (${ref} > ${value} OR ${ref} IS NULL))`);
|
|
20475
|
+
equal.push(`${ref} = ${value}`);
|
|
20476
|
+
}
|
|
20477
|
+
}
|
|
20478
|
+
after = `(${terms.join(" OR ")})`;
|
|
20479
|
+
}
|
|
20480
|
+
const qualify = plan.timeRange.mode === "traces" ? "s.\"inWindow\"" : `s."${plan.timeRange.field}" >= $1 AND s."${plan.timeRange.field}" < $2`;
|
|
20481
|
+
const filtered = predicateFields(plan.where);
|
|
20482
|
+
const firstContext = [...contextFields, "timeToFirstChunkMs"].filter((field) => field === "resourceId" || filtered.has(field));
|
|
20483
|
+
const lastFields = [
|
|
20484
|
+
"traceId",
|
|
20485
|
+
"spanId",
|
|
20486
|
+
"cursorId",
|
|
20487
|
+
"resourceId",
|
|
20488
|
+
"endedAt",
|
|
20489
|
+
...filtered.has("status") ? ["status"] : []
|
|
20490
|
+
];
|
|
20491
|
+
values.push(plan.limit + 1);
|
|
20492
|
+
return {
|
|
20493
|
+
text: `WITH ${scopedRoots}, ${strategy === "candidates" ? `${candidates}, ` : ""}current_roots AS (
|
|
20494
|
+
SELECT DISTINCT ON ("organizationId", "traceId")
|
|
20495
|
+
"organizationId", "threadId", "traceId", "spanId", "cursorId", "startedAt", "endedAt", "isPending",
|
|
20496
|
+
${firstContext.map((field) => field === "timeToFirstChunkMs" ? `CASE WHEN "spanType" = 'agent_run' THEN "timeToFirstChunkMs" END AS "timeToFirstChunkMs"` : `"${field}"`).join(", ")}
|
|
20497
|
+
${filtered.has("status") ? ", CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status" : ""}
|
|
20498
|
+
FROM scoped_roots ${strategy === "candidates" ? `WHERE (${identity("traceId")}) IN (SELECT ${identity("traceId")} FROM candidate_traces)` : ""}
|
|
20499
|
+
ORDER BY "organizationId", "traceId", "startedAt" ASC, "spanId" COLLATE "C", "cursorId" DESC
|
|
20500
|
+
), ranked AS (
|
|
20501
|
+
SELECT *, row_number() OVER first_order AS rank,
|
|
20502
|
+
max("endedAt") OVER population AS "lastActivity", count(*) OVER population AS "traceCount",
|
|
20503
|
+
bool_or("startedAt" >= $1 AND "startedAt" < $2) OVER population AS "inWindow",
|
|
20504
|
+
${lastFields.map((field) => `first_value("${field}") OVER last_order AS "last${field[0].toUpperCase()}${field.slice(1)}"`).join(", ")}
|
|
20505
|
+
FROM current_roots WHERE NOT "isPending" AND "endedAt" IS NOT NULL AND "threadId" IS NOT NULL ${strategy === "candidates" ? `AND ${threadFilter}` : ""}
|
|
20506
|
+
WINDOW population AS (PARTITION BY "organizationId", "threadId"),
|
|
20507
|
+
first_order AS (PARTITION BY "organizationId", "threadId" ORDER BY "startedAt", "traceId" COLLATE "C"),
|
|
20508
|
+
last_order AS (PARTITION BY "organizationId", "threadId" ORDER BY "startedAt" DESC, "traceId" COLLATE "C" DESC)
|
|
20509
|
+
), rows AS (
|
|
20510
|
+
SELECT "organizationId", "threadId", "traceId" AS "firstTraceId", "spanId" AS "firstSpanId", "cursorId" AS "firstCursorId",
|
|
20511
|
+
"endedAt" AS "firstEndedAt", "startedAt", "lastActivity" AS "endedAt", "traceCount", "inWindow",
|
|
20512
|
+
${firstContext.map((field) => `"${field}"`).join(", ")},
|
|
20513
|
+
${lastFields.map((field) => `"last${field[0].toUpperCase()}${field.slice(1)}"${field === "status" ? " AS status" : ""}`).join(", ")}
|
|
20514
|
+
FROM ranked WHERE rank = 1
|
|
20515
|
+
) SELECT * FROM rows s WHERE ${qualify} AND (${predicate.sql}) AND ${after}
|
|
20516
|
+
ORDER BY s."${plan.orderBy.field}" ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"},
|
|
20517
|
+
s."organizationId" COLLATE "C" ASC NULLS LAST, s."threadId" COLLATE "C" ASC LIMIT $${values.length}`,
|
|
20518
|
+
values
|
|
20519
|
+
};
|
|
20520
|
+
}
|
|
20521
|
+
async function queryThreadRows(client, schema, plan, timeoutMs, strategy = "auto") {
|
|
20522
|
+
const deadline = performance.now() + _mastra_core_storage.resolveTraceQueryTimeoutMs(timeoutMs);
|
|
20523
|
+
const run = async (text, values) => {
|
|
20524
|
+
const remaining = Math.floor(deadline - performance.now());
|
|
20525
|
+
if (remaining <= 0) throw new _mastra_core_storage.TraceQueryExecutionError();
|
|
20526
|
+
return await runWithPostgresTraceQueryTimeout(client, remaining, (tx) => tx.any(text, values));
|
|
20527
|
+
};
|
|
20528
|
+
if (strategy === "auto") {
|
|
20529
|
+
const probeQuery = compilePostgresThreadRowsQuery(schema, plan, "probe");
|
|
20530
|
+
const [probe] = await run(probeQuery.text, probeQuery.values);
|
|
20531
|
+
if (Number(probe.threadCount) === 0) return {
|
|
20532
|
+
threads: [],
|
|
20533
|
+
page: { next: null }
|
|
20534
|
+
};
|
|
20535
|
+
strategy = canUseThreadCandidates(probe) ? "candidates" : "full";
|
|
20536
|
+
}
|
|
20537
|
+
const compiled = compilePostgresThreadRowsQuery(schema, plan, strategy);
|
|
20538
|
+
const selected = await run(compiled.text, compiled.values);
|
|
20539
|
+
const page = selected.slice(0, plan.limit);
|
|
20540
|
+
if (!page.length) return {
|
|
20541
|
+
threads: [],
|
|
20542
|
+
page: { next: null }
|
|
20543
|
+
};
|
|
20544
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
20545
|
+
const values = [];
|
|
20546
|
+
const keys = page.flatMap((row) => ["first", "last"].map((which) => {
|
|
20547
|
+
const entries = {
|
|
20548
|
+
organizationId: row.organizationId,
|
|
20549
|
+
resourceId: which === "first" ? row.resourceId : row.lastResourceId,
|
|
20550
|
+
traceId: row[`${which}TraceId`],
|
|
20551
|
+
spanId: row[`${which}SpanId`],
|
|
20552
|
+
cursorId: row[`${which}CursorId`],
|
|
20553
|
+
endedAt: row[`${which}EndedAt`]
|
|
20554
|
+
};
|
|
20555
|
+
return `(${Object.entries(entries).map(([field, value]) => {
|
|
20556
|
+
values.push(value);
|
|
20557
|
+
return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${values.length}`;
|
|
20558
|
+
}).join(" AND ")})`;
|
|
20559
|
+
}));
|
|
20560
|
+
const payloads = await run(`SELECT "organizationId", "traceId", "cursorId", "spanType", ${contextFields.map((field) => `"${field}"`).join(", ")},
|
|
20561
|
+
CASE WHEN "spanType" = 'agent_run' THEN "timeToFirstChunkMs" END AS "timeToFirstChunkMs",
|
|
20562
|
+
CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
|
|
20563
|
+
${[
|
|
20564
|
+
"input",
|
|
20565
|
+
"output",
|
|
20566
|
+
"error"
|
|
20567
|
+
].map((field) => `"${field}Preview", CASE WHEN ${missingPreviewSql(`"${field}Preview"`)} THEN "${field}" END AS "${field}"`).join(", ")}
|
|
20568
|
+
FROM ${table} WHERE ${keys.join(" OR ")}`, values);
|
|
20569
|
+
const key = (org, trace, version) => JSON.stringify([
|
|
20570
|
+
org,
|
|
20571
|
+
trace,
|
|
20572
|
+
String(version)
|
|
20573
|
+
]);
|
|
20574
|
+
const byRoot = new Map(payloads.map((row) => [key(row.organizationId, row.traceId, row.cursorId), row]));
|
|
20575
|
+
const agents = page.filter((row) => byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId))?.spanType === "agent_run");
|
|
20576
|
+
const models = /* @__PURE__ */ new Map();
|
|
20577
|
+
if (agents.length) {
|
|
20578
|
+
const modelValues = [];
|
|
20579
|
+
const rows = await run(`SELECT DISTINCT ON ("organizationId", "traceId") "organizationId", "traceId",
|
|
20580
|
+
CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
|
|
20581
|
+
CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider
|
|
20582
|
+
FROM ${table} WHERE "spanType" = 'model_generation' AND NOT "isPending" AND (${agents.map((row) => `(${Object.entries({
|
|
20583
|
+
organizationId: row.organizationId,
|
|
20584
|
+
resourceId: row.resourceId,
|
|
20585
|
+
traceId: row.firstTraceId,
|
|
20586
|
+
parentSpanId: row.firstSpanId
|
|
20587
|
+
}).map(([field, value]) => {
|
|
20588
|
+
modelValues.push(value);
|
|
20589
|
+
return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${modelValues.length}`;
|
|
20590
|
+
}).join(" AND ")})`).join(" OR ")})
|
|
20591
|
+
ORDER BY "organizationId", "traceId", "startedAt", "spanId" COLLATE "C", "cursorId" DESC`, modelValues);
|
|
20592
|
+
for (const row of rows) models.set(JSON.stringify([row.organizationId, row.traceId]), row);
|
|
20593
|
+
}
|
|
20594
|
+
const threads = page.flatMap((row) => {
|
|
20595
|
+
const first = byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId));
|
|
20596
|
+
const last = byRoot.get(key(row.organizationId, row.lastTraceId, row.lastCursorId));
|
|
20597
|
+
if (!first || !last) return [];
|
|
20598
|
+
const model = models.get(JSON.stringify([row.organizationId, row.firstTraceId]));
|
|
20599
|
+
return [_mastra_core_storage.threadQueryRowSchema.parse({
|
|
20600
|
+
organizationId: row.organizationId,
|
|
20601
|
+
threadId: row.threadId,
|
|
20602
|
+
firstTraceId: row.firstTraceId,
|
|
20603
|
+
lastTraceId: row.lastTraceId,
|
|
20604
|
+
...Object.fromEntries(contextFields.map((field) => [field, first[field]])),
|
|
20605
|
+
status: last.status,
|
|
20606
|
+
startedAt: row.startedAt.toISOString(),
|
|
20607
|
+
endedAt: row.endedAt.toISOString(),
|
|
20608
|
+
traceCount: Number(row.traceCount),
|
|
20609
|
+
timeToFirstChunkMs: first.timeToFirstChunkMs,
|
|
20610
|
+
model: model?.model ?? null,
|
|
20611
|
+
provider: model?.provider ?? null,
|
|
20612
|
+
inputPreview: readPreview(first.inputPreview, first.input),
|
|
20613
|
+
outputPreview: readPreview(last.outputPreview, last.output),
|
|
20614
|
+
errorPreview: readPreview(last.errorPreview, last.error)
|
|
20615
|
+
})];
|
|
20616
|
+
});
|
|
20617
|
+
const last = page.at(-1);
|
|
20618
|
+
return {
|
|
20619
|
+
threads,
|
|
20620
|
+
page: { next: selected.length > plan.limit ? _mastra_core_storage.encodeThreadQueryCursor(plan, {
|
|
20621
|
+
organizationId: last.organizationId,
|
|
20622
|
+
threadId: last.threadId,
|
|
20623
|
+
sortValue: last[plan.orderBy.field].toISOString()
|
|
20624
|
+
}) : null }
|
|
20625
|
+
};
|
|
20626
|
+
}
|
|
20627
|
+
//#endregion
|
|
20364
20628
|
//#region src/storage/domains/observability/v-next/trace-aggregate.ts
|
|
20365
20629
|
/** Trace-root column expressions (alias `r`) for each groupable dimension; same values `where` sees. */
|
|
20366
20630
|
const DIMENSION_SQL = {
|
|
20367
20631
|
entityType: "r.\"entityType\"",
|
|
20368
20632
|
entityName: "r.\"entityName\"",
|
|
20633
|
+
name: "r.\"name\"",
|
|
20634
|
+
spanType: "r.\"spanType\"",
|
|
20369
20635
|
environment: "r.\"environment\"",
|
|
20370
20636
|
status: TRACE_STATUS_SQL,
|
|
20371
20637
|
serviceName: "r.\"serviceName\"",
|
|
@@ -21592,12 +21858,15 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
21592
21858
|
"trace-query",
|
|
21593
21859
|
"trace-aggregate",
|
|
21594
21860
|
...spanQueryFeatures,
|
|
21861
|
+
...typeof _mastra_core_storage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
|
|
21595
21862
|
"trace-query-root-duration",
|
|
21596
21863
|
"trace-query-discovery",
|
|
21597
21864
|
"thread-query",
|
|
21598
21865
|
"trace-query-tenant-scope",
|
|
21599
21866
|
"feedback",
|
|
21600
|
-
"trace-query-context-ids"
|
|
21867
|
+
"trace-query-context-ids",
|
|
21868
|
+
...timeToFirstChunkFeatures,
|
|
21869
|
+
"trace-query-root-span-fields"
|
|
21601
21870
|
];
|
|
21602
21871
|
return [
|
|
21603
21872
|
"metrics",
|
|
@@ -21612,12 +21881,15 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
21612
21881
|
"trace-query",
|
|
21613
21882
|
"trace-aggregate",
|
|
21614
21883
|
...spanQueryFeatures,
|
|
21884
|
+
...typeof _mastra_core_storage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
|
|
21615
21885
|
"trace-query-root-duration",
|
|
21616
21886
|
"trace-query-discovery",
|
|
21617
21887
|
"thread-query",
|
|
21618
21888
|
"trace-query-tenant-scope",
|
|
21619
21889
|
"feedback",
|
|
21620
|
-
"trace-query-context-ids"
|
|
21890
|
+
"trace-query-context-ids",
|
|
21891
|
+
...timeToFirstChunkFeatures,
|
|
21892
|
+
"trace-query-root-span-fields"
|
|
21621
21893
|
];
|
|
21622
21894
|
}
|
|
21623
21895
|
async #run(op, fn, details) {
|
|
@@ -21679,7 +21951,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
21679
21951
|
return this.#run("GET_TRACE_QUERY_VALUES", () => getTraceQueryValues(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
21680
21952
|
}
|
|
21681
21953
|
async queryThreads(plan) {
|
|
21682
|
-
return this.#run("QUERY_THREADS", () => queryThreads(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
21954
|
+
return this.#run("QUERY_THREADS", () => plan.result === "threadRows" ? queryThreadRows(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs) : queryThreads(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
21683
21955
|
}
|
|
21684
21956
|
async listBranches(args) {
|
|
21685
21957
|
return this.#run("LIST_BRANCHES", () => listBranches(this.#readClient, this.#schema, args));
|
|
@@ -24111,7 +24383,7 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
|
|
|
24111
24383
|
}
|
|
24112
24384
|
}
|
|
24113
24385
|
async list(args) {
|
|
24114
|
-
const { page = 0, perPage: perPageInput, orderBy, authorId, visibility, status, entityIds, pinFavoritedFor, favoritedOnly } = args || {};
|
|
24386
|
+
const { page = 0, perPage: perPageInput, orderBy, authorId, visibility, status, entityIds, pinFavoritedFor, favoritedOnly, metadata } = args || {};
|
|
24115
24387
|
const { field, direction } = this.parseOrderBy(orderBy);
|
|
24116
24388
|
if (page < 0) throw new _mastra_core_error.MastraError({
|
|
24117
24389
|
id: (0, _mastra_core_storage.createStorageErrorId)("PG", "LIST_SKILLS", "INVALID_PAGE"),
|
|
@@ -24156,6 +24428,16 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
|
|
|
24156
24428
|
conditions.push(`s.visibility = $${paramIdx++}`);
|
|
24157
24429
|
queryParams.push(visibility);
|
|
24158
24430
|
}
|
|
24431
|
+
if (metadata && Object.keys(metadata).length > 0) {
|
|
24432
|
+
const versionsTable = getTableName$5({
|
|
24433
|
+
indexName: _mastra_core_storage.TABLE_SKILL_VERSIONS,
|
|
24434
|
+
schemaName: getSchemaName$5(this.#schema)
|
|
24435
|
+
});
|
|
24436
|
+
const latestVersionId = `(SELECT lv.id FROM ${versionsTable} lv WHERE lv."skillId" = s.id ORDER BY lv."versionNumber" DESC LIMIT 1)`;
|
|
24437
|
+
const resolvedVersionId = status === "draft" ? latestVersionId : `COALESCE(s."activeVersionId", ${latestVersionId})`;
|
|
24438
|
+
conditions.push(`EXISTS (SELECT 1 FROM ${versionsTable} mv WHERE mv."skillId" = s.id AND mv.id = ${resolvedVersionId} AND mv.metadata @> $${paramIdx++}::jsonb)`);
|
|
24439
|
+
queryParams.push(toPgJson(metadata));
|
|
24440
|
+
}
|
|
24159
24441
|
if (entityIds && entityIds.length > 0) {
|
|
24160
24442
|
const placeholders = entityIds.map(() => `$${paramIdx++}`).join(", ");
|
|
24161
24443
|
conditions.push(`s.id IN (${placeholders})`);
|