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