@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.
@@ -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.23.0"
6
+ version: "1.24.0-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.23.0",
2
+ "version": "1.24.0-alpha.1",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -650,7 +650,7 @@ Key metadata considerations:
650
650
 
651
651
  ## Deleting vectors
652
652
 
653
- When building RAG applications, you often need to clean up stale vectors when documents are deleted or updated. Mastra provides the `deleteVectors` method that supports deleting vectors by metadata filters, making it straightforward to remove all embeddings associated with a specific document.
653
+ Use `deleteVectors` with a metadata filter to remove embeddings associated with a document. This is useful for cleaning up stale vectors after a document is deleted or updated.
654
654
 
655
655
  ### Delete by Metadata Filter
656
656
 
package/dist/index.cjs CHANGED
@@ -7108,6 +7108,12 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
7108
7108
  name: "idx_experiment_results_org_project",
7109
7109
  table: _mastra_core_storage.TABLE_EXPERIMENT_RESULTS,
7110
7110
  columns: ["organizationId", "projectId"]
7111
+ },
7112
+ {
7113
+ name: "idx_experiment_results_tags_gin",
7114
+ table: _mastra_core_storage.TABLE_EXPERIMENT_RESULTS,
7115
+ columns: ["tags"],
7116
+ method: "gin"
7111
7117
  }
7112
7118
  ];
7113
7119
  }
@@ -7716,6 +7722,10 @@ var ExperimentsPG = class ExperimentsPG extends _mastra_core_storage.Experiments
7716
7722
  conditions.push(`"status" = $${paramIndex++}`);
7717
7723
  queryParams.push(args.status);
7718
7724
  }
