@mastra/pg 1.35.0-alpha.0 → 1.35.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.
package/dist/index.js CHANGED
@@ -4443,7 +4443,8 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
4443
4443
  "skillsFormat",
4444
4444
  "durable",
4445
4445
  "browser",
4446
- "toolProviders"
4446
+ "toolProviders",
4447
+ "modelList"
4447
4448
  ]
4448
4449
  });
4449
4450
  await this.#migrateToolsToJsonbFormat();
@@ -4501,10 +4502,10 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
4501
4502
  row.updatedAt ?? now
4502
4503
  ]);
4503
4504
  await this.#db.client.none(`INSERT INTO ${fullVersionsTableName}
4504
- (id, "agentId", "versionNumber", name, description, instructions, model, tools,
4505
+ (id, "agentId", "versionNumber", name, description, instructions, model, "modelList", tools,
4505
4506
  "defaultOptions", workflows, agents, "integrationTools", "toolProviders", "inputProcessors",
4506
4507
  "outputProcessors", memory, scorers, "changedFields", "changeMessage", "createdAt")
4507
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20)
4508
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21)
4508
4509
  ON CONFLICT (id) DO NOTHING`, [
4509
4510
  versionId,
4510
4511
  agentId,
@@ -4513,6 +4514,7 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
4513
4514
  row.description ?? null,
4514
4515
  this.serializeInstructions(row.instructions ?? ""),
4515
4516
  row.model ? toPgJson(row.model) : "{}",
4517
+ row.modelList ? toPgJson(row.modelList) : null,
4516
4518
  row.tools ? toPgJson(row.tools) : null,
4517
4519
  row.defaultOptions ? toPgJson(row.defaultOptions) : null,
4518
4520
  row.workflows ? toPgJson(row.workflows) : null,
@@ -4926,21 +4928,22 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
4926
4928
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
4927
4929
  const row = await this.#db.client.one(`INSERT INTO ${tableName} (
4928
4930
  id, "agentId", "versionNumber",
4929
- name, description, instructions, model, tools,
4931
+ name, description, instructions, model, "modelList", tools,
4930
4932
  "defaultOptions", workflows, agents, "integrationTools", "toolProviders",
4931
4933
  "inputProcessors", "outputProcessors", memory, scorers,
4932
4934
  "mcpClients", "requestContextSchema", workspace, skills, "skillsFormat",
4933
4935
  durable, browser,
4934
4936
  "changedFields", "changeMessage",
4935
4937
  "createdAt", "createdAtZ"
4936
- ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28) RETURNING *`, [
4938
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29) RETURNING *`, [
4937
4939
  input.id,
4938
4940
  input.agentId,
4939
4941
  input.versionNumber,
4940
4942
  input.name,
4941
4943
  input.description ?? null,
4942
- this.serializeInstructions(input.instructions),
4943
- toPgJson(input.model),
4944
+ this.serializeInstructions(input.instructions) ?? "",
4945
+ toPgJson(input.model ?? {}),
4946
+ input.modelList ? toPgJson(input.modelList) : null,
4944
4947
  input.tools ? toPgJson(input.tools) : null,
4945
4948
  input.defaultOptions ? toPgJson(input.defaultOptions) : null,
4946
4949
  input.workflows ? toPgJson(input.workflows) : null,
@@ -5186,6 +5189,7 @@ var AgentsPG = class AgentsPG extends AgentsStorage {
5186
5189
  description: row.description,
5187
5190
  instructions: this.deserializeInstructions(row.instructions),
5188
5191
  model: parseJsonResilient(row.model, "model"),
5192
+ modelList: parseJsonResilient(row.modelList, "modelList"),
5189
5193
  tools: parseJsonResilient(row.tools, "tools"),
5190
5194
  defaultOptions: parseJsonResilient(row.defaultOptions, "defaultOptions"),
5191
5195
  workflows: parseJsonResilient(row.workflows, "workflows"),
@@ -8643,13 +8647,23 @@ function createKnowledgePagesCoreLoader(features, loadStorageModule) {
8643
8647
  };
8644
8648
  }
8645
8649
  /**
8646
- * Keyword-search words: the query split on whitespace, lowercased, deduplicated. Every word must
8647
- * appear (as a case-insensitive substring) in a hit; an empty list means the search returns nothing.
8650
+ * Keyword-search words: the query split on whitespace, lowercased, deduplicated. A hit needs at
8651
+ * least one of them (as a case-insensitive substring); an empty list means the search returns nothing.
8648
8652
  */
8649
8653
  function knowledgeSearchWords(query) {
8650
8654
  return [...new Set(query.toLowerCase().split(/\s+/).filter(Boolean))];
8651
8655
  }
8652
8656
  /**
8657
+ * Points one matched search word earns on a page, by the best field it appears in: name, then
8658
+ * description, then body. Pages rank by how many query words they match first; these points only
8659
+ * break ties between pages that match the same number of words.
8660
+ */
8661
+ const KNOWLEDGE_SEARCH_WEIGHTS = {
8662
+ name: 3,
8663
+ description: 2,
8664
+ body: 1
8665
+ };
8666
+ /**
8653
8667
  * Why `key` can't be a Knowledge page key, or undefined when it can. Keys are one path segment:
8654
8668
  * non-empty, with no `/` (path separator), `#` (scope/path separator) or `%` (escape character).
8655
8669
  */
@@ -9527,6 +9541,18 @@ var PgKnowledgePages = class {
9527
9541
  const rows = await this.#rows(this.#client, `SELECT ${this.#noteColumns()} FROM ${this.#visibleNotes(filter)} AND ${extra.join(" AND ")} ORDER BY n."createdAt", n."id" LIMIT ${limit + 1}`, params.values);
9528
9542
  return this.#noteOutput(rows, limit);
9529
9543
  }
9544
+ async countChildPages(input) {
9545
+ const ids = [...new Set(input.parentIds)];
9546
+ const counts = Object.fromEntries(ids.map((id) => [id, 0]));
9547
+ if (!ids.length) return counts;
9548
+ const params = new Params();
9549
+ const filter = new ReadFilter(input.read, params, this.#pages);
9550
+ const rows = await this.#rows(this.#client, `SELECT p."parentId" AS "parentId", count(*)::int AS "count" FROM ${this.#pages} p JOIN ${this.#pages} s ON s."id" = p."scopeId"
9551
+ WHERE p."parentId" = ANY(${params.add(ids)}::text[]) AND NOT p."isScope" AND p."deletedAt" IS NULL AND ${filter.readable("s")}
9552
+ GROUP BY p."parentId"`, params.values);
9553
+ for (const row of rows) counts[row.parentId] = Number(row.count);
9554
+ return counts;
9555
+ }
9530
9556
  async countNotes(input) {
9531
9557
  const ids = [...new Set(input.pageIds)];
9532
9558
  const counts = Object.fromEntries(ids.map((id) => [id, 0]));
@@ -9694,9 +9720,12 @@ var PgKnowledgePages = class {
9694
9720
  filter.readable("s")
9695
9721
  ];
9696
9722
  if (input.scopeIds?.length) where.push(`p."scopeId" = ANY(${params.add(input.scopeIds)}::text[])`);
9697
- for (const pattern of patterns) where.push(`(p."name" ILIKE ${pattern} OR p."description" ILIKE ${pattern} OR p."body" ILIKE ${pattern})`);
9698
- const tier = `CASE WHEN p."canonicalName" LIKE ${phrasePattern} THEN 0 WHEN ${patterns.map((pattern) => `p."name" ILIKE ${pattern}`).join(" AND ")} THEN 1 ELSE 2 END`;
9699
- const rows = await this.#rows(this.#client, `SELECT p.* FROM ${this.#pages} p JOIN ${this.#pages} s ON s."id" = p."scopeId" WHERE ${where.join(" AND ")} ORDER BY ${tier}, p."updatedAt" DESC, p."id" ASC LIMIT ${limit}`, params.values);
9723
+ const anyField = patterns.map((pattern) => `(p."name" ILIKE ${pattern} OR p."description" ILIKE ${pattern} OR p."body" ILIKE ${pattern})`).join(" OR ");
9724
+ where.push(`(${anyField})`);
9725
+ const score = patterns.map((pattern) => `(CASE WHEN p."name" ILIKE ${pattern} THEN ${KNOWLEDGE_SEARCH_WEIGHTS.name} WHEN p."description" ILIKE ${pattern} THEN ${KNOWLEDGE_SEARCH_WEIGHTS.description} WHEN p."body" ILIKE ${pattern} THEN ${KNOWLEDGE_SEARCH_WEIGHTS.body} ELSE 0 END)`).join(" + ");
9726
+ const count = patterns.map((pattern) => `(CASE WHEN p."name" ILIKE ${pattern} OR p."description" ILIKE ${pattern} OR p."body" ILIKE ${pattern} THEN 1 ELSE 0 END)`).join(" + ");
9727
+ const tier = `CASE WHEN p."canonicalName" LIKE ${phrasePattern} THEN 0 ELSE 1 END`;
9728
+ const rows = await this.#rows(this.#client, `SELECT p.* FROM ${this.#pages} p JOIN ${this.#pages} s ON s."id" = p."scopeId" WHERE ${where.join(" AND ")} ORDER BY ${tier}, (${count}) DESC, (${score}) DESC, p."updatedAt" DESC, p."id" ASC LIMIT ${limit}`, params.values);
9700
9729
  for (const row of rows) hits.push({
9701
9730
  type: "page",
9702
9731
  page: toPage(row)
@@ -9708,8 +9737,10 @@ var PgKnowledgePages = class {
9708
9737
  const filter = new ReadFilter(input.read, params, this.#pages);
9709
9738
  const extra = [`n."deletedAt" IS NULL`, `np."deletedAt" IS NULL`];
9710
9739
  if (input.scopeIds?.length) extra.push(`np."scopeId" = ANY(${params.add(input.scopeIds)}::text[])`);
9711
- for (const word of words) extra.push(`n."text" ILIKE ${params.add(`%${escapeLike(word)}%`)}`);
9712
- const rows = await this.#rows(this.#client, `SELECT ${this.#noteColumns()}, row_to_json(np) AS "pageJson" FROM ${this.#visibleNotes(filter)} AND ${extra.join(" AND ")} ORDER BY n."updatedAt" DESC, n."id" DESC LIMIT ${limit - hits.length}`, params.values);
9740
+ const noteHas = words.map((word) => `n."text" ILIKE ${params.add(`%${escapeLike(word)}%`)}`);
9741
+ extra.push(`(${noteHas.join(" OR ")})`);
9742
+ const noteScore = noteHas.map((has) => `(CASE WHEN ${has} THEN 1 ELSE 0 END)`).join(" + ");
9743
+ const rows = await this.#rows(this.#client, `SELECT ${this.#noteColumns()}, row_to_json(np) AS "pageJson" FROM ${this.#visibleNotes(filter)} AND ${extra.join(" AND ")} ORDER BY (${noteScore}) DESC, n."updatedAt" DESC, n."id" DESC LIMIT ${limit - hits.length}`, params.values);
9713
9744
  for (const row of rows) hits.push({
9714
9745
  type: "note",
9715
9746
  note: toNote(row),
@@ -10053,6 +10084,9 @@ var KnowledgePG = class extends KnowledgeStorage {
10053
10084
  listNotes(input) {
10054
10085
  return this.#pages.listNotes(input);
10055
10086
  }
10087
+ countChildPages(input) {
10088
+ return this.#pages.countChildPages(input);
10089
+ }
10056
10090
  countNotes(input) {
10057
10091
  return this.#pages.countNotes(input);
10058
10092
  }
@@ -19002,6 +19036,8 @@ const timeToFirstTokenSortSupported = coreStorage.TRACE_QUERY_ORDER_FIELDS?.incl
19002
19036
  const spanQueryOutcomeFieldsSupported = "outcome" in (coreStorage.SPAN_QUERY_FIELD_REGISTRY ?? {});
19003
19037
  const traceQueryOutcomeFieldsSupported = "outcome" in (coreStorage.TRACE_QUERY_FIELD_REGISTRY?.trace ?? {});
19004
19038
  const outcomeFeatures = [...spanQueryOutcomeFieldsSupported ? ["span-query-outcome-fields"] : [], ...traceQueryOutcomeFieldsSupported ? ["trace-query-outcome-fields"] : []];
19039
+ /** Core before the fields rejects their trace and span predicates, so the feature is only declared when core plans them. */
19040
+ const contextFieldFeatures = "requestId" in (coreStorage.TRACE_QUERY_FIELD_REGISTRY?.trace ?? {}) ? ["trace-query-context-fields"] : [];
19005
19041
  const timingFeatures = [
19006
19042
  ...timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [],
19007
19043
  ...timeToFirstChunkSortSupported ? ["trace-query-time-to-first-chunk-sort"] : [],
@@ -19036,6 +19072,9 @@ const TRACE_FIELDS = {
19036
19072
  sessionId: "r.\"sessionId\"",
19037
19073
  userId: "r.\"userId\"",
19038
19074
  organizationId: "r.\"organizationId\"",
19075
+ requestId: "r.\"requestId\"",
19076
+ serviceName: "r.\"serviceName\"",
19077
+ experimentId: "r.\"experimentId\"",
19039
19078
  startedAt: "r.\"startedAt\"",
19040
19079
  endedAt: "r.\"endedAt\"",
19041
19080
  durationMs: durationMsSql("r.\"startedAt\"", "r.\"endedAt\""),
@@ -19075,7 +19114,10 @@ const SPAN_FIELDS = {
19075
19114
  runId: "s.\"runId\"",
19076
19115
  sessionId: "s.\"sessionId\"",
19077
19116
  userId: "s.\"userId\"",
19078
- organizationId: "s.\"organizationId\""
19117
+ organizationId: "s.\"organizationId\"",
19118
+ requestId: "s.\"requestId\"",
19119
+ serviceName: "s.\"serviceName\"",
19120
+ experimentId: "s.\"experimentId\""
19079
19121
  };
19080
19122
  const SPAN_QUERY_FIELDS = {
19081
19123
  ...SPAN_FIELDS,
@@ -19084,9 +19126,6 @@ const SPAN_QUERY_FIELDS = {
19084
19126
  parentSpanId: "s.\"parentSpanId\"",
19085
19127
  threadId: "s.\"threadId\"",
19086
19128
  resourceId: "s.\"resourceId\"",
19087
- requestId: "s.\"requestId\"",
19088
- serviceName: "s.\"serviceName\"",
19089
- experimentId: "s.\"experimentId\"",
19090
19129
  environment: "s.\"environment\"",
19091
19130
  executionSource: "s.\"executionSource\"",
19092
19131
  parentEntityType: "s.\"parentEntityType\"",
@@ -19350,6 +19389,9 @@ const ROOT_PUSHDOWN_FIELDS = /* @__PURE__ */ new Set([
19350
19389
  "sessionId",
19351
19390
  "userId",
19352
19391
  "organizationId",
19392
+ "requestId",
19393
+ "serviceName",
19394
+ "experimentId",
19353
19395
  "startedAt",
19354
19396
  "endedAt",
19355
19397
  "entityId",
@@ -19521,7 +19563,10 @@ function compilePostgresTraceScope(schema, selection, relationCollections, scope
19521
19563
  s."runId",
19522
19564
  s."sessionId",
19523
19565
  s."userId",
19524
- s."organizationId"
19566
+ s."organizationId",
19567
+ s."requestId",
19568
+ s."serviceName",
19569
+ s."experimentId"
19525
19570
  FROM ${spanTable} s
19526
19571
  WHERE s."traceId" IS NOT NULL
19527
19572
  AND s."traceId" IN (SELECT "traceId" FROM root_scope)
@@ -20503,6 +20548,18 @@ const PERCENTILES = {
20503
20548
  "duration.p95": .95,
20504
20549
  "duration.p99": .99
20505
20550
  };
20551
+ /** Quantile for each percentile statistic of a time-to-first measure. */
20552
+ const STATISTIC_PERCENTILES = {
20553
+ p50: .5,
20554
+ p90: .9,
20555
+ p95: .95,
20556
+ p99: .99
20557
+ };
20558
+ /**
20559
+ * Store features this compiler supports beyond `trace-aggregate` / `span-aggregate`. Core before
20560
+ * the time-to-first measures rejects them, so they are only declared when core plans them.
20561
+ */
20562
+ const aggregateTimeToFirstFeatures = "timeToFirstToken.p50" in coreStorage.TRACE_AGGREGATE_MEASURE_REGISTRY ? ["aggregate-time-to-first-measures"] : [];
20506
20563
  const COMPARISON_SQL = {
20507
20564
  eq: "=",
20508
20565
  ne: "<>",
@@ -20570,6 +20627,8 @@ function compilePostgresAggregate(schema, plan, source) {
20570
20627
  factColumns.push(`(${distinctSql(measure.field)})::text AS ${column}`);
20571
20628
  }
20572
20629
  factColumns.push(`(${durationMsSql("r.\"startedAt\"", "r.\"endedAt\"")})::float8 AS "durationMs"`, `r."error" IS NOT NULL AS "isError"`);
20630
+ const timeToFirstFields = new Set(plan.measures.map((measure) => measureRule(measure.name)?.field));
20631
+ for (const field of timeToFirstFields) if (field) factColumns.push(`r."${field}"::float8 AS "${field}"`);
20573
20632
  if (plan.interval !== void 0) {
20574
20633
  const intervalMs = coreStorage.TRACE_AGGREGATE_INTERVAL_MS[plan.interval];
20575
20634
  if (intervalMs === void 0) throw new Error(`Unsupported trusted trace-aggregate interval: ${plan.interval}`);
@@ -20601,6 +20660,15 @@ function compilePostgresAggregate(schema, plan, source) {
20601
20660
  const aggregate = rule.statistic === "avg" ? "AVG" : "SUM";
20602
20661
  return `(CASE WHEN ${mixedUnitsSql(alias)} THEN NULL ELSE ${aggregate}(${column("traceCost")}) END)::float8`;
20603
20662
  }
20663
+ if (rule?.field) {
20664
+ const value = column(rule.field);
20665
+ if (rule.statistic === "count") return `COUNT(${value})::float8`;
20666
+ if (rule.statistic === "avg") return `AVG(${value})`;
20667
+ if (rule.statistic === "min") return `MIN(${value})`;
20668
+ if (rule.statistic === "max") return `MAX(${value})`;
20669
+ const quantile = rule.statistic && STATISTIC_PERCENTILES[rule.statistic];
20670
+ if (quantile !== void 0) return `percentile_cont(${quantile}) WITHIN GROUP (ORDER BY ${value})`;
20671
+ }
20604
20672
  if (name === "errorCount") return `(COUNT(*) FILTER (WHERE ${column("isError")}))::float8`;
20605
20673
  if (name === "errorRate") return `(COUNT(*) FILTER (WHERE ${column("isError")}))::float8 / COUNT(*)`;
20606
20674
  if (name === "duration.avg") return `AVG(${column("durationMs")})`;
@@ -21755,6 +21823,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
21755
21823
  "metric-discovery",
21756
21824
  "trace-query",
21757
21825
  "trace-aggregate",
21826
+ ...aggregateTimeToFirstFeatures,
21758
21827
  ...spanQueryFeatures,
21759
21828
  ...spanAggregateFeatures,
21760
21829
  ...typeof coreStorage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
@@ -21764,6 +21833,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
21764
21833
  "trace-query-tenant-scope",
21765
21834
  "feedback",
21766
21835
  "trace-query-context-ids",
21836
+ ...contextFieldFeatures,
21767
21837
  ...timingFeatures,
21768
21838
  ...outcomeFeatures,
21769
21839
  "trace-query-root-span-fields",
@@ -21781,6 +21851,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
21781
21851
  "delta-polling",
21782
21852
  "trace-query",
21783
21853
  "trace-aggregate",
21854
+ ...aggregateTimeToFirstFeatures,
21784
21855
  ...spanQueryFeatures,
21785
21856
  ...spanAggregateFeatures,
21786
21857
  ...typeof coreStorage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [],
@@ -21790,6 +21861,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
21790
21861
  "trace-query-tenant-scope",
21791
21862
  "feedback",
21792
21863
  "trace-query-context-ids",
21864
+ ...contextFieldFeatures,
21793
21865
  ...timingFeatures,
21794
21866
  ...outcomeFeatures,
21795
21867
  "trace-query-root-span-fields",