@mastra/pg 1.32.0-alpha.2 → 1.32.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.
@@ -3,7 +3,7 @@ name: mastra-pg
3
3
  description: Documentation for @mastra/pg. Use when working with @mastra/pg APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/pg"
6
- version: "1.32.0-alpha.2"
6
+ version: "1.32.0-alpha.3"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.32.0-alpha.2",
2
+ "version": "1.32.0-alpha.3",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -19209,6 +19209,9 @@ 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
+ const timeToFirstChunkFeatures = timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [];
19212
19215
  function durationMsSql(startedAt, endedAt) {
19213
19216
  return `EXTRACT(EPOCH FROM (${endedAt} - ${startedAt}))::numeric * 1000`;
19214
19217
  }
@@ -19223,8 +19226,11 @@ const TRACE_FIELDS = {
19223
19226
  startedAt: "r.\"startedAt\"",
19224
19227
  endedAt: "r.\"endedAt\"",
19225
19228
  durationMs: durationMsSql("r.\"startedAt\"", "r.\"endedAt\""),
19229
+ timeToFirstChunkMs: "r.\"timeToFirstChunkMs\"",
19226
19230
  entityName: "r.\"entityName\"",
19227
19231
  entityType: "r.\"entityType\"",
19232
+ name: "r.\"name\"",
19233
+ spanType: "r.\"spanType\"",
19228
19234
  environment: "r.\"environment\"",
19229
19235
  status: TRACE_STATUS_SQL,
19230
19236
  tags: "r.\"tags\""
@@ -19237,6 +19243,7 @@ const SPAN_FIELDS = {
19237
19243
  startedAt: "s.\"startedAt\"",
19238
19244
  endedAt: "s.\"endedAt\"",
19239
19245
  durationMs: "s.\"durationMs\"",
19246
+ timeToFirstChunkMs: "s.\"timeToFirstChunkMs\"",
19240
19247
  status: "s.\"status\"",
19241
19248
  error: "s.\"error\"",
19242
19249
  entityType: "s.\"entityType\"",
@@ -19306,6 +19313,7 @@ const TRACE_SELECT = `
19306
19313
  r."resourceId" AS "resourceId",
19307
19314
  r."startedAt" AS "startedAt",
19308
19315
  r."endedAt" AS "endedAt",
19316
+ r."timeToFirstChunkMs" AS "timeToFirstChunkMs",
19309
19317
  r."entityName" AS "entityName",
19310
19318
  r."entityType" AS "entityType",
19311
19319
  r."environment" AS "environment",
@@ -19429,11 +19437,11 @@ function compileScalarPredicate(predicate, registry, parameterOffset, allowMetad
19429
19437
  gte: ">="
19430
19438
  };
19431
19439
  if (predicate.operator === "eq") return {
19432
- sql: `${field} IS NOT DISTINCT FROM ${parameter}`,
19440
+ sql: `${field} IS NOT NULL AND ${field} = ${parameter}`,
19433
19441
  values: [...fieldValues, predicate.value]
19434
19442
  };
19435
19443
  if (predicate.operator === "ne") return {
19436
- sql: `${field} IS DISTINCT FROM ${parameter}`,
19444
+ sql: `${field} IS NULL OR ${field} <> ${parameter}`,
19437
19445
  values: [...fieldValues, predicate.value]
19438
19446
  };
19439
19447
  const operator = operators[predicate.operator];
@@ -19522,6 +19530,8 @@ const ROOT_PUSHDOWN_FIELDS = /* @__PURE__ */ new Set([
19522
19530
  "endedAt",
19523
19531
  "entityName",
19524
19532
  "entityType",
19533
+ "name",
19534
+ "spanType",
19525
19535
  "environment"
19526
19536
  ]);
19527
19537
  function isRootPushdownPredicate(predicate) {
@@ -19671,6 +19681,7 @@ function compilePostgresTraceScope(schema, selection, relationCollections, scope
19671
19681
  WHEN s."isPending" THEN NULL
19672
19682
  ELSE ${durationMsSql("s.\"startedAt\"", "s.\"endedAt\"")}
19673
19683
  END AS "durationMs",
19684
+ s."timeToFirstChunkMs",
19674
19685
  CASE WHEN s."error" IS NOT NULL THEN 'error' ELSE 'success' END AS "status",
19675
19686
  s."error",
19676
19687
  s."entityType",
@@ -20045,6 +20056,7 @@ function traceRowToResult(row) {
20045
20056
  resourceId: row.resourceId == null ? null : String(row.resourceId),
20046
20057
  startedAt: asIsoTimestamp$1(row.startedAt),
20047
20058
  endedAt: asIsoTimestamp$1(row.endedAt),
20059
+ ...timeToFirstChunkSupported && { timeToFirstChunkMs: row.timeToFirstChunkMs == null ? null : Number(row.timeToFirstChunkMs) },
20048
20060
  entityName: row.entityName == null ? null : String(row.entityName),
20049
20061
  entityType: row.entityType == null ? null : String(row.entityType),
20050
20062
  environment: row.environment == null ? null : String(row.environment),
@@ -20164,6 +20176,9 @@ async function queryThreads(client, schema, plan, timeoutMs) {
20164
20176
  function compileSpanQueryPredicate(predicate, offset) {
20165
20177
  return compileScalarPredicate(predicate, SPAN_QUERY_FIELDS, offset);
20166
20178
  }
20179
+ function compileThreadQueryPredicate(predicate, offset) {
20180
+ return compileScalarPredicate(predicate, Object.fromEntries(Object.keys(_mastra_core_storage.THREAD_QUERY_FIELD_REGISTRY).map((field) => [field, `s."${field}"`])), offset);
20181
+ }
20167
20182
  //#endregion
20168
20183
  //#region src/storage/domains/observability/v-next/span-query.ts
20169
20184
  const identityFields = [
@@ -20197,7 +20212,8 @@ const fields = [
20197
20212
  "serviceName",
20198
20213
  "experimentId",
20199
20214
  "environment",
20200
- "executionSource"
20215
+ "executionSource",
20216
+ "timeToFirstChunkMs"
20201
20217
  ];
20202
20218
  const identities = identityFields.map((field) => `"${field}"`).join(", ");
20203
20219
  const identityOrder = identityFields.map((field) => `"${field}" COLLATE "C" ASC NULLS LAST`).join(", ");
@@ -20313,8 +20329,9 @@ async function querySpans(client, schema, plan, timeoutMs) {
20313
20329
  return runWithPostgresTraceQueryTimeout(client, timeoutMs, async (tx) => {
20314
20330
  const query = compilePostgresSpanQuery(schema, plan);
20315
20331
  const rows = await tx.any(query.text, query.values);
20316
- const selected = rows.map(({ version: _version, startedAt, endedAt, ...row }) => ({
20332
+ const selected = rows.map(({ version: _version, startedAt, endedAt, timeToFirstChunkMs, ...row }) => ({
20317
20333
  ...row,
20334
+ ...timeToFirstChunkSupported && { timeToFirstChunkMs },
20318
20335
  startedAt: startedAt.toISOString(),
20319
20336
  endedAt: endedAt.toISOString()
20320
20337
  }));
@@ -20361,11 +20378,245 @@ async function querySpans(client, schema, plan, timeoutMs) {
20361
20378
  }, { repeatableRead: true });
20362
20379
  }
20363
20380
  //#endregion
20381
+ //#region src/storage/domains/observability/v-next/thread-query.ts
20382
+ const contextFields = [
20383
+ "resourceId",
20384
+ "userId",
20385
+ "entityType",
20386
+ "entityId",
20387
+ "entityName",
20388
+ "entityVersionId",
20389
+ "runId",
20390
+ "sessionId",
20391
+ "requestId",
20392
+ "serviceName",
20393
+ "experimentId",
20394
+ "environment",
20395
+ "executionSource"
20396
+ ];
20397
+ function predicateFields(predicate, fields = /* @__PURE__ */ new Set()) {
20398
+ if (!predicate) return fields;
20399
+ if (predicate.type === "boolean") for (const arg of predicate.args) predicateFields(arg, fields);
20400
+ else if (predicate.type === "not") predicateFields(predicate.arg, fields);
20401
+ else fields.add(predicate.field);
20402
+ return fields;
20403
+ }
20404
+ function canUseThreadCandidates(probe) {
20405
+ return Number(probe.threadCount) <= 16384 && Number(probe.traceCount) <= 1e5 && Number(probe.threadBytes) + Number(probe.traceBytes) <= 4 * 1024 * 1024;
20406
+ }
20407
+ function compilePostgresThreadRowsQuery(schema, plan, strategy = "full") {
20408
+ const values = [plan.timeRange.from, plan.timeRange.to];
20409
+ const scope = [];
20410
+ if (plan.scope) {
20411
+ values.push(plan.scope.organizationId);
20412
+ scope.push(`"organizationId" = $${values.length}`);
20413
+ if (plan.scope.resourceId !== void 0) {
20414
+ values.push(plan.scope.resourceId);
20415
+ scope.push(`"resourceId" = $${values.length}`);
20416
+ }
20417
+ }
20418
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
20419
+ const timestamp = plan.timeRange.mode === "threads" ? plan.timeRange.field : "startedAt";
20420
+ const identity = (field) => `"organizationId" IS NULL, COALESCE("organizationId", ''), "${field}"`;
20421
+ const threadFilter = `(${identity("threadId")}) IN (SELECT ${identity("threadId")} FROM candidate_threads)`;
20422
+ const scopedRoots = `scoped_roots AS NOT MATERIALIZED (
20423
+ SELECT * FROM ${table} WHERE "parentSpanId" IS NULL ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
20424
+ )`;
20425
+ const candidates = `candidate_threads AS MATERIALIZED (
20426
+ SELECT DISTINCT "organizationId", "threadId" FROM scoped_roots
20427
+ WHERE "threadId" IS NOT NULL AND "${timestamp}" >= $1 AND "${timestamp}" < $2
20428
+ ${strategy === "probe" ? "LIMIT 16385" : ""}
20429
+ ), candidate_traces AS MATERIALIZED (
20430
+ SELECT DISTINCT "organizationId", "traceId" FROM scoped_roots WHERE ${threadFilter}
20431
+ ${strategy === "probe" ? "LIMIT 100001" : ""}
20432
+ )`;
20433
+ if (strategy === "probe") return {
20434
+ text: `WITH ${scopedRoots}, ${candidates}
20435
+ SELECT (SELECT count(*) FROM candidate_threads) AS "threadCount",
20436
+ (SELECT COALESCE(sum(octet_length(COALESCE("organizationId", '')) + octet_length("threadId")), 0) FROM candidate_threads) AS "threadBytes",
20437
+ count(*) AS "traceCount", COALESCE(sum(octet_length(COALESCE("organizationId", '')) + octet_length("traceId")), 0) AS "traceBytes"
20438
+ FROM candidate_traces`,
20439
+ values
20440
+ };
20441
+ const predicate = plan.where ? compileThreadQueryPredicate(plan.where, values.length + 1) : {
20442
+ sql: "TRUE",
20443
+ values: []
20444
+ };
20445
+ values.push(...predicate.values);
20446
+ let after = "TRUE";
20447
+ if (plan.cursor) {
20448
+ values.push(plan.cursor.sortValue);
20449
+ const stamp = `$${values.length}::timestamptz`;
20450
+ const field = `s."${plan.orderBy.field}"`;
20451
+ const terms = [`${field} ${plan.orderBy.direction === "asc" ? ">" : "<"} ${stamp}`];
20452
+ const equal = [`${field} = ${stamp}`];
20453
+ for (const key of ["organizationId", "threadId"]) {
20454
+ const ref = `s."${key}" COLLATE "C"`;
20455
+ if (plan.cursor[key] === null) equal.push(`${ref} IS NULL`);
20456
+ else {
20457
+ values.push(plan.cursor[key]);
20458
+ const value = `$${values.length}::text COLLATE "C"`;
20459
+ terms.push(`(${equal.join(" AND ")} AND (${ref} > ${value} OR ${ref} IS NULL))`);
20460
+ equal.push(`${ref} = ${value}`);
20461
+ }
20462
+ }
20463
+ after = `(${terms.join(" OR ")})`;
20464
+ }
20465
+ const qualify = plan.timeRange.mode === "traces" ? "s.\"inWindow\"" : `s."${plan.timeRange.field}" >= $1 AND s."${plan.timeRange.field}" < $2`;
20466
+ const filtered = predicateFields(plan.where);
20467
+ const firstContext = [...contextFields, "timeToFirstChunkMs"].filter((field) => field === "resourceId" || filtered.has(field));
20468
+ const lastFields = [
20469
+ "traceId",
20470
+ "spanId",
20471
+ "cursorId",
20472
+ "resourceId",
20473
+ "endedAt",
20474
+ ...filtered.has("status") ? ["status"] : []
20475
+ ];
20476
+ values.push(plan.limit + 1);
20477
+ return {
20478
+ text: `WITH ${scopedRoots}, ${strategy === "candidates" ? `${candidates}, ` : ""}current_roots AS (
20479
+ SELECT DISTINCT ON ("organizationId", "traceId")
20480
+ "organizationId", "threadId", "traceId", "spanId", "cursorId", "startedAt", "endedAt", "isPending",
20481
+ ${firstContext.map((field) => field === "timeToFirstChunkMs" ? `CASE WHEN "spanType" = 'agent_run' THEN "timeToFirstChunkMs" END AS "timeToFirstChunkMs"` : `"${field}"`).join(", ")}
20482
+ ${filtered.has("status") ? ", CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status" : ""}
20483
+ FROM scoped_roots ${strategy === "candidates" ? `WHERE (${identity("traceId")}) IN (SELECT ${identity("traceId")} FROM candidate_traces)` : ""}
20484
+ ORDER BY "organizationId", "traceId", "startedAt" ASC, "spanId" COLLATE "C", "cursorId" DESC
20485
+ ), ranked AS (
20486
+ SELECT *, row_number() OVER first_order AS rank,
20487
+ max("endedAt") OVER population AS "lastActivity", count(*) OVER population AS "traceCount",
20488
+ bool_or("startedAt" >= $1 AND "startedAt" < $2) OVER population AS "inWindow",
20489
+ ${lastFields.map((field) => `first_value("${field}") OVER last_order AS "last${field[0].toUpperCase()}${field.slice(1)}"`).join(", ")}
20490
+ FROM current_roots WHERE NOT "isPending" AND "endedAt" IS NOT NULL AND "threadId" IS NOT NULL ${strategy === "candidates" ? `AND ${threadFilter}` : ""}
20491
+ WINDOW population AS (PARTITION BY "organizationId", "threadId"),
20492
+ first_order AS (PARTITION BY "organizationId", "threadId" ORDER BY "startedAt", "traceId" COLLATE "C"),
20493
+ last_order AS (PARTITION BY "organizationId", "threadId" ORDER BY "startedAt" DESC, "traceId" COLLATE "C" DESC)
20494
+ ), rows AS (
20495
+ SELECT "organizationId", "threadId", "traceId" AS "firstTraceId", "spanId" AS "firstSpanId", "cursorId" AS "firstCursorId",
20496
+ "endedAt" AS "firstEndedAt", "startedAt", "lastActivity" AS "endedAt", "traceCount", "inWindow",
20497
+ ${firstContext.map((field) => `"${field}"`).join(", ")},
20498
+ ${lastFields.map((field) => `"last${field[0].toUpperCase()}${field.slice(1)}"${field === "status" ? " AS status" : ""}`).join(", ")}
20499
+ FROM ranked WHERE rank = 1
20500
+ ) SELECT * FROM rows s WHERE ${qualify} AND (${predicate.sql}) AND ${after}
20501
+ ORDER BY s."${plan.orderBy.field}" ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"},
20502
+ s."organizationId" COLLATE "C" ASC NULLS LAST, s."threadId" COLLATE "C" ASC LIMIT $${values.length}`,
20503
+ values
20504
+ };
20505
+ }
20506
+ async function queryThreadRows(client, schema, plan, timeoutMs, strategy = "auto") {
20507
+ const deadline = performance.now() + _mastra_core_storage.resolveTraceQueryTimeoutMs(timeoutMs);
20508
+ const run = async (text, values) => {
20509
+ const remaining = Math.floor(deadline - performance.now());
20510
+ if (remaining <= 0) throw new _mastra_core_storage.TraceQueryExecutionError();
20511
+ return await runWithPostgresTraceQueryTimeout(client, remaining, (tx) => tx.any(text, values));
20512
+ };
20513
+ if (strategy === "auto") {
20514
+ const probeQuery = compilePostgresThreadRowsQuery(schema, plan, "probe");
20515
+ const [probe] = await run(probeQuery.text, probeQuery.values);
20516
+ if (Number(probe.threadCount) === 0) return {
20517
+ threads: [],
20518
+ page: { next: null }
20519
+ };
20520
+ strategy = canUseThreadCandidates(probe) ? "candidates" : "full";
20521
+ }
20522
+ const compiled = compilePostgresThreadRowsQuery(schema, plan, strategy);
20523
+ const selected = await run(compiled.text, compiled.values);
20524
+ const page = selected.slice(0, plan.limit);
20525
+ if (!page.length) return {
20526
+ threads: [],
20527
+ page: { next: null }
20528
+ };
20529
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
20530
+ const values = [];
20531
+ const keys = page.flatMap((row) => ["first", "last"].map((which) => {
20532
+ const entries = {
20533
+ organizationId: row.organizationId,
20534
+ resourceId: which === "first" ? row.resourceId : row.lastResourceId,
20535
+ traceId: row[`${which}TraceId`],
20536
+ spanId: row[`${which}SpanId`],
20537
+ cursorId: row[`${which}CursorId`],
20538
+ endedAt: row[`${which}EndedAt`]
20539
+ };
20540
+ return `(${Object.entries(entries).map(([field, value]) => {
20541
+ values.push(value);
20542
+ return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${values.length}`;
20543
+ }).join(" AND ")})`;
20544
+ }));
20545
+ const payloads = await run(`SELECT "organizationId", "traceId", "cursorId", "spanType", ${contextFields.map((field) => `"${field}"`).join(", ")},
20546
+ CASE WHEN "spanType" = 'agent_run' THEN "timeToFirstChunkMs" END AS "timeToFirstChunkMs",
20547
+ CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
20548
+ ${[
20549
+ "input",
20550
+ "output",
20551
+ "error"
20552
+ ].map((field) => `"${field}Preview", CASE WHEN ${missingPreviewSql(`"${field}Preview"`)} THEN "${field}" END AS "${field}"`).join(", ")}
20553
+ FROM ${table} WHERE ${keys.join(" OR ")}`, values);
20554
+ const key = (org, trace, version) => JSON.stringify([
20555
+ org,
20556
+ trace,
20557
+ String(version)
20558
+ ]);
20559
+ const byRoot = new Map(payloads.map((row) => [key(row.organizationId, row.traceId, row.cursorId), row]));
20560
+ const agents = page.filter((row) => byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId))?.spanType === "agent_run");
20561
+ const models = /* @__PURE__ */ new Map();
20562
+ if (agents.length) {
20563
+ const modelValues = [];
20564
+ const rows = await run(`SELECT DISTINCT ON ("organizationId", "traceId") "organizationId", "traceId",
20565
+ CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
20566
+ CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider
20567
+ FROM ${table} WHERE "spanType" = 'model_generation' AND NOT "isPending" AND (${agents.map((row) => `(${Object.entries({
20568
+ organizationId: row.organizationId,
20569
+ resourceId: row.resourceId,
20570
+ traceId: row.firstTraceId,
20571
+ parentSpanId: row.firstSpanId
20572
+ }).map(([field, value]) => {
20573
+ modelValues.push(value);
20574
+ return `"${field}" ${field === "organizationId" || field === "resourceId" ? "IS NOT DISTINCT FROM" : "="} $${modelValues.length}`;
20575
+ }).join(" AND ")})`).join(" OR ")})
20576
+ ORDER BY "organizationId", "traceId", "startedAt", "spanId" COLLATE "C", "cursorId" DESC`, modelValues);
20577
+ for (const row of rows) models.set(JSON.stringify([row.organizationId, row.traceId]), row);
20578
+ }
20579
+ const threads = page.flatMap((row) => {
20580
+ const first = byRoot.get(key(row.organizationId, row.firstTraceId, row.firstCursorId));
20581
+ const last = byRoot.get(key(row.organizationId, row.lastTraceId, row.lastCursorId));
20582
+ if (!first || !last) return [];
20583
+ const model = models.get(JSON.stringify([row.organizationId, row.firstTraceId]));
20584
+ return [_mastra_core_storage.threadQueryRowSchema.parse({
20585
+ organizationId: row.organizationId,
20586
+ threadId: row.threadId,
20587
+ firstTraceId: row.firstTraceId,
20588
+ lastTraceId: row.lastTraceId,
20589
+ ...Object.fromEntries(contextFields.map((field) => [field, first[field]])),
20590
+ status: last.status,
20591
+ startedAt: row.startedAt.toISOString(),
20592
+ endedAt: row.endedAt.toISOString(),
20593
+ traceCount: Number(row.traceCount),
20594
+ timeToFirstChunkMs: first.timeToFirstChunkMs,
20595
+ model: model?.model ?? null,
20596
+ provider: model?.provider ?? null,
20597
+ inputPreview: readPreview(first.inputPreview, first.input),
20598
+ outputPreview: readPreview(last.outputPreview, last.output),
20599
+ errorPreview: readPreview(last.errorPreview, last.error)
20600
+ })];
20601
+ });
20602
+ const last = page.at(-1);
20603
+ return {
20604
+ threads,
20605
+ page: { next: selected.length > plan.limit ? _mastra_core_storage.encodeThreadQueryCursor(plan, {
20606
+ organizationId: last.organizationId,
20607
+ threadId: last.threadId,
20608
+ sortValue: last[plan.orderBy.field].toISOString()
20609
+ }) : null }
20610
+ };
20611
+ }
20612
+ //#endregion
20364
20613
  //#region src/storage/domains/observability/v-next/trace-aggregate.ts