7725
+ for (const tag of args.tags ?? []) {
7726
+ conditions.push(`"tags" @> $${paramIndex++}::jsonb`);
7727
+ queryParams.push(JSON.stringify([tag]));
7728
+ }
7719
7729
  if (args.filters) {
7720
7730
  const { organizationId, projectId } = args.filters;
7721
7731
  if (organizationId !== void 0) {
@@ -11064,13 +11074,36 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11064
11074
  * asked for a page after the last row, because there is then no row to carry the
11065
11075
  * count on.
11066
11076
  */
11067
- async #fetchMessagePage({ selectStatement, tableName, whereClause, orderByStatement, queryParams, perPageInput, perPage, offset }) {
11077
+ async #fetchMessagePage({ selectStatement, tableName, whereClause, orderByStatement, queryParams, perPageInput, perPage, offset, includeTotal = true }) {
11078
+ if (includeTotal === false && perPageInput !== false) {
11079
+ const peekLimit = perPage + 1;
11080
+ const rows = await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} LIMIT $${queryParams.length + 1} OFFSET $${queryParams.length + 2}`, [
11081
+ ...queryParams,
11082
+ peekLimit,
11083
+ offset
11084
+ ]) || [];
11085
+ const hasMore = rows.length > perPage;
11086
+ const messages = hasMore ? rows.slice(0, perPage) : rows;
11087
+ return {
11088
+ total: offset + messages.length,
11089
+ messages,
11090
+ hasMore
11091
+ };
11092
+ }
11068
11093
  const limitClause = perPageInput === false ? "" : ` LIMIT $${queryParams.length + 1} OFFSET $${queryParams.length + 2}`;
11069
11094
  const dataParams = perPageInput === false ? queryParams : [
11070
11095
  ...queryParams,
11071
11096
  perPage,
11072
11097
  offset
11073
11098
  ];
11099
+ if (includeTotal === false) {
11100
+ const rows = await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, dataParams) || [];
11101
+ return {
11102
+ total: rows.length,
11103
+ messages: rows,
11104
+ hasMore: false
11105
+ };
11106
+ }
11074
11107
  const rows = await this.#db.readClient.manyOrNone(`${selectStatement}, (SELECT COUNT(*) FROM ${tableName} ${whereClause}) AS "__total" FROM ${tableName} ${whereClause} ${orderByStatement}${limitClause}`, dataParams) || [];
11075
11108
  if (rows.length > 0) return {
11076
11109
  total: Number(rows[0].__total),
@@ -11087,7 +11120,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11087
11120
  };
11088
11121
  }
11089
11122
  async listMessages(args) {
11090
- const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
11123
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy, includeTotal = true } = args;
11091
11124
  const threadIds = (Array.isArray(threadId) ? threadId : [threadId]).filter((id) => typeof id === "string");
11092
11125
  if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) throw new _mastra_core_error.MastraError({
11093
11126
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "LIST_MESSAGES", "INVALID_THREAD_ID"),
@@ -11173,20 +11206,27 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11173
11206
  }) : null;
11174
11207
  let total;
11175
11208
  let messages;
11209
+ let peekedHasMore;
11176
11210
  if (metadataFilter) {
11177
11211
  const filteredRows = (await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, queryParams) || []).filter((row) => (0, _mastra_core_storage.storageMessageMatchesMetadataFilter)(row.content, metadataFilter));
11178
11212
  total = filteredRows.length;
11179
11213
  messages = perPageInput === false ? filteredRows : filteredRows.slice(offset, offset + perPage);
11180
- } else ({total, messages} = await this.#fetchMessagePage({
11181
- selectStatement,
11182
- tableName,
11183
- whereClause,
11184
- orderByStatement,
11185
- queryParams,
11186
- perPageInput,
11187
- perPage,
11188
- offset
11189
- }));
11214
+ } else {
11215
+ const pageResult = await this.#fetchMessagePage({
11216
+ selectStatement,
11217
+ tableName,
11218
+ whereClause,
11219
+ orderByStatement,
11220
+ queryParams,
11221
+ perPageInput,
11222
+ perPage,
11223
+ offset,
11224
+ includeTotal
11225
+ });
11226
+ total = pageResult.total;
11227
+ messages = pageResult.messages;
11228
+ peekedHasMore = pageResult.hasMore;
11229
+ }
11190
11230
  const primaryPageCount = messages.length;
11191
11231
  if (total === 0 && messages.length === 0 && (!include || include.length === 0)) return {
11192
11232
  messages: [],
@@ -11211,7 +11251,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11211
11251
  const finalMessages = this._sortMessages(list.get.all.db(), field, direction);
11212
11252
  const threadIdSet = new Set(threadIds);
11213
11253
  const allThreadMessagesReturned = new Set(finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)).size >= total;
11214
- const hasMore = metadataFilter ? perPageInput !== false && offset + primaryPageCount < total : perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
11254
+ const hasMore = peekedHasMore !== void 0 ? peekedHasMore : metadataFilter ? perPageInput !== false && offset + primaryPageCount < total : perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
11215
11255
  return {
11216
11256
  messages: finalMessages,
11217
11257
  total,
@@ -11236,7 +11276,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11236
11276
  }
11237
11277
  }
11238
11278
  async listMessagesByResourceId(args) {
11239
- const { resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
11279
+ const { resourceId, include, filter, perPage: perPageInput, page = 0, orderBy, includeTotal = true } = args;
11240
11280
  if (!(resourceId !== void 0 && resourceId !== null && resourceId.trim() !== "")) throw new _mastra_core_error.MastraError({
11241
11281
  id: (0, _mastra_core_storage.createStorageErrorId)("PG", "LIST_MESSAGES_BY_RESOURCE_ID", "INVALID_QUERY"),
11242
11282
  domain: _mastra_core_error.ErrorDomain.STORAGE,
@@ -11319,20 +11359,27 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11319
11359
  }) : null;
11320
11360
  let total;
11321
11361
  let messages;
11362
+ let peekedHasMore;
11322
11363
  if (metadataFilter) {
11323
11364
  const filteredRows = (await this.#db.readClient.manyOrNone(`${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement}`, queryParams) || []).filter((row) => (0, _mastra_core_storage.storageMessageMatchesMetadataFilter)(row.content, metadataFilter));
11324
11365
  total = filteredRows.length;
11325
11366
  messages = perPageInput === false ? filteredRows : filteredRows.slice(offset, offset + perPage);
11326
- } else ({total, messages} = await this.#fetchMessagePage({
11327
- selectStatement,
11328
- tableName,
11329
- whereClause,
11330
- orderByStatement,
11331
- queryParams,
11332
- perPageInput,
11333
- perPage,
11334
- offset
11335
- }));
11367
+ } else {
11368
+ const pageResult = await this.#fetchMessagePage({
11369
+ selectStatement,
11370
+ tableName,
11371
+ whereClause,
11372
+ orderByStatement,
11373
+ queryParams,
11374
+ perPageInput,
11375
+ perPage,
11376
+ offset,
11377
+ includeTotal
11378
+ });
11379
+ total = pageResult.total;
11380
+ messages = pageResult.messages;
11381
+ peekedHasMore = pageResult.hasMore;
11382
+ }
11336
11383
  if (total === 0 && messages.length === 0 && (!include || include.length === 0)) return {
11337
11384
  messages: [],
11338
11385
  total: 0,
@@ -11354,7 +11401,7 @@ var MemoryPG = class MemoryPG extends _mastra_core_storage.MemoryStorage {
11354
11401
  const messagesWithParsedContent = messages.map((row) => this.parseRow(row));
11355
11402
  const list = new _mastra_core_agent.MessageList().add(messagesWithParsedContent, "memory");
11356
11403
  const finalMessages = this._sortMessages(list.get.all.db(), field, direction);
11357
- const hasMore = perPageInput !== false && offset + perPage < total;
11404
+ const hasMore = peekedHasMore !== void 0 ? peekedHasMore : perPageInput !== false && offset + perPage < total;
11358
11405
  return {
11359
11406
  messages: finalMessages,
11360
11407
  total,
@@ -17044,12 +17091,32 @@ const TRACE_FIELDS = {
17044
17091
  status: TRACE_STATUS_SQL
17045
17092
  };
17046
17093
  const SPAN_FIELDS = {
17094
+ name: "s.\"name\"",
17047
17095
  spanType: "s.\"spanType\"",
17048
- error: "s.\"error\""
17096
+ model: "s.\"model\"",
17097
+ provider: "s.\"provider\"",
17098
+ startedAt: "s.\"startedAt\"",
17099
+ endedAt: "s.\"endedAt\"",
17100
+ durationMs: "s.\"durationMs\"",
17101
+ status: "s.\"status\"",
17102
+ error: "s.\"error\"",
17103
+ entityType: "s.\"entityType\"",
17104
+ entityId: "s.\"entityId\"",
17105
+ entityName: "s.\"entityName\"",
17106
+ entityVersionId: "s.\"entityVersionId\"",
17107
+ parentEntityVersionId: "s.\"parentEntityVersionId\"",
17108
+ rootEntityVersionId: "s.\"rootEntityVersionId\""
17049
17109
  };
17050
17110
  const SCORE_FIELDS = {
17051
17111
  scorerId: "s.\"scorerId\"",
17052
- score: "s.\"score\""
17112
+ scorerVersion: "s.\"scorerVersion\"",
17113
+ scoreSource: "s.\"scoreSource\"",
17114
+ score: "s.\"score\"",
17115
+ timestamp: "s.\"timestamp\"",
17116
+ spanId: "s.\"spanId\"",
17117
+ entityVersionId: "s.\"entityVersionId\"",
17118
+ parentEntityVersionId: "s.\"parentEntityVersionId\"",
17119
+ rootEntityVersionId: "s.\"rootEntityVersionId\""
17053
17120
  };
17054
17121
  const TRACE_SELECT = `
17055
17122
  r."traceId" AS "traceId",
@@ -17067,15 +17134,18 @@ function fieldSql(registry, field) {
17067
17134
  if (sql === void 0) throw new Error(`Unsupported trusted trace-query field: ${field}`);
17068
17135
  return sql;
17069
17136
  }
17137
+ function isMetadataField(field) {
17138
+ return field.startsWith("metadata.");
17139
+ }
17070
17140
  function placeholders(values, offset) {
17071
17141
  return values.map((_, index) => `$${offset + index}`).join(", ");
17072
17142
  }
17073
- function compileScalarPredicate(predicate, registry, parameterOffset) {
17143
+ function compileScalarPredicate(predicate, registry, parameterOffset, allowMetadata = false) {
17074
17144
  if (predicate.type === "boolean") {
17075
17145
  const values = [];
17076
17146
  return {
17077
17147
  sql: predicate.args.map((arg) => {
17078
- const compiled = compileScalarPredicate(arg, registry, parameterOffset + values.length);
17148
+ const compiled = compileScalarPredicate(arg, registry, parameterOffset + values.length, allowMetadata);
17079
17149
  values.push(...compiled.values);
17080
17150
  return `(${compiled.sql})`;
17081
17151
  }).join(predicate.operator === "and" ? " AND " : " OR "),
@@ -17083,26 +17153,36 @@ function compileScalarPredicate(predicate, registry, parameterOffset) {
17083
17153
  };
17084
17154
  }
17085
17155
  if (predicate.type === "not") {
17086
- const compiled = compileScalarPredicate(predicate.arg, registry, parameterOffset);
17156
+ const compiled = compileScalarPredicate(predicate.arg, registry, parameterOffset, allowMetadata);
17087
17157
  return {
17088
17158
  sql: `NOT (${compiled.sql})`,
17089
17159
  values: compiled.values
17090
17160
  };
17091
17161
  }
17092
- const field = fieldSql(registry, predicate.field);
17162
+ let field;
17163
+ let fieldValues = [];
17164
+ if (isMetadataField(predicate.field)) {
17165
+ if (!allowMetadata) throw new Error(`Unsupported trusted trace-query field: ${predicate.field}`);
17166
+ const keyParameter = `$${parameterOffset++}`;
17167
+ field = `COALESCE(
17168
+ CASE WHEN jsonb_typeof(r."metadataSearch" -> ${keyParameter}) = 'string' THEN r."metadataSearch" ->> ${keyParameter} END,
17169
+ CASE WHEN jsonb_typeof(r."metadataRaw" -> ${keyParameter}) = 'string' THEN NULLIF(btrim(r."metadataRaw" ->> ${keyParameter}), '') END
17170
+ )`;
17171
+ fieldValues = [predicate.field.slice(9)];
17172
+ } else field = fieldSql(registry, predicate.field);
17093
17173
  if (predicate.type === "presence") return {
17094
17174
  sql: `${field} IS ${predicate.operator === "exists" ? "NOT " : ""}NULL`,
17095
- values: []
17175
+ values: fieldValues
17096
17176
  };
17097
17177
  if (predicate.type === "membership") {
17098
17178
  const list = placeholders(predicate.values, parameterOffset);
17099
17179
  if (predicate.operator === "in") return {
17100
17180
  sql: `${field} IS NOT NULL AND ${field} IN (${list})`,
17101
- values: predicate.values
17181
+ values: [...fieldValues, ...predicate.values]
17102
17182
  };
17103
17183
  return {
17104
17184
  sql: `${field} IS NULL OR ${field} NOT IN (${list})`,
17105
- values: predicate.values
17185
+ values: [...fieldValues, ...predicate.values]
17106
17186
  };
17107
17187
  }
17108
17188
  const parameter = `$${parameterOffset}`;
@@ -17114,17 +17194,17 @@ function compileScalarPredicate(predicate, registry, parameterOffset) {
17114
17194
  };
17115
17195
  if (predicate.operator === "eq") return {
17116
17196
  sql: `${field} IS NOT DISTINCT FROM ${parameter}`,
17117
- values: [predicate.value]
17197
+ values: [...fieldValues, predicate.value]
17118
17198
  };
17119
17199
  if (predicate.operator === "ne") return {
17120
17200
  sql: `${field} IS DISTINCT FROM ${parameter}`,
17121
- values: [predicate.value]
17201
+ values: [...fieldValues, predicate.value]
17122
17202
  };
17123
17203
  const operator = operators[predicate.operator];
17124
17204
  if (operator === void 0) throw new Error(`Unsupported trusted trace-query operator: ${predicate.operator}`);
17125
17205
  return {
17126
17206
  sql: `${field} IS NOT NULL AND ${field} ${operator} ${parameter}`,
17127
- values: [predicate.value]
17207
+ values: [...fieldValues, predicate.value]
17128
17208
  };
17129
17209
  }
17130
17210
  function latestRootPredicate$1(spanTable) {
@@ -17189,7 +17269,7 @@ function compilePredicate(predicate, parameterOffset) {
17189
17269
  values: compiled.values
17190
17270
  };
17191
17271
  }
17192
- return compileScalarPredicate(predicate, TRACE_FIELDS, parameterOffset);
17272
+ return compileScalarPredicate(predicate, TRACE_FIELDS, parameterOffset, true);
17193
17273
  }
17194
17274
  function compilePostgresTraceQuery(schema, plan) {
17195
17275
  const spanTable = qualifiedTable(schema, TABLE_SPAN_EVENTS);
@@ -17209,14 +17289,43 @@ function compilePostgresTraceQuery(schema, plan) {
17209
17289
  ].join("\n AND ")}
17210
17290
  )`];
17211
17291
  if (relationCollections.has("spans")) ctes.push(`current_spans AS MATERIALIZED (
17212
- SELECT s."traceId", s."spanType", s."error"
17292
+ SELECT
17293
+ s."traceId",
17294
+ s."name",
17295
+ s."spanType",
17296
+ CASE WHEN jsonb_typeof(s."attributes" -> 'model') = 'string' THEN s."attributes" ->> 'model' END AS "model",
17297
+ CASE WHEN jsonb_typeof(s."attributes" -> 'provider') = 'string' THEN s."attributes" ->> 'provider' END AS "provider",
17298
+ s."startedAt",
17299
+ CASE WHEN s."isPending" THEN NULL ELSE s."endedAt" END AS "endedAt",
17300
+ CASE
17301
+ WHEN s."isPending" THEN NULL
17302
+ ELSE EXTRACT(EPOCH FROM (s."endedAt" - s."startedAt")) * 1000
17303
+ END AS "durationMs",
17304
+ CASE WHEN s."error" IS NOT NULL THEN 'error' ELSE 'success' END AS "status",
17305
+ s."error",
17306
+ s."entityType",
17307
+ s."entityId",
17308
+ s."entityName",
17309
+ s."entityVersionId",
17310
+ s."parentEntityVersionId",
17311
+ s."rootEntityVersionId"
17213
17312
  FROM ${spanTable} s
17214
17313
  WHERE s."traceId" IS NOT NULL
17215
17314
  AND s."traceId" IN (SELECT "traceId" FROM root_scope)
17216
17315
  AND ${latestSpanPredicate$1(spanTable)}
17217
17316
  )`);
17218
17317
  if (relationCollections.has("scores")) ctes.push(`current_scores AS MATERIALIZED (
17219
- SELECT s."traceId", s."scorerId", s."score"
17318
+ SELECT
17319
+ s."traceId",
17320
+ s."spanId",
17321
+ s."timestamp",
17322
+ s."scorerId",
17323
+ s."scorerVersion",
17324
+ s."scoreSource",
17325
+ s."score",
17326
+ s."entityVersionId",
17327
+ s."parentEntityVersionId",
17328
+ s."rootEntityVersionId"
17220
17329
  FROM ${scoreTable} s
17221
17330
  WHERE s."traceId" IS NOT NULL
17222
17331
  AND s."traceId" IN (SELECT "traceId" FROM root_scope)