@mastra/pg 1.30.0-alpha.2 → 1.30.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 +91 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +91 -9
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-aggregate.d.ts.map +1 -1
- package/dist/vector/sql-builder.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -317,13 +317,9 @@ const FILTER_OPERATORS = {
|
|
|
317
317
|
};
|
|
318
318
|
},
|
|
319
319
|
$exists: (key, paramIndex, value) => {
|
|
320
|
-
const
|
|
321
|
-
if (value === false) return {
|
|
322
|
-
sql: `NOT (metadata ? '${jsonPathKey}')`,
|
|
323
|
-
needsValue: false
|
|
324
|
-
};
|
|
320
|
+
const existsSql = key.includes(".") ? `${getJsonExtractExpr(key)} IS NOT NULL` : `metadata ? '${parseJsonPathKey(key)}'`;
|
|
325
321
|
return {
|
|
326
|
-
sql:
|
|
322
|
+
sql: value === false ? `NOT (${existsSql})` : existsSql,
|
|
327
323
|
needsValue: false
|
|
328
324
|
};
|
|
329
325
|
},
|
|
@@ -18484,13 +18480,32 @@ function compilePostgresTraceAggregate(schema, plan) {
|
|
|
18484
18480
|
if (intervalMs === void 0) throw new Error(`Unsupported trusted trace-aggregate interval: ${plan.interval}`);
|
|
18485
18481
|
factColumns.push(`to_timestamp(floor(EXTRACT(EPOCH FROM r."startedAt") * 1000 / ${intervalMs}) * ${intervalMs} / 1000.0) AS "bucket"`);
|
|
18486
18482
|
}
|
|
18483
|
+
const measureKinds = new Set(plan.measures.map((measure) => measureRule(measure.name)?.kind));
|
|
18484
|
+
const hasCost = measureKinds.has("cost");
|
|
18485
|
+
let usageJoin = "";
|
|
18486
|
+
if (hasCost || measureKinds.has("tokens")) {
|
|
18487
|
+
ctes.push(...compileUsageCtes(schema, plan, param));
|
|
18488
|
+
usageJoin = "\n LEFT JOIN usage u ON u.\"traceId\" = r.\"traceId\"";
|
|
18489
|
+
USAGE_METRIC_NAMES.forEach((_, index) => factColumns.push(`CASE WHEN u."traceId" IS NOT NULL THEN COALESCE(u."t${index}", 0) END AS "t${index}"`));
|
|
18490
|
+
factColumns.push(`u."traceId" IS NOT NULL AS "usageBearing"`, `CASE WHEN u."priced" THEN u."cost" END AS "traceCost"`, `COALESCE(u."priced" AND NOT u."pricingFailure", FALSE) AS "covered"`, `u."unitMin"`, `u."unitMax"`);
|
|
18491
|
+
}
|
|
18487
18492
|
ctes.push(`facts AS (
|
|
18488
18493
|
SELECT ${factColumns.join(",\n ")}
|
|
18489
|
-
FROM candidates r
|
|
18494
|
+
FROM candidates r${usageJoin}
|
|
18490
18495
|
)`);
|
|
18496
|
+
const mixedUnitsSql = (alias) => `MIN(${alias}"unitMin" COLLATE "C") <> MAX(${alias}"unitMax" COLLATE "C")`;
|
|
18491
18497
|
const measureSql = (name, alias = "") => {
|
|
18492
18498
|
const column = (name) => `${alias}"${name}"`;
|
|
18493
18499
|
if (name === "count") return "COUNT(*)::float8";
|
|
18500
|
+
const rule = measureRule(name);
|
|
18501
|
+
if (rule?.kind === "tokens" && rule.metricNames) {
|
|
18502
|
+
const value = rule.metricNames.map((metricName) => column(`t${usageMetricIndex(metricName)}`)).join(" + ");
|
|
18503
|
+
return `(${rule.statistic === "avg" ? "AVG" : "SUM"}(${value}))::float8`;
|
|
18504
|
+
}
|
|
18505
|
+
if (rule?.kind === "cost") {
|
|
18506
|
+
const aggregate = rule.statistic === "avg" ? "AVG" : "SUM";
|
|
18507
|
+
return `(CASE WHEN ${mixedUnitsSql(alias)} THEN NULL ELSE ${aggregate}(${column("traceCost")}) END)::float8`;
|
|
18508
|
+
}
|
|
18494
18509
|
if (name === "errorCount") return `(COUNT(*) FILTER (WHERE ${column("isError")}))::float8`;
|
|
18495
18510
|
if (name === "errorRate") return `(COUNT(*) FILTER (WHERE ${column("isError")}))::float8 / COUNT(*)`;
|
|
18496
18511
|
if (name === "duration.avg") return `AVG(${column("durationMs")})`;
|
|
@@ -18528,8 +18543,17 @@ function compilePostgresTraceAggregate(schema, plan) {
|
|
|
18528
18543
|
const orderSql = [`${orderTarget} ${direction} NULLS LAST`, ...dimensionColumns.map((column) => `${column} COLLATE "C" ASC NULLS LAST`)].join(", ");
|
|
18529
18544
|
const groupSql = dimensionColumns.length > 0 ? dimensionColumns.join(", ") : "()";
|
|
18530
18545
|
const limitParameter = param(plan.limit + 1);
|
|
18546
|
+
const costColumns = (alias) => {
|
|
18547
|
+
if (!hasCost) return [];
|
|
18548
|
+
const mixedUnit = param(coreStorage.TRACE_AGGREGATE_MIXED_COST_UNIT);
|
|
18549
|
+
return [`(COUNT(*) FILTER (WHERE ${alias}"covered"))::float8 / NULLIF(COUNT(*) FILTER (WHERE ${alias}"usageBearing"), 0) AS "costCoverage"`, `CASE WHEN ${mixedUnitsSql(alias)} THEN ${mixedUnit}::text ELSE MIN(${alias}"unitMin" COLLATE "C") END AS "costUnit"`];
|
|
18550
|
+
};
|
|
18531
18551
|
if (plan.interval === void 0) {
|
|
18532
|
-
const projected = [
|
|
18552
|
+
const projected = [
|
|
18553
|
+
...dimensionColumns,
|
|
18554
|
+
...plan.measures.map((measure, index) => `${measureSql(measure.name)} AS "m${index}"`),
|
|
18555
|
+
...costColumns("")
|
|
18556
|
+
];
|
|
18533
18557
|
return {
|
|
18534
18558
|
text: `WITH ${ctes.join(",\n")}
|
|
18535
18559
|
SELECT ${projected.join(", ")}
|
|
@@ -18555,6 +18579,7 @@ LIMIT ${limitParameter}`,
|
|
|
18555
18579
|
...dimensionColumns.map((column) => `f.${column}`),
|
|
18556
18580
|
"f.\"bucket\"",
|
|
18557
18581
|
...plan.measures.map((measure, index) => `${measureSql(measure.name, "f.")} AS "m${index}"`),
|
|
18582
|
+
...costColumns("f."),
|
|
18558
18583
|
`(SELECT COUNT(*) FROM ranked) > ${maxRankParameter} AS "truncated"`
|
|
18559
18584
|
];
|
|
18560
18585
|
return {
|
|
@@ -18572,6 +18597,59 @@ ORDER BY g."rank" ASC, f."bucket" ASC`,
|
|
|
18572
18597
|
values
|
|
18573
18598
|
};
|
|
18574
18599
|
}
|
|
18600
|
+
const USAGE_METRIC_NAMES = coreStorage.TRACE_AGGREGATE_USAGE_METRIC_NAMES;
|
|
18601
|
+
function measureRule(name) {
|
|
18602
|
+
return coreStorage.isTraceAggregateCanonicalMeasure(name) ? coreStorage.TRACE_AGGREGATE_MEASURE_REGISTRY[name] : void 0;
|
|
18603
|
+
}
|
|
18604
|
+
function usageMetricIndex(name) {
|
|
18605
|
+
const index = USAGE_METRIC_NAMES.indexOf(name);
|
|
18606
|
+
if (index === -1) throw new Error(`Unsupported trusted trace-aggregate token metric: ${name}`);
|
|
18607
|
+
return index;
|
|
18608
|
+
}
|
|
18609
|
+
/**
|
|
18610
|
+
* Builds `usage`: one row per candidate trace that has at least one token metric row, holding
|
|
18611
|
+
* per-name token sums (`t<i>`, indexed by `TRACE_AGGREGATE_USAGE_METRIC_NAMES`) and the trace's
|
|
18612
|
+
* pricing state. Metric rows are matched by traceId, usage metric name, tenant scope, and
|
|
18613
|
+
* `timestamp >= from` only: a trace that starts in the window can emit metrics after `to`, and
|
|
18614
|
+
* the candidates semi-join already bounds the scan.
|
|
18615
|
+
*
|
|
18616
|
+
* Rows are deduplicated on `metricId` alone. The primary key is (`metricId`, `timestamp`)
|
|
18617
|
+
* because the table is partitioned by timestamp, so retried copies with different timestamps
|
|
18618
|
+
* are both stored.
|
|
18619
|
+
*/
|
|
18620
|
+
function compileUsageCtes(schema, plan, param) {
|
|
18621
|
+
const scopeConditions = plan.scope ? [`m."organizationId" = ${param(plan.scope.organizationId)}`, ...plan.scope.resourceId === void 0 ? [] : [`m."resourceId" = ${param(plan.scope.resourceId)}`]] : [];
|
|
18622
|
+
const rowConditions = [
|
|
18623
|
+
`m."traceId" IN (SELECT "traceId" FROM candidates)`,
|
|
18624
|
+
`m."name" = ANY(${param(USAGE_METRIC_NAMES)}::text[])`,
|
|
18625
|
+
`m."timestamp" >= ${param(plan.timeRange.from)}::timestamptz`,
|
|
18626
|
+
...scopeConditions
|
|
18627
|
+
];
|
|
18628
|
+
const costRow = `"name" = ANY(${param(coreStorage.TRACE_AGGREGATE_COST_METRIC_NAMES)}::text[])`;
|
|
18629
|
+
const priced = `${costRow} AND "estimatedCost" IS NOT NULL AND "costUnit" IS NOT NULL AND NOT "hasError"`;
|
|
18630
|
+
const failed = `${costRow} AND ("hasError" OR ("estimatedCost" IS NOT NULL AND "costUnit" IS NULL))`;
|
|
18631
|
+
const tokenColumns = USAGE_METRIC_NAMES.map((name, index) => `SUM("value") FILTER (WHERE "name" = ${param(name)}) AS "t${index}"`);
|
|
18632
|
+
return [`usage_rows AS (
|
|
18633
|
+
SELECT DISTINCT ON (m."metricId") m."traceId", m."name", m."value", m."estimatedCost", m."costUnit",
|
|
18634
|
+
COALESCE(jsonb_typeof(m."costMetadata" -> 'error'), 'null') <> 'null' AS "hasError"
|
|
18635
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)} m
|
|
18636
|
+
WHERE ${rowConditions.join("\n AND ")}
|
|
18637
|
+
ORDER BY m."metricId", m."timestamp"
|
|
18638
|
+
)`, `usage AS (
|
|
18639
|
+
SELECT "traceId",
|
|
18640
|
+
${tokenColumns.join(",\n ")},
|
|
18641
|
+
SUM("estimatedCost") FILTER (WHERE ${priced}) AS "cost",
|
|
18642
|
+
bool_or(${priced}) AS "priced",
|
|
18643
|
+
bool_or(${failed}) AS "pricingFailure",
|
|
18644
|
+
MIN("costUnit" COLLATE "C") FILTER (WHERE ${priced}) AS "unitMin",
|
|
18645
|
+
MAX("costUnit" COLLATE "C") FILTER (WHERE ${priced}) AS "unitMax"
|
|
18646
|
+
FROM usage_rows
|
|
18647
|
+
GROUP BY "traceId"
|
|
18648
|
+
)`];
|
|
18649
|
+
}
|
|
18650
|
+
function nullableNumber(value) {
|
|
18651
|
+
return value === null || value === void 0 ? null : Number(value);
|
|
18652
|
+
}
|
|
18575
18653
|
function toIsoTimestamp(value) {
|
|
18576
18654
|
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
|
18577
18655
|
}
|
|
@@ -18589,7 +18667,11 @@ async function aggregateTraces(client, schema, plan, timeoutMs) {
|
|
|
18589
18667
|
}
|
|
18590
18668
|
return {
|
|
18591
18669
|
rows: resultRows.map((row) => {
|
|
18592
|
-
const shaped = { measures: Object.fromEntries(plan.measures.map((measure, index) => [measure.name,
|
|
18670
|
+
const shaped = { measures: Object.fromEntries(plan.measures.map((measure, index) => [measure.name, nullableNumber(row[`m${index}`])])) };
|
|
18671
|
+
if ("costCoverage" in row) shaped.cost = {
|
|
18672
|
+
coverage: nullableNumber(row.costCoverage),
|
|
18673
|
+
unit: row.costUnit ?? null
|
|
18674
|
+
};
|
|
18593
18675
|
if (plan.dimensions.length > 0) shaped.dimensions = Object.fromEntries(plan.dimensions.map((dimension, index) => [dimension, row[`d${index}`] ?? null]));
|
|
18594
18676
|
if (plan.interval !== void 0) shaped.bucket = toIsoTimestamp(row.bucket);
|
|
18595
18677
|
return shaped;
|