20365
20614
  /** Trace-root column expressions (alias `r`) for each groupable dimension; same values `where` sees. */
20366
20615
  const DIMENSION_SQL = {
20367
20616
  entityType: "r.\"entityType\"",
20368
20617
  entityName: "r.\"entityName\"",
20618
+ name: "r.\"name\"",
20619
+ spanType: "r.\"spanType\"",
20369
20620
  environment: "r.\"environment\"",
20370
20621
  status: TRACE_STATUS_SQL,
20371
20622
  serviceName: "r.\"serviceName\"",
@@ -21592,12 +21843,15 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
21592
21843
  "trace-query",
21593
21844
  "trace-aggregate",
21594
21845
  ...spanQueryFeatures,
21846
+ ...typeof _mastra_core_storage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
21595
21847
  "trace-query-root-duration",
21596
21848
  "trace-query-discovery",
21597
21849
  "thread-query",
21598
21850
  "trace-query-tenant-scope",
21599
21851
  "feedback",
21600
- "trace-query-context-ids"
21852
+ "trace-query-context-ids",
21853
+ ...timeToFirstChunkFeatures,
21854
+ "trace-query-root-span-fields"
21601
21855
  ];
21602
21856
  return [
21603
21857
  "metrics",
@@ -21612,12 +21866,15 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
21612
21866
  "trace-query",
21613
21867
  "trace-aggregate",
21614
21868
  ...spanQueryFeatures,
21869
+ ...typeof _mastra_core_storage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
21615
21870
  "trace-query-root-duration",
21616
21871
  "trace-query-discovery",
21617
21872
  "thread-query",
21618
21873
  "trace-query-tenant-scope",
21619
21874
  "feedback",
21620
- "trace-query-context-ids"
21875
+ "trace-query-context-ids",
21876
+ ...timeToFirstChunkFeatures,
21877
+ "trace-query-root-span-fields"
21621
21878
  ];
