@mastra/pg 1.22.3 → 1.23.0-alpha.1

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
@@ -1,4 +1,5 @@
1
1
  import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
2
+ import * as coreStorage from "@mastra/core/storage";
2
3
  import { AgentsStorage, BRANCH_SPAN_TYPES, BackgroundTasksStorage, BlobStore, ChannelsStorage, DATASETS_SCHEMA, DATASET_ITEMS_SCHEMA, DATASET_VERSIONS_SCHEMA, DatasetsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, EntityType, ExperimentsStorage, FactoryStorage, FavoritesStorage, KNOWLEDGE_ACTIVITY_SCHEMA, KNOWLEDGE_CURSORS_SCHEMA, KNOWLEDGE_MENTIONS_SCHEMA, KNOWLEDGE_NODES_SCHEMA, KNOWLEDGE_RECORDS_SCHEMA, KNOWLEDGE_SEMANTIC_OUTBOX_SCHEMA, KnowledgeConflictError, KnowledgeNotFoundError, KnowledgeStorage, MCPClientsStorage, MCPServersStorage, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, NotificationsStorage, OBSERVATIONAL_MEMORY_TABLE_SCHEMA, ObservabilityStorage, PromptBlocksStorage, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_KNOWLEDGE_ACTIVITY, TABLE_KNOWLEDGE_CURSORS, TABLE_KNOWLEDGE_MENTIONS, TABLE_KNOWLEDGE_NODES, TABLE_KNOWLEDGE_RECORDS, TABLE_KNOWLEDGE_SEMANTIC_OUTBOX, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_NOTIFICATIONS, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_THREAD_STATE, TABLE_TOOL_PROVIDER_CONNECTIONS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, ThreadStateStorage, ToolProviderConnectionsStorage, TraceStatus, UniqueViolationError, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, assertKnowledgeCeilingRaised, assertKnowledgeScopeWithinCeiling, calculatePagination, canonicalizeKnowledgeScope, createKnowledgeUlid, createStorageErrorId, createVectorErrorId, ensureDate, getDefaultValue, getSqlType, hasErrorCode, isKnowledgeScopeVisible, knowledgeScopeKey, knowledgeSemanticDocumentId, knowledgeSemanticIdempotencyKey, listBranchesArgsSchema, listFeedbackArgsSchema, listLogsArgsSchema, listMetricsArgsSchema, listScoresArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, mergeWorkflowStepResult, normalizePerPage, normalizeScheduleTarget, parseDuration, parseKnowledgeNodeCursor, parseKnowledgeWikilinks, safelyParseJSON, storageMessageMatchesMetadataFilter, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
3
4
  import { parseFieldKey, parseSqlIdentifier } from "@mastra/core/utils";
4
5
  import { MastraVector, validateTopK, validateUpsertInput } from "@mastra/core/vector";
@@ -12145,12 +12146,20 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
12145
12146
  };
12146
12147
  const lastBufferedAtTime = input.lastBufferedAtTime ? input.lastBufferedAtTime.toISOString() : null;
