@mastra/pg 1.23.0 → 1.24.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
@@ -7084,6 +7084,12 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
7084
7084
  name: "idx_experiment_results_org_project",
7085
7085
  table: TABLE_EXPERIMENT_RESULTS,
7086
7086
  columns: ["organizationId", "projectId"]
7087
+ },
7088
+ {
7089
+ name: "idx_experiment_results_tags_gin",
7090
+ table: TABLE_EXPERIMENT_RESULTS,
7091
+ columns: ["tags"],
7092
+ method: "gin"
7087
7093
  }
7088
7094
  ];
7089
7095
  }
@@ -7692,6 +7698,10 @@ var ExperimentsPG = class ExperimentsPG extends ExperimentsStorage {
7692
7698
  conditions.push(`"status" = $${paramIndex++}`);
7693
7699
  queryParams.push(args.status);
7694
7700
  }
7701
+ for (const tag of args.tags ?? []) {
7702
+ conditions.push(`"tags" @> $${paramIndex++}::jsonb`);
7703
+ queryParams.push(JSON.stringify([tag]));
7704
+ }
7695
7705
  if (args.filters) {
7696
7706
  const { organizationId, projectId } = args.filters;
7697
7707
  if (organizationId !== void 0) {
@@ -11040,13 +11050,36 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
11040
11050
  * asked for a page after the last row, because there is then no row to carry the
11041
11051
  * count on.
11042
11052
  */
11043
- async #fetchMessagePage({ selectStatement, tableName, whereClause, orderByStatement, queryParams, perPageInput, perPage, offset }) {
11053
+ async #fetchMessagePage({ selectStatement, tableName, whereClause, orderByStatement, queryParams, perPageInput, perPage, offset, includeTotal = true }) {
11054
+ if (includeTotal === false && perPageInput !== false) {
11055
+ const peekLimit = perPage + 1;
11056
+ const rows = await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} LIMIT $${queryParams.length + 1} OFFSET $${queryParams.length + 2}`, [
11057
+ ...queryParams,
11058
+ peekLimit,
11059
+ offset
11060
+ ]) || [];
11061
+ const hasMore = rows.length > perPage;
11062
+ const messages = hasMore ? rows.slice(0, perPage) : rows;
11063
+ return {
11064
+ total: offset + messages.length,
11065
+ messages,
11066
+ hasMore
11067
+ };
11068
+ }
11044
11069
  const limitClause = perPageInput === false ? "" : ` LIMIT $${queryParams.length + 1} OFFSET $${queryParams.length + 2}`;
11045
11070
  const dataParams = perPageInput === false ? queryParams : [
11046
11071
  ...queryParams,
11047
11072
  perPage,
11048
11073
  offset
11049
11074
  ];
11075
+ if (includeTotal === false) {
11076
+ const rows = await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, dataParams) || [];
11077
+ return {
11078
+ total: rows.length,
11079
+ messages: rows,
11080
+ hasMore: false
11081
+ };
11082
+ }
11050
11083
  const rows = await this.#db.readClient.manyOrNone(`${selectStatement}, (SELECT COUNT(*) FROM ${tableName} ${whereClause}) AS "__total" FROM ${tableName} ${whereClause} ${orderByStatement}${limitClause}`, dataParams) || [];
11051
11084
  if (rows.length > 0) return {
11052
11085
  total: Number(rows[0].__total),
@@ -11063,7 +11096,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
11063
11096
  };
11064
11097
  }
11065
11098
  async listMessages(args) {
11066
- const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
11099
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy, includeTotal = true } = args;
11067
11100
  const threadIds = (Array.isArray(threadId) ? threadId : [threadId]).filter((id) => typeof id === "string");
11068
11101
  if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) throw new MastraError({
11069
11102
  id: createStorageErrorId("PG", "LIST_MESSAGES", "INVALID_THREAD_ID"),
@@ -11149,20 +11182,27 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
11149
11182
  }) : null;
11150
11183
  let total;
11151
11184
  let messages;
11185
+ let peekedHasMore;
11152
11186
  if (metadataFilter) {
11153
11187
  const filteredRows = (await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, queryParams) || []).filter((row) => storageMessageMatchesMetadataFilter(row.content, metadataFilter));
11154
11188
  total = filteredRows.length;
11155
11189
  messages = perPageInput === false ? filteredRows : filteredRows.slice(offset, offset + perPage);
11156
- } else ({total, messages} = await this.#fetchMessagePage({
11157
- selectStatement,
11158
- tableName,
11159
- whereClause,
11160
- orderByStatement,
11161
- queryParams,
11162
- perPageInput,
11163
- perPage,
11164
- offset
11165
- }));
11190
+ } else {
11191
+ const pageResult = await this.#fetchMessagePage({
11192
+ selectStatement,
11193
+ tableName,
11194
+ whereClause,
11195
+ orderByStatement,
11196
+ queryParams,
11197
+ perPageInput,
11198
+ perPage,
11199
+ offset,
11200
+ includeTotal
11201
+ });
11202
+ total = pageResult.total;
11203
+ messages = pageResult.messages;
11204
+ peekedHasMore = pageResult.hasMore;
11205
+ }
11166
11206
  const primaryPageCount = messages.length;
11167
11207
  if (total === 0 && messages.length === 0 && (!include || include.length === 0)) return {
11168
11208
  messages: [],
@@ -11187,7 +11227,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
11187
11227
  const finalMessages = this._sortMessages(list.get.all.db(), field, direction);
11188
11228
  const threadIdSet = new Set(threadIds);
11189
11229
  const allThreadMessagesReturned = new Set(finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)).size >= total;
11190
- const hasMore = metadataFilter ? perPageInput !== false && offset + primaryPageCount < total : perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
11230
+ const hasMore = peekedHasMore !== void 0 ? peekedHasMore : metadataFilter ? perPageInput !== false && offset + primaryPageCount < total : perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
11191
11231
  return {
11192
11232
  messages: finalMessages,
11193
11233
  total,
@@ -11212,7 +11252,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
11212
11252
  }
11213
11253
  }
11214
11254
  async listMessagesByResourceId(args) {
11215
- const { resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
11255
+ const { resourceId, include, filter, perPage: perPageInput, page = 0, orderBy, includeTotal = true } = args;
11216
11256
  if (!(resourceId !== void 0 && resourceId !== null && resourceId.trim() !== "")) throw new MastraError({
11217
11257
  id: createStorageErrorId("PG", "LIST_MESSAGES_BY_RESOURCE_ID", "INVALID_QUERY"),
11218
11258
  domain: ErrorDomain.STORAGE,
@@ -11295,20 +11335,27 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
11295
11335
  }) : null;
11296
11336
  let total;
11297
11337
  let messages;
11338
+ let peekedHasMore;
11298
11339
  if (metadataFilter) {
11299
11340
  const filteredRows = (await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, queryParams) || []).filter((row) => storageMessageMatchesMetadataFilter(row.content, metadataFilter));
11300
11341
  total = filteredRows.length;
11301
11342
  messages = perPageInput === false ? filteredRows : filteredRows.slice(offset, offset + perPage);
11302
- } else ({total, messages} = await this.#fetchMessagePage({
11303
- selectStatement,
11304
- tableName,
11305
- whereClause,
11306
- orderByStatement,
11307
- queryParams,
11308
- perPageInput,
11309
- perPage,
11310
- offset
11311
- }));
11343
+ } else {
11344
+ const pageResult = await this.#fetchMessagePage({
11345
+ selectStatement,
11346
+ tableName,
11347
+ whereClause,
11348
+ orderByStatement,
11349
+ queryParams,
11350
+ perPageInput,
11351
+ perPage,
11352
+ offset,
11353
+ includeTotal
11354
+ });
11355
+ total = pageResult.total;
11356
+ messages = pageResult.messages;
11357
+ peekedHasMore = pageResult.hasMore;
11358
+ }
11312
11359
  if (total === 0 && messages.length === 0 && (!include || include.length === 0)) return {
11313
11360
  messages: [],
11314
11361
  total: 0,
@@ -11330,7 +11377,7 @@ var MemoryPG = class MemoryPG extends MemoryStorage {
11330
11377
  const messagesWithParsedContent = messages.map((row) => this.parseRow(row));
11331
11378
  const list = new MessageList().add(messagesWithParsedContent, "memory");
11332
11379
  const finalMessages = this._sortMessages(list.get.all.db(), field, direction);
11333
- const hasMore = perPageInput !== false && offset + perPage < total;
11380
+ const hasMore = peekedHasMore !== void 0 ? peekedHasMore : perPageInput !== false && offset + perPage < total;
11334
11381
  return {
11335
11382
  messages: finalMessages,
11336
11383
  total,
@@ -17020,12 +17067,32 @@ const TRACE_FIELDS = {
17020
17067
  status: TRACE_STATUS_SQL
17021
17068
  };
17022
17069
  const SPAN_FIELDS = {
17070
+ name: "s.\"name\"",
17023
17071
  spanType: "s.\"spanType\"",
17024
- error: "s.\"error\""
17072
+ model: "s.\"model\"",
17073
+ provider: "s.\"provider\"",
17074
+ startedAt: "s.\"startedAt\"",
17075
+ endedAt: "s.\"endedAt\"",
17076
+ durationMs: "s.\"durationMs\"",
17077
+ status: "s.\"status\"",
17078
+ error: "s.\"error\"",
17079
+ entityType: "s.\"entityType\"",
17080
+ entityId: "s.\"entityId\"",
17081
+ entityName: "s.\"entityName\"",
17082
+ entityVersionId: "s.\"entityVersionId\"",
17083
+ parentEntityVersionId: "s.\"parentEntityVersionId\"",
17084
+ rootEntityVersionId: "s.\"rootEntityVersionId\""
17025
17085
  };
17026
17086
  const SCORE_FIELDS = {
17027
17087
  scorerId: "s.\"scorerId\"",
17028
- score: "s.\"score\""
17088
+ scorerVersion: "s.\"scorerVersion\"",
17089
+ scoreSource: "s.\"scoreSource\"",
17090
+ score: "s.\"score\"",
17091
+ timestamp: "s.\"timestamp\"",
17092
+ spanId: "s.\"spanId\"",
17093
+ entityVersionId: "s.\"entityVersionId\"",
17094
+ parentEntityVersionId: "s.\"parentEntityVersionId\"",
17095
+ rootEntityVersionId: "s.\"rootEntityVersionId\""
17029
17096
  };
17030
17097
  const TRACE_SELECT = `
17031
17098
  r."traceId" AS "traceId",
@@ -17043,15 +17110,18 @@ function fieldSql(registry, field) {
17043
17110
  if (sql === void 0) throw new Error(`Unsupported trusted trace-query field: ${field}`);
17044
17111
  return sql;
17045
17112
  }
17113
+ function isMetadataField(field) {
17114
+ return field.startsWith("metadata.");
17115
+ }
17046
17116
  function placeholders(values, offset) {
17047
17117
  return values.map((_, index) => `$${offset + index}`).join(", ");
17048
17118
  }
17049
- function compileScalarPredicate(predicate, registry, parameterOffset) {
17119
+ function compileScalarPredicate(predicate, registry, parameterOffset, allowMetadata = false) {
17050
17120
  if (predicate.type === "boolean") {
17051
17121
  const values = [];
17052
17122
  return {
17053
17123
  sql: predicate.args.map((arg) => {
17054
- const compiled = compileScalarPredicate(arg, registry, parameterOffset + values.length);
17124
+ const compiled = compileScalarPredicate(arg, registry, parameterOffset + values.length, allowMetadata);
17055
17125
  values.push(...compiled.values);
17056
17126
  return `(${compiled.sql})`;
17057
17127
  }).join(predicate.operator === "and" ? " AND " : " OR "),
@@ -17059,26 +17129,36 @@ function compileScalarPredicate(predicate, registry, parameterOffset) {
17059
17129
  };
17060
17130
  }
17061
17131
  if (predicate.type === "not") {
17062
- const compiled = compileScalarPredicate(predicate.arg, registry, parameterOffset);
17132
+ const compiled = compileScalarPredicate(predicate.arg, registry, parameterOffset, allowMetadata);
17063
17133
  return {
17064
17134
  sql: `NOT (${compiled.sql})`,
17065
17135
  values: compiled.values
17066
17136
  };
17067
17137
  }
17068
- const field = fieldSql(registry, predicate.field);
17138
+ let field;
17139
+ let fieldValues = [];
17140
+ if (isMetadataField(predicate.field)) {
17141
+ if (!allowMetadata) throw new Error(`Unsupported trusted trace-query field: ${predicate.field}`);
17142
+ const keyParameter = `$${parameterOffset++}`;
17143
+ field = `COALESCE(
17144
+ CASE WHEN jsonb_typeof(r."metadataSearch" -> ${keyParameter}) = 'string' THEN r."metadataSearch" ->> ${keyParameter} END,
17145
+ CASE WHEN jsonb_typeof(r."metadataRaw" -> ${keyParameter}) = 'string' THEN NULLIF(btrim(r."metadataRaw" ->> ${keyParameter}), '') END
17146
+ )`;
17147
+ fieldValues = [predicate.field.slice(9)];
17148
+ } else field = fieldSql(registry, predicate.field);
17069
17149
  if (predicate.type === "presence") return {
17070
17150
  sql: `${field} IS ${predicate.operator === "exists" ? "NOT " : ""}NULL`,
17071
- values: []
17151
+ values: fieldValues
17072
17152
  };
17073
17153
  if (predicate.type === "membership") {
17074
17154
  const list = placeholders(predicate.values, parameterOffset);
17075
17155
  if (predicate.operator === "in") return {
17076
17156
  sql: `${field} IS NOT NULL AND ${field} IN (${list})`,
17077
- values: predicate.values
17157
+ values: [...fieldValues, ...predicate.values]
17078
17158
  };
17079
17159
  return {
17080
17160
  sql: `${field} IS NULL OR ${field} NOT IN (${list})`,
17081
- values: predicate.values
17161
+ values: [...fieldValues, ...predicate.values]
17082
17162
  };
17083
17163
  }
17084
17164
  const parameter = `$${parameterOffset}`;
@@ -17090,17 +17170,17 @@ function compileScalarPredicate(predicate, registry, parameterOffset) {
17090
17170
  };
17091
17171
  if (predicate.operator === "eq") return {
17092
17172
  sql: `${field} IS NOT DISTINCT FROM ${parameter}`,
17093
- values: [predicate.value]
17173
+ values: [...fieldValues, predicate.value]
17094
17174
  };
17095
17175
  if (predicate.operator === "ne") return {
17096
17176
  sql: `${field} IS DISTINCT FROM ${parameter}`,
17097
- values: [predicate.value]
17177
+ values: [...fieldValues, predicate.value]
17098
17178
  };
17099
17179
  const operator = operators[predicate.operator];
17100
17180
  if (operator === void 0) throw new Error(`Unsupported trusted trace-query operator: ${predicate.operator}`);
17101
17181
  return {
17102
17182
  sql: `${field} IS NOT NULL AND ${field} ${operator} ${parameter}`,
17103
- values: [predicate.value]
17183
+ values: [...fieldValues, predicate.value]
17104
17184
  };
17105
17185
  }
17106
17186
  function latestRootPredicate$1(spanTable) {
@@ -17165,7 +17245,7 @@ function compilePredicate(predicate, parameterOffset) {
17165
17245
  values: compiled.values
17166
17246
  };
17167
17247
  }
17168
- return compileScalarPredicate(predicate, TRACE_FIELDS, parameterOffset);
17248
+ return compileScalarPredicate(predicate, TRACE_FIELDS, parameterOffset, true);
17169
17249
  }
17170
17250
  function compilePostgresTraceQuery(schema, plan) {
17171
17251
  const spanTable = qualifiedTable(schema, TABLE_SPAN_EVENTS);
@@ -17185,14 +17265,43 @@ function compilePostgresTraceQuery(schema, plan) {
17185
17265
  ].join("\n AND ")}
17186
17266
  )`];
17187
17267
  if (relationCollections.has("spans")) ctes.push(`current_spans AS MATERIALIZED (
17188
- SELECT s."traceId", s."spanType", s."error"
17268
+ SELECT
17269
+ s."traceId",
17270
+ s."name",
17271
+ s."spanType",
17272
+ CASE WHEN jsonb_typeof(s."attributes" -> 'model') = 'string' THEN s."attributes" ->> 'model' END AS "model",
17273
+ CASE WHEN jsonb_typeof(s."attributes" -> 'provider') = 'string' THEN s."attributes" ->> 'provider' END AS "provider",
17274
+ s."startedAt",
17275
+ CASE WHEN s."isPending" THEN NULL ELSE s."endedAt" END AS "endedAt",
17276
+ CASE
17277
+ WHEN s."isPending" THEN NULL
17278
+ ELSE EXTRACT(EPOCH FROM (s."endedAt" - s."startedAt")) * 1000
17279
+ END AS "durationMs",
17280
+ CASE WHEN s."error" IS NOT NULL THEN 'error' ELSE 'success' END AS "status",
17281
+ s."error",
17282
+ s."entityType",
17283
+ s."entityId",
17284
+ s."entityName",
17285
+ s."entityVersionId",
17286
+ s."parentEntityVersionId",
17287
+ s."rootEntityVersionId"
17189
17288
  FROM ${spanTable} s
17190
17289
  WHERE s."traceId" IS NOT NULL
17191
17290
  AND s."traceId" IN (SELECT "traceId" FROM root_scope)
17192
17291
  AND ${latestSpanPredicate$1(spanTable)}
17193
17292
  )`);
17194
17293
  if (relationCollections.has("scores")) ctes.push(`current_scores AS MATERIALIZED (
17195
- SELECT s."traceId", s."scorerId", s."score"
17294
+ SELECT
17295
+ s."traceId",
17296
+ s."spanId",
17297
+ s."timestamp",
17298
+ s."scorerId",
17299
+ s."scorerVersion",
17300
+ s."scoreSource",
17301
+ s."score",
17302
+ s."entityVersionId",
17303
+ s."parentEntityVersionId",
17304
+ s."rootEntityVersionId"
17196
17305
  FROM ${scoreTable} s
17197
17306
  WHERE s."traceId" IS NOT NULL
17198
17307
  AND s."traceId" IN (SELECT "traceId" FROM root_scope)