@mastra/pg 1.31.3-alpha.0 → 1.32.0-alpha.2

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.31.3-alpha.0"
6
+ version: "1.32.0-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.31.3-alpha.0",
2
+ "version": "1.32.0-alpha.2",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -403,6 +403,8 @@ Memory uses a single embedder for both storing and recalling messages, so pick o
403
403
 
404
404
  Multilingual E5 produces 1024-dimensional vectors. Your vector index must be created with matching dimensions, and E5 vectors can't be mixed with vectors from another embedder in the same index.
405
405
 
406
+ FastEmbed models embed at most 512 tokens per input (roughly 2,000 to 2,500 characters of English text). Longer inputs are truncated, so text past the limit doesn't affect the embedding and can't be found by semantic recall. The AI SDK v3 FastEmbed models return a warning when this happens. The legacy v1 and v2 models don't. If you embed long documents with FastEmbed, chunk them to fit the window, for example with `maxSize: 1500` in `MDocument.chunk()`.
407
+
406
408
  ## PostgreSQL index optimization
407
409
 
408
410
  When using PostgreSQL as your vector store, you can optimize semantic recall performance by configuring the vector index. This is particularly important for large-scale deployments with thousands of messages.
package/dist/index.cjs CHANGED
@@ -6327,7 +6327,11 @@ var DatasetsPG = class DatasetsPG extends _mastra_core_storage.DatasetsStorage {
6327
6327
  const queryParams = [];
6328
6328
  let paramIndex = 1;
6329
6329
  if (args.filters) {
6330
- const { organizationId, projectId, candidateKey, candidateId, targetType, targetIds, name } = args.filters;
6330
+ const { organizationId, projectId, candidateKey, candidateId, targetType, targetIds, datasetIds, name } = args.filters;
6331
+ if (datasetIds !== void 0) {
6332
+ conditions.push(`"id" = ANY($${paramIndex++}::text[])`);
6333
+ queryParams.push(datasetIds);
6334
+ }
6331
6335
  if (organizationId !== void 0) {
6332
6336
  conditions.push(`"organizationId" = $${paramIndex++}`);
6333
6337
  queryParams.push(organizationId);
@@ -16030,6 +16034,11 @@ const SPAN_EVENT_COLUMNS = [
16030
16034
  name: "endedAt",
16031
16035
  type: "timestamptz"
16032
16036
  },
16037
+ {
16038
+ name: "timeToFirstChunkMs",
16039
+ type: "double precision",
16040
+ nullable: true
16041
+ },
16033
16042
  {
16034
16043
  name: "tags",
16035
16044
  type: "text[]",
@@ -16764,6 +16773,11 @@ function additiveColumns(schema) {
16764
16773
  column,
16765
16774
  ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "${column}" text`
16766
16775
  })),
16776
+ {
16777
+ table: TABLE_SPAN_EVENTS,
16778
+ column: "timeToFirstChunkMs",
16779
+ ddl: `ALTER TABLE ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} ADD COLUMN IF NOT EXISTS "timeToFirstChunkMs" double precision`
16780
+ },
16767
16781
  {
16768
16782
  table: TABLE_FEEDBACK_EVENTS,
16769
16783
  column: "reviewStatus",
@@ -17118,9 +17132,27 @@ function readPreview(preview, payload, jsonEncoded = false) {
17118
17132
  }
17119
17133
  /** Older response builders may shorten previews or turn empty strings into null. */
17120
17134
  function buildSpanQueryResponse(...args) {
17121
- if (canGeneratePreviews) return _mastra_core_storage.buildSpanQueryResponse(...args);
17122
- const [plan, selected, payloads, metrics] = args;
17123
- const response = _mastra_core_storage.buildSpanQueryResponse(plan, selected, [], metrics);
17135
+ const [plan, selected, payloads, metrics = []] = args;
17136
+ const compatibleSelected = _mastra_core_storage.SPAN_QUERY_FIELD_REGISTRY ? selected : selected.map((row) => ({
17137
+ organizationId: row.organizationId,
17138
+ resourceId: row.resourceId,
17139
+ traceId: row.traceId,
17140
+ spanId: row.spanId,
17141
+ parentSpanId: row.parentSpanId,
17142
+ name: row.name,
17143
+ spanType: row.spanType,
17144
+ status: row.status,
17145
+ startedAt: row.startedAt,
17146
+ endedAt: row.endedAt,
17147
+ durationMs: row.durationMs,
17148
+ entityType: row.entityType,
17149
+ entityId: row.entityId,
17150
+ entityName: row.entityName,
17151
+ model: row.model,
17152
+ provider: row.provider
17153
+ }));
17154
+ if (canGeneratePreviews) return _mastra_core_storage.buildSpanQueryResponse(plan, compatibleSelected, payloads, metrics);
17155
+ const response = _mastra_core_storage.buildSpanQueryResponse(plan, compatibleSelected, [], metrics);
17124
17156
  const byIdentity = new Map(payloads.map((payload) => [_mastra_core_storage.spanQueryIdentityKey(payload), payload]));
17125
17157
  for (const span of response.spans) {
17126
17158
  const payload = byIdentity.get(_mastra_core_storage.spanQueryIdentityKey(span));
@@ -17467,6 +17499,7 @@ function spanRecordToRow(span) {
17467
17499
  isPending,
17468
17500
  startedAt: toIsoOrDate(span.startedAt),
17469
17501
  endedAt: toIsoOrDate(endedAt),
17502
+ timeToFirstChunkMs: span.timeToFirstChunkMs ?? null,
17470
17503
  tags: normalizeTags(span.tags),
17471
17504
  metadataSearch: buildMetadataSearch(metadata),
17472
17505
  metadataRaw: jsonField(metadata),
@@ -18390,6 +18423,7 @@ async function listLogsDelta(client, table, filters, after, limit) {
18390
18423
  function applyMetricFilters(acc, filters) {
18391
18424
  applyCommonFilters(acc, filters);
18392
18425
  applySingleOrArrayFilter(acc, "traceId", filters?.traceIds);
18426
+ applySingleOrArrayFilter(acc, "experimentId", filters?.experimentIds);
18393
18427
  applySingleOrArrayFilter(acc, "name", filters?.name);
18394
18428
  applySingleOrArrayFilter(acc, "provider", filters?.provider);
18395
18429
  applySingleOrArrayFilter(acc, "model", filters?.model);
@@ -19216,6 +19250,25 @@ const SPAN_FIELDS = {
19216
19250
  userId: "s.\"userId\"",
19217
19251
  organizationId: "s.\"organizationId\""
19218
19252
  };
19253
+ const SPAN_QUERY_FIELDS = {
19254
+ ...SPAN_FIELDS,
19255
+ traceId: "s.\"traceId\"",
19256
+ spanId: "s.\"spanId\"",
19257
+ parentSpanId: "s.\"parentSpanId\"",
19258
+ threadId: "s.\"threadId\"",
19259
+ resourceId: "s.\"resourceId\"",
19260
+ requestId: "s.\"requestId\"",
19261
+ serviceName: "s.\"serviceName\"",
19262
+ experimentId: "s.\"experimentId\"",
19263
+ environment: "s.\"environment\"",
19264
+ executionSource: "s.\"executionSource\"",
19265
+ parentEntityType: "s.\"parentEntityType\"",
19266
+ parentEntityId: "s.\"parentEntityId\"",
19267
+ parentEntityName: "s.\"parentEntityName\"",
19268
+ rootEntityType: "s.\"rootEntityType\"",
19269
+ rootEntityId: "s.\"rootEntityId\"",
19270
+ rootEntityName: "s.\"rootEntityName\""
19271
+ };
19219
19272
  const SCORE_FIELDS = {
19220
19273
  scorerId: "s.\"scorerId\"",
19221
19274
  scorerVersion: "s.\"scorerVersion\"",
@@ -20107,9 +20160,9 @@ async function queryThreads(client, schema, plan, timeoutMs) {
20107
20160
  }) : null }
20108
20161
  });
20109
20162
  }
20110
- /** Compile a span-row filter with exactly the same rules as trace span predicates. */
20163
+ /** Compile a direct span-query filter using its dedicated field mapping. */
20111
20164
  function compileSpanQueryPredicate(predicate, offset) {
20112
- return compileScalarPredicate(predicate, SPAN_FIELDS, offset);
20165
+ return compileScalarPredicate(predicate, SPAN_QUERY_FIELDS, offset);
20113
20166
  }
20114
20167
  //#endregion
20115
20168
  //#region src/storage/domains/observability/v-next/span-query.ts
@@ -20128,11 +20181,23 @@ const fields = [
20128
20181
  "entityId",
20129
20182
  "entityName",
20130
20183
  "entityVersionId",
20184
+ "parentEntityType",
20185
+ "parentEntityId",
20186
+ "parentEntityName",
20131
20187
  "parentEntityVersionId",
20188
+ "rootEntityType",
20189
+ "rootEntityId",
20190
+ "rootEntityName",
20132
20191
  "rootEntityVersionId",
20192
+ "threadId",
20133
20193
  "runId",
20134
20194
  "sessionId",
20135
- "userId"
20195
+ "userId",
20196
+ "requestId",
20197
+ "serviceName",
20198
+ "experimentId",
20199
+ "environment",
20200
+ "executionSource"
20136
20201
  ];
20137
20202
  const identities = identityFields.map((field) => `"${field}"`).join(", ");
20138
20203
  const identityOrder = identityFields.map((field) => `"${field}" COLLATE "C" ASC NULLS LAST`).join(", ");
@@ -20182,6 +20247,8 @@ function compilePostgresSpanQuery(schema, plan) {
20182
20247
  const after = afterCursor(plan, values);
20183
20248
  values.push(plan.limit + 1);
20184
20249
  const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
20250
+ const legacyModelFields = _mastra_core_storage.SPAN_QUERY_FIELD_REGISTRY ? "" : `CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
20251
+ CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider,`;
20185
20252
  return {
20186
20253
  text: `WITH candidate_ids AS MATERIALIZED (
20187
20254
  SELECT DISTINCT ${identities} FROM ${table}
@@ -20190,8 +20257,7 @@ function compilePostgresSpanQuery(schema, plan) {
20190
20257
  ), current_spans AS MATERIALIZED (
20191
20258
  SELECT DISTINCT ON (${identities})
20192
20259
  ${fields.map((field) => `"${field}"`).join(", ")}, "startedAt", "endedAt", "cursorId"::text AS version,
20193
- CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
20194
- CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider,
20260
+ ${legacyModelFields}
20195
20261
  (EXTRACT(EPOCH FROM ("endedAt" - "startedAt")) * 1000)::float8 AS "durationMs",
20196
20262
  CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
20197
20263
  error IS NOT NULL AS "hasError"
@@ -20206,15 +20272,7 @@ function compilePostgresSpanQuery(schema, plan) {
20206
20272
  SELECT *, CASE WHEN "hasError" THEN 'error' ELSE NULL END AS error FROM current_spans
20207
20273
  )
20208
20274
  SELECT ${[
20209
- ...identityFields,
20210
- "parentSpanId",
20211
- "name",
20212
- "spanType",
20213
- "entityType",
20214
- "entityId",
20215
- "entityName",
20216
- "model",
20217
- "provider",
20275
+ ...fields,
20218
20276
  "startedAt",
20219
20277
  "endedAt",
20220
20278
  "durationMs",
@@ -20261,7 +20319,7 @@ async function querySpans(client, schema, plan, timeoutMs) {
20261
20319
  endedAt: endedAt.toISOString()
20262
20320
  }));
20263
20321
  const page = rows.slice(0, plan.limit);
20264
- if (!page.length) return _mastra_core_storage.buildSpanQueryResponse(plan, selected, [], []);
20322
+ if (!page.length) return buildSpanQueryResponse(plan, [], []);
20265
20323
  const remaining = async () => {
20266
20324
  const ms = Math.floor(deadline - performance.now());
20267
20325
  if (ms <= 0) throw new _mastra_core_storage.TraceQueryExecutionError();
@@ -20274,20 +20332,32 @@ async function querySpans(client, schema, plan, timeoutMs) {
20274
20332
  payloadValues.push(row.version);
20275
20333
  return `(${key} AND "cursorId" = $${payloadValues.length}::bigint)`;
20276
20334
  }).join(" OR ");
20277
- const payloads = (await tx.any(`SELECT ${identities},
20335
+ const payloadRows = await tx.any(`SELECT ${identities},
20336
+ CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
20337
+ CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider,
20278
20338
  ${PREVIEW_PAYLOADS$1.map(([preview, payload]) => `"${preview}", CASE WHEN ${missingPreviewSql(`"${preview}"`)} THEN "${payload}" END AS "${payload}"`).join(",\n ")}
20279
- FROM ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} WHERE ${payloadWhere}`, payloadValues)).map(toSpanQueryPayload);
20280
- await remaining();
20281
- const metricValues = [];
20282
- const metricWhere = selectedKeys(page, metricValues);
20283
- const metrics = await tx.any(`SELECT ${identities}, name, "estimatedCost", "costUnit",
20284
- "costMetadata" ->> 'allocation' AS allocation, COALESCE("costMetadata" ? 'error', false) AS "costError"
20285
- FROM (SELECT DISTINCT ON (${identities}, "metricId") ${identities}, name, "estimatedCost", "costUnit", "costMetadata" FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
20286
- WHERE (${metricWhere}) AND name LIKE 'mastra_model_%'
20287
- ORDER BY ${identities}, "metricId", "cursorId" DESC) m
20288
- LIMIT ${_mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS + 1}`, metricValues);
20289
- if (metrics.length > _mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS) throw new _mastra_core_storage.TraceQueryResourceLimitError();
20290
- return buildSpanQueryResponse(plan, selected, payloads, metrics);
20339
+ FROM ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} WHERE ${payloadWhere}`, payloadValues);
20340
+ const payloads = payloadRows.map(toSpanQueryPayload);
20341
+ const metadata = new Map(payloadRows.map((row) => [_mastra_core_storage.spanQueryIdentityKey(row), row]));
20342
+ const hydrated = selected.map((row) => ({
20343
+ ...row,
20344
+ model: metadata.get(_mastra_core_storage.spanQueryIdentityKey(row))?.model ?? null,
20345
+ provider: metadata.get(_mastra_core_storage.spanQueryIdentityKey(row))?.provider ?? null
20346
+ }));
20347
+ let metrics = [];
20348
+ if (!_mastra_core_storage.SPAN_QUERY_FIELD_REGISTRY) {
20349
+ await remaining();
20350
+ const metricValues = [];
20351
+ const metricWhere = selectedKeys(page, metricValues);
20352
+ metrics = await tx.any(`SELECT ${identities}, name, "estimatedCost", "costUnit",
20353
+ "costMetadata" ->> 'allocation' AS allocation, COALESCE("costMetadata" ? 'error', false) AS "costError"
20354
+ FROM (SELECT DISTINCT ON (${identities}, "metricId") ${identities}, name, "estimatedCost", "costUnit", "costMetadata" FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
20355
+ WHERE (${metricWhere}) AND name LIKE 'mastra_model_%'
20356
+ ORDER BY ${identities}, "metricId", "cursorId" DESC) m
20357
+ LIMIT ${_mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS + 1}`, metricValues);
20358
+ if (metrics.length > _mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS) throw new _mastra_core_storage.TraceQueryResourceLimitError();
20359
+ }
20360
+ return buildSpanQueryResponse(plan, hydrated, payloads, metrics);
20291
20361
  }, { repeatableRead: true });
20292
20362
  }
20293
20363
  //#endregion
@@ -21331,7 +21401,7 @@ async function dangerouslyClearTracing(client, schema) {
21331
21401
  * application database — observability writes will degrade app performance.
21332
21402
  * Use it through `MastraCompositeStore` with a dedicated Postgres connection.
21333
21403
  */
21334
- const spanQueryFeatures = typeof _mastra_core_storage.planSpanQuery === "function" ? ["span-query"] : [];
21404
+ const spanQueryFeatures = typeof _mastra_core_storage.planSpanQuery === "function" ? ["span-query", "span-query-context-fields"] : [];
21335
21405
  function wrapError(op, error, details) {
21336
21406
  if (error instanceof _mastra_core_error.MastraError || error instanceof _mastra_core_storage.TraceQueryCursorError || error instanceof _mastra_core_storage.TraceQueryExecutionError || error instanceof _mastra_core_storage.TraceQueryResourceLimitError) throw error;
21337
21407
  throw new _mastra_core_error.MastraError({