12147
12148
  if ((await this.#db.client.query(`UPDATE ${tableName} SET
12148
- "bufferedObservationChunks" = COALESCE("bufferedObservationChunks", '[]'::jsonb) || $1::jsonb,
12149
- "lastBufferedAtTime" = COALESCE($2, "lastBufferedAtTime"),
12150
- "updatedAt" = $3,
12151
- "updatedAtZ" = $4
12152
- WHERE id = $5`, [
12149
+ "bufferedObservationChunks" = CASE
12150
+ WHEN EXISTS (
12151
+ SELECT 1
12152
+ FROM jsonb_array_elements(COALESCE("bufferedObservationChunks", '[]'::jsonb)) AS chunk
12153
+ WHERE chunk->>'cycleId' = $2
12154
+ ) THEN COALESCE("bufferedObservationChunks", '[]'::jsonb)
12155
+ ELSE COALESCE("bufferedObservationChunks", '[]'::jsonb) || $1::jsonb
12156
+ END,
12157
+ "lastBufferedAtTime" = COALESCE($3, "lastBufferedAtTime"),
12158
+ "updatedAt" = $4,
12159
+ "updatedAtZ" = $5
12160
+ WHERE id = $6`, [
12153
12161
  JSON.stringify([newChunk]),
12162
+ input.chunk.cycleId,
12154
12163
  lastBufferedAtTime,
12155
12164
  nowStr,
12156
12165
  nowStr,
@@ -13480,6 +13489,7 @@ var ObservabilityPG = class ObservabilityPG extends ObservabilityStorage {
13480
13489
  }
13481
13490
  }
13482
13491
  async batchDeleteTraces(args) {
13492
+ this.assertUnscopedBatchDeleteTraces(args);
13483
13493
  try {
13484
13494
  const tableName = getTableName$5({
13485
13495
  indexName: TABLE_SPANS,
@@ -16715,6 +16725,304 @@ async function getScorePercentiles(client, schema, args) {
16715
16725
  return { series: percentileSeriesFromRows(await client.manyOrNone(sql, acc.params), args.percentiles) };
16716
16726
  }
16717
16727
  //#endregion
16728
+ //#region src/storage/domains/observability/v-next/trace-query.ts
16729
+ const TRACE_STATUS_SQL = `CASE WHEN r."error" IS NOT NULL THEN 'error' ELSE 'success' END`;
16730
+ const TRACE_FIELDS = {
16731
+ traceId: "r.\"traceId\"",
16732
+ threadId: "r.\"threadId\"",
16733
+ resourceId: "r.\"resourceId\"",
16734
+ startedAt: "r.\"startedAt\"",
16735
+ endedAt: "r.\"endedAt\"",
16736
+ entityName: "r.\"entityName\"",
16737
+ entityType: "r.\"entityType\"",
16738
+ environment: "r.\"environment\"",
16739
+ status: TRACE_STATUS_SQL
16740
+ };
16741
+ const SPAN_FIELDS = {
16742
+ spanType: "s.\"spanType\"",
16743
+ error: "s.\"error\""
16744
+ };
16745
+ const SCORE_FIELDS = {
16746
+ scorerId: "s.\"scorerId\"",
16747
+ score: "s.\"score\""
16748
+ };
16749
+ const TRACE_SELECT = `
16750
+ r."traceId" AS "traceId",
16751
+ r."spanId" AS "rootSpanId",
16752
+ r."threadId" AS "threadId",
16753
+ r."resourceId" AS "resourceId",
16754
+ r."startedAt" AS "startedAt",
16755
+ r."endedAt" AS "endedAt",
16756
+ r."entityName" AS "entityName",
16757
+ r."entityType" AS "entityType",
16758
+ r."environment" AS "environment",
16759
+ ${TRACE_STATUS_SQL} AS "status"`;
16760
+ function fieldSql(registry, field) {
16761
+ const sql = registry[field];
16762
+ if (sql === void 0) throw new Error(`Unsupported trusted trace-query field: ${field}`);
16763
+ return sql;
16764
+ }
16765
+ function placeholders(values, offset) {
16766
+ return values.map((_, index) => `$${offset + index}`).join(", ");
16767
+ }
16768
+ function compileScalarPredicate(predicate, registry, parameterOffset) {
16769
+ if (predicate.type === "boolean") {
16770
+ const values = [];
16771
+ return {
16772
+ sql: predicate.args.map((arg) => {
16773
+ const compiled = compileScalarPredicate(arg, registry, parameterOffset + values.length);
16774
+ values.push(...compiled.values);
16775
+ return `(${compiled.sql})`;
16776
+ }).join(predicate.operator === "and" ? " AND " : " OR "),
16777
+ values
16778
+ };
16779
+ }
16780
+ if (predicate.type === "not") {
16781
+ const compiled = compileScalarPredicate(predicate.arg, registry, parameterOffset);
16782
+ return {
16783
+ sql: `NOT (${compiled.sql})`,
16784
+ values: compiled.values
16785
+ };
16786
+ }
16787
+ const field = fieldSql(registry, predicate.field);
16788
+ if (predicate.type === "presence") return {
16789
+ sql: `${field} IS ${predicate.operator === "exists" ? "NOT " : ""}NULL`,
16790
+ values: []
16791
+ };
16792
+ if (predicate.type === "membership") {
16793
+ const list = placeholders(predicate.values, parameterOffset);
16794
+ if (predicate.operator === "in") return {
16795
+ sql: `${field} IS NOT NULL AND ${field} IN (${list})`,
16796
+ values: predicate.values
16797
+ };
16798
+ return {
16799
+ sql: `${field} IS NULL OR ${field} NOT IN (${list})`,
16800
+ values: predicate.values
16801
+ };
16802
+ }
16803
+ const parameter = `$${parameterOffset}`;
16804
+ const operators = {
16805
+ lt: "<",
16806
+ lte: "<=",
16807
+ gt: ">",
16808
+ gte: ">="
16809
+ };
16810
+ if (predicate.operator === "eq") return {
16811
+ sql: `${field} IS NOT DISTINCT FROM ${parameter}`,
16812
+ values: [predicate.value]
16813
+ };
16814
+ if (predicate.operator === "ne") return {
16815
+ sql: `${field} IS DISTINCT FROM ${parameter}`,
16816
+ values: [predicate.value]
16817
+ };
16818
+ const operator = operators[predicate.operator];
16819
+ if (operator === void 0) throw new Error(`Unsupported trusted trace-query operator: ${predicate.operator}`);
16820
+ return {
16821
+ sql: `${field} IS NOT NULL AND ${field} ${operator} ${parameter}`,
16822
+ values: [predicate.value]
16823
+ };
16824
+ }
16825
+ function latestRootPredicate$1(spanTable) {
16826
+ return `NOT EXISTS (
16827
+ SELECT 1 FROM ${spanTable} newer
16828
+ WHERE newer."traceId" = r."traceId"
16829
+ AND newer."parentSpanId" IS NULL
16830
+ AND newer."cursorId" > r."cursorId"
16831
+ )`;
16832
+ }
16833
+ function latestSpanPredicate$1(spanTable) {
16834
+ return `NOT EXISTS (
16835
+ SELECT 1 FROM ${spanTable} newer
16836
+ WHERE newer."traceId" = s."traceId"
16837
+ AND newer."spanId" = s."spanId"
16838
+ AND (newer."isPending" < s."isPending" OR (newer."isPending" = s."isPending" AND newer."cursorId" > s."cursorId"))
16839
+ )`;
16840
+ }
16841
+ function latestScorePredicate(scoreTable) {
16842
+ return `NOT EXISTS (
16843
+ SELECT 1 FROM ${scoreTable} newer
16844
+ WHERE newer."scoreId" = s."scoreId"
16845
+ AND newer."cursorId" > s."cursorId"
16846
+ )`;
16847
+ }
16848
+ function collectRelationCollections(predicate, collections = /* @__PURE__ */ new Set()) {
16849
+ if (!predicate) return collections;
16850
+ if (predicate.type === "relation") collections.add(predicate.collection);
16851
+ else if (predicate.type === "boolean") for (const arg of predicate.args) collectRelationCollections(arg, collections);
16852
+ else if (predicate.type === "not") collectRelationCollections(predicate.arg, collections);
16853
+ return collections;
16854
+ }
16855
+ function compilePredicate(predicate, parameterOffset) {
16856
+ if (predicate.type === "relation") {
16857
+ const registry = predicate.collection === "spans" ? SPAN_FIELDS : SCORE_FIELDS;
16858
+ const compiled = compileScalarPredicate(predicate.predicate, registry, parameterOffset);
16859
+ const existence = `EXISTS (
16860
+ SELECT 1 FROM ${predicate.collection === "spans" ? "current_spans" : "current_scores"} s
16861
+ WHERE s."traceId" = r."traceId"
16862
+ AND (${compiled.sql})
16863
+ )`;
16864
+ return {
16865
+ sql: predicate.quantifier === "some" ? existence : `NOT ${existence}`,
16866
+ values: compiled.values
16867
+ };
16868
+ }
16869
+ if (predicate.type === "boolean") {
16870
+ const values = [];
16871
+ return {
16872
+ sql: predicate.args.map((arg) => {
16873
+ const compiled = compilePredicate(arg, parameterOffset + values.length);
16874
+ values.push(...compiled.values);
16875
+ return `(${compiled.sql})`;
16876
+ }).join(predicate.operator === "and" ? " AND " : " OR "),
16877
+ values
16878
+ };
16879
+ }
16880
+ if (predicate.type === "not") {
16881
+ const compiled = compilePredicate(predicate.arg, parameterOffset);
16882
+ return {
16883
+ sql: `NOT (${compiled.sql})`,
16884
+ values: compiled.values
16885
+ };
16886
+ }
16887
+ return compileScalarPredicate(predicate, TRACE_FIELDS, parameterOffset);
16888
+ }
16889
+ function compilePostgresTraceQuery(schema, plan) {
16890
+ const spanTable = qualifiedTable(schema, TABLE_SPAN_EVENTS);
16891
+ const scoreTable = qualifiedTable(schema, TABLE_SCORE_EVENTS);
16892
+ const values = [plan.timeRange.from, plan.timeRange.to];
16893
+ const relationCollections = collectRelationCollections(plan.where);
16894
+ const ctes = [`root_scope AS MATERIALIZED (
16895
+ SELECT *
16896
+ FROM ${spanTable} r
16897
+ WHERE ${[
16898
+ `r."parentSpanId" IS NULL`,
16899
+ latestRootPredicate$1(spanTable),
16900
+ `NOT r."isPending"`,
16901
+ `r."endedAt" IS NOT NULL`,
16902
+ `r."startedAt" >= $1`,
16903
+ `r."startedAt" < $2`
16904
+ ].join("\n AND ")}
16905
+ )`];
16906
+ if (relationCollections.has("spans")) ctes.push(`current_spans AS MATERIALIZED (
16907
+ SELECT s."traceId", s."spanType", s."error"
16908
+ FROM ${spanTable} s
16909
+ WHERE s."traceId" IS NOT NULL
16910
+ AND s."traceId" IN (SELECT "traceId" FROM root_scope)
16911
+ AND ${latestSpanPredicate$1(spanTable)}
16912
+ )`);
16913
+ if (relationCollections.has("scores")) ctes.push(`current_scores AS MATERIALIZED (
16914
+ SELECT s."traceId", s."scorerId", s."score"
16915
+ FROM ${scoreTable} s
16916
+ WHERE s."traceId" IS NOT NULL
16917
+ AND s."traceId" IN (SELECT "traceId" FROM root_scope)
16918
+ AND ${latestScorePredicate(scoreTable)}
16919
+ )`);
16920
+ let predicateSql = "TRUE";
16921
+ if (plan.where) {
16922
+ const predicate = compilePredicate(plan.where, values.length + 1);
16923
+ predicateSql = predicate.sql;
16924
+ values.push(...predicate.values);
16925
+ }
16926
+ ctes.push(`candidates AS (
16927
+ SELECT ${TRACE_SELECT}
16928
+ FROM root_scope r
16929
+ WHERE ${predicateSql}
16930
+ )`);
16931
+ const candidates = `WITH ${ctes.join(",\n")}`;
16932
+ if (plan.result === "groups") {
16933
+ const pageCondition = plan.cursor ? `AND "threadId" > $${values.length + 1}` : "";
16934
+ if (plan.cursor) values.push(plan.cursor.threadId);
16935
+ values.push(plan.limit + 1);
16936
+ return {
16937
+ text: `${candidates}
16938
+ SELECT "threadId"
16939
+ FROM candidates
16940
+ WHERE "threadId" IS NOT NULL ${pageCondition}
16941
+ GROUP BY "threadId"
16942
+ ORDER BY "threadId" ASC
16943
+ LIMIT $${values.length}`,
16944
+ values
16945
+ };
16946
+ }
16947
+ const orderField = plan.orderBy.field === "startedAt" ? "\"startedAt\"" : "\"endedAt\"";
16948
+ const direction = plan.orderBy.direction === "asc" ? "ASC" : "DESC";
16949
+ let pageCondition = "";
16950
+ if (plan.cursor) {
16951
+ const comparison = plan.orderBy.direction === "asc" ? ">" : "<";
16952
+ const sortParameter = `$${values.length + 1}`;
16953
+ pageCondition = `WHERE (${orderField} ${comparison} ${sortParameter} OR (${orderField} = ${sortParameter} AND "traceId" > ${`$${values.length + 2}`}))`;
16954
+ values.push(plan.cursor.sortValue, plan.cursor.traceId);
16955
+ }
16956
+ values.push(plan.limit + 1);
16957
+ return {
16958
+ text: `${candidates}
16959
+ SELECT *
16960
+ FROM candidates
16961
+ ${pageCondition}
16962
+ ORDER BY ${orderField} ${direction}, "traceId" ASC
16963
+ LIMIT $${values.length}`,
16964
+ values
16965
+ };
16966
+ }
16967
+ function asIsoTimestamp$1(value) {
16968
+ if (value === null || value === void 0) throw new Error("Trace query returned a null timestamp");
16969
+ return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
16970
+ }
16971
+ function isPostgresStatementTimeout(error) {
16972
+ if (!error || typeof error !== "object") return false;
16973
+ const candidate = error;
16974
+ return candidate.code === "57014" && String(candidate.message ?? "").includes("statement timeout");
16975
+ }
16976
+ async function runWithPostgresTraceQueryTimeout(client, timeoutMs, execute) {
16977
+ const resolvedTimeoutMs = coreStorage.resolveTraceQueryTimeoutMs(timeoutMs);
16978
+ try {
16979
+ return await client.tx(async (transaction) => {
16980
+ await transaction.query(`SELECT set_config('statement_timeout', $1, true)`, [`${resolvedTimeoutMs}ms`]);
16981
+ return execute(transaction);
16982
+ });
16983
+ } catch (error) {
16984
+ if (isPostgresStatementTimeout(error)) throw new coreStorage.TraceQueryExecutionError();
16985
+ throw error;
16986
+ }
16987
+ }
16988
+ async function queryTraces(client, schema, plan, timeoutMs) {
16989
+ const query = compilePostgresTraceQuery(schema, plan);
16990
+ const rows = await runWithPostgresTraceQueryTimeout(client, timeoutMs, (transaction) => transaction.any(query.text, query.values));
16991
+ const visibleRows = rows.slice(0, plan.limit);
16992
+ if (plan.result === "groups") {
16993
+ const groups = visibleRows.map((row) => ({ threadId: String(row.threadId) }));
16994
+ const last = groups.at(-1);
16995
+ return coreStorage.traceQueryResponseSchema.parse({
16996
+ groups,
16997
+ page: { next: rows.length > plan.limit && last ? coreStorage.encodeTraceQueryCursor(plan, {
16998
+ result: "groups",
16999
+ threadId: last.threadId
17000
+ }) : null }
17001
+ });
17002
+ }
17003
+ const traces = visibleRows.map((row) => ({
17004
+ traceId: String(row.traceId),
17005
+ rootSpanId: String(row.rootSpanId),
17006
+ threadId: row.threadId == null ? null : String(row.threadId),
17007
+ resourceId: row.resourceId == null ? null : String(row.resourceId),
17008
+ startedAt: asIsoTimestamp$1(row.startedAt),
17009
+ endedAt: asIsoTimestamp$1(row.endedAt),
17010
+ entityName: row.entityName == null ? null : String(row.entityName),
17011
+ entityType: row.entityType == null ? null : String(row.entityType),
17012
+ environment: row.environment == null ? null : String(row.environment),
17013
+ status: row.status
17014
+ }));
17015
+ const last = traces.at(-1);
17016
+ return coreStorage.traceQueryResponseSchema.parse({
17017
+ traces,
17018
+ page: { next: rows.length > plan.limit && last ? coreStorage.encodeTraceQueryCursor(plan, {
17019
+ result: "traces",
17020
+ sortValue: last[plan.orderBy.field],
17021
+ traceId: last.traceId
17022
+ }) : null }
17023
+ });
17024
+ }
17025
+ //#endregion
16718
17026
  //#region src/storage/domains/observability/v-next/traces.ts
16719
17027
  /**
16720
17028
  * Trace / branch list reads for the v-next Postgres observability domain.
@@ -17364,11 +17672,39 @@ async function getTraceLight(client, schema, args) {
17364
17672
  spans: rows.map(rowToLightSpanRecord)
17365
17673
  };
17366
17674
  }
17675
+ /**
17676
+ * Delete traces by traceId, cascading to trace-linked signal events
17677
+ * (metrics, logs, scores, feedback). Signal rows with a NULL traceId are
17678
+ * never affected. When the optional tenant scope (`organizationId` /
17679
+ * `resourceId`) is set, every DELETE additionally requires the row's tenant
17680
+ * columns to match.
17681
+ */
17367
17682
  async function batchDeleteTraces(client, schema, args) {
17368
17683
  if (args.traceIds.length === 0) return;
17369
- const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
17684
+ const params = [...args.traceIds];
17370
17685
  const placeholders = args.traceIds.map((_, i) => `$${i + 1}`).join(", ");
17371
- await client.query(`DELETE FROM ${span} WHERE "traceId" IN (${placeholders})`, args.traceIds);
17686
+ let scopeCondition = "";
17687
+ if (args.organizationId !== void 0) {
17688
+ params.push(args.organizationId);
17689
+ scopeCondition += ` AND "organizationId" = $${params.length}`;
17690
+ }
17691
+ if (args.resourceId !== void 0) {
17692
+ params.push(args.resourceId);
17693
+ scopeCondition += ` AND "resourceId" = $${params.length}`;
17694
+ }
17695
+ const tables = [
17696
+ TABLE_SPAN_EVENTS,
17697
+ TABLE_METRIC_EVENTS,
17698
+ TABLE_LOG_EVENTS,
17699
+ TABLE_SCORE_EVENTS,
17700
+ TABLE_FEEDBACK_EVENTS
17701
+ ];
17702
+ await client.tx(async (t) => {
17703
+ for (const tableName of tables) {
17704
+ const table = qualifiedTable(schema, tableName);
17705
+ await t.query(`DELETE FROM ${table} WHERE "traceId" IN (${placeholders})${scopeCondition}`, params);
17706
+ }
17707
+ });
17372
17708
  }
17373
17709
  /** Truncate the span_events table. */
17374
17710
  async function dangerouslyClearTracing(client, schema) {
@@ -17401,7 +17737,7 @@ async function dangerouslyClearTracing(client, schema) {
17401
17737
  * Use it through `MastraCompositeStore` with a dedicated Postgres connection.
17402
17738
  */
17403
17739
  function wrapError(op, error, details) {
17404
- if (error instanceof MastraError) throw error;
17740
+ if (error instanceof MastraError || error instanceof coreStorage.TraceQueryExecutionError) throw error;
17405
17741
  throw new MastraError({
17406
17742
  id: createStorageErrorId("PG", op, "FAILED"),
17407
17743
  domain: ErrorDomain.STORAGE,
@@ -17414,6 +17750,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
17414
17750
  #schema;
17415
17751
  #partitioning;
17416
17752
  #discoveryConfig;
17753
+ #traceQueryTimeoutMs;
17417
17754
  #partitionMode;
17418
17755
  constructor(config) {
17419
17756
  super();
@@ -17422,6 +17759,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
17422
17759
  this.#schema = schemaName ?? "public";
17423
17760
  this.#partitioning = config.partitioning ?? {};
17424
17761
  this.#discoveryConfig = config.discovery ?? {};
17762
+ this.#traceQueryTimeoutMs = coreStorage.resolveTraceQueryTimeoutMs(config.traceQueryTimeoutMs);
17425
17763
  }
17426
17764
  /**
17427
17765
  * Build the discovery config used at each call site, with the framework
@@ -17573,11 +17911,16 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
17573
17911
  };
17574
17912
  }
17575
17913
  getFeatures() {
17576
- if (!deltaPollingFeatureEnabled()) return ["metrics", "logs"];
17914
+ if (!deltaPollingFeatureEnabled()) return [
17915
+ "metrics",
17916
+ "logs",
17917
+ "trace-query"
17918
+ ];
17577
17919
  return [
17578
17920
  "metrics",
17579
17921
  "logs",
17580
- "delta-polling"
17922
+ "delta-polling",
17923
+ "trace-query"
17581
17924
  ];
17582
17925
  }
17583
17926
  async #run(op, fn, details) {
@@ -17620,6 +17963,9 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
17620
17963
  async listTraces(args) {
17621
17964
  return this.#run("LIST_TRACES", () => listTraces(this.#client, this.#schema, args));
17622
17965
  }
17966
+ async queryTraces(plan) {
17967
+ return this.#run("QUERY_TRACES", () => queryTraces(this.#client, this.#schema, plan, this.#traceQueryTimeoutMs));
17968
+ }
17623
17969
  async listBranches(args) {
17624
17970
  return this.#run("LIST_BRANCHES", () => listBranches(this.#client, this.#schema, args));
17625
17971
  }
@@ -22819,7 +23165,8 @@ var PostgresStoreVNext = class extends PostgresStore {
22819
23165
  client: observabilityClient,
22820
23166
  schemaName: obsConfig.schemaName ?? config.schemaName,
22821
23167
  partitioning: obsConfig.partitioning,
22822
- discovery: obsConfig.discovery
23168
+ discovery: obsConfig.discovery,
23169
+ traceQueryTimeoutMs: obsConfig.traceQueryTimeoutMs
22823
23170
  });
22824
23171
  this.stores = {
22825
23172
  ...this.stores,