21622
21879
  }
21623
21880
  async #run(op, fn, details) {
@@ -21679,7 +21936,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
21679
21936
  return this.#run("GET_TRACE_QUERY_VALUES", () => getTraceQueryValues(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
21680
21937
  }
21681
21938
  async queryThreads(plan) {
21682
- return this.#run("QUERY_THREADS", () => queryThreads(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
21939
+ 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
21940
  }
21684
21941
  async listBranches(args) {
21685
21942
  return this.#run("LIST_BRANCHES", () => listBranches(this.#readClient, this.#schema, args));
@@ -24111,7 +24368,7 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
24111
24368
  }
24112
24369
  }
24113
24370
  async list(args) {
24114
- const { page = 0, perPage: perPageInput, orderBy, authorId, visibility, status, entityIds, pinFavoritedFor, favoritedOnly } = args || {};
24371
+ const { page = 0, perPage: perPageInput, orderBy, authorId, visibility, status, entityIds, pinFavoritedFor, favoritedOnly, metadata } = args || {};
24115
24372
  const { field, direction } = this.parseOrderBy(orderBy);
24116
24373
  if (page < 0) throw new _mastra_core_error.MastraError({
24117
24374
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "LIST_SKILLS", "INVALID_PAGE"),
@@ -24156,6 +24413,16 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
24156
24413
  conditions.push(`s.visibility = $${paramIdx++}`);
24157
24414
  queryParams.push(visibility);
24158
24415
  }
24416
+ if (metadata && Object.keys(metadata).length > 0) {
24417
+ const versionsTable = getTableName$5({
24418
+ indexName: _mastra_core_storage.TABLE_SKILL_VERSIONS,
24419
+ schemaName: getSchemaName$5(this.#schema)
24420
+ });
24421
+ const latestVersionId = `(SELECT lv.id FROM ${versionsTable} lv WHERE lv."skillId" = s.id ORDER BY lv."versionNumber" DESC LIMIT 1)`;
24422
+ const resolvedVersionId = status === "draft" ? latestVersionId : `COALESCE(s."activeVersionId", ${latestVersionId})`;
24423
+ conditions.push(`EXISTS (SELECT 1 FROM ${versionsTable} mv WHERE mv."skillId" = s.id AND mv.id = ${resolvedVersionId} AND mv.metadata @> $${paramIdx++}::jsonb)`);
24424
+ queryParams.push(toPgJson(metadata));
24425
+ }
24159
24426
  if (entityIds && entityIds.length > 0) {
24160
24427
  const placeholders = entityIds.map(() => `$${paramIdx++}`).join(", ");
24161
24428
  conditions.push(`s.id IN (${placeholders})`);