@mastra/pg 1.20.1-alpha.0 → 1.20.1-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/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @mastra/pg
2
2
 
3
+ ## 1.20.1-alpha.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Added a `durable` option to stored agents so agents created through the Agents API can run with durable execution — no code deployment required. ([#21715](https://github.com/mastra-ai/mastra/pull/21715))
8
+
9
+ ```typescript
10
+ await mastraClient.createStoredAgent({
11
+ id: 'helper',
12
+ name: 'Helper',
13
+ instructions: 'You are a helpful assistant.',
14
+ model: { provider: 'openai', name: 'gpt-5' },
15
+ durable: true,
16
+ });
17
+ ```
18
+
19
+ Pass `true` for defaults, or `{ maxSteps, cleanupTimeoutMs }` to tune the durable loop. Cache and pubsub are inherited from the server's Mastra instance, so configure distributed backends there for durability across replicas. Automatic recovery is still configured in code via `recovery.durableAgents`.
20
+
21
+ - Improved PgVector upsert performance when writing many vectors at once. Batches are now written with a small number of multi-row inserts instead of one insert per vector, which reduces database round trips and connection pool usage during RAG and memory ingestion. ([#21719](https://github.com/mastra-ai/mastra/pull/21719))
22
+
23
+ - Updated dependencies [[`6223446`](https://github.com/mastra-ai/mastra/commit/6223446ddce6166e96e0ba5e00d628b615dee8ca), [`583e235`](https://github.com/mastra-ai/mastra/commit/583e23519c13af16c1746f9c49722d011216611b), [`a77f8d4`](https://github.com/mastra-ai/mastra/commit/a77f8d4740d2178a74c41e4bf678b4fcd8fa0bb2), [`40d358e`](https://github.com/mastra-ai/mastra/commit/40d358e29d55543803e64b49241122f598ffabc7), [`e80cd7e`](https://github.com/mastra-ai/mastra/commit/e80cd7e7683e7d732e1cc6784bcac1d2640d2ce3), [`20504b2`](https://github.com/mastra-ai/mastra/commit/20504b2ecebd0e077acda3d457ab57480a98ed3e)]:
24
+ - @mastra/core@1.60.0-alpha.11
25
+
26
+ ## 1.20.1-alpha.1
27
+
28
+ ### Patch Changes
29
+
30
+ - Make `listWorkflowRuns` status filtering indexable on Postgres. The status predicate previously wrapped every snapshot in a `regexp_replace(snapshot::text, ...)::jsonb` sanitization step, which forced a sequential scan over the whole `mastra_workflow_snapshot` table. On `jsonb` snapshot columns Postgres already rejects the problematic Unicode escape sequences at insert time, so the sanitization was a no-op there and the query now uses a plain `snapshot->>'status'` comparison backed by a new default expression index on `(workflow_name, snapshot->>'status', "createdAt" DESC)`. Legacy tables whose snapshot column is still `json` or `text` keep the sanitizing path. ([#21684](https://github.com/mastra-ai/mastra/pull/21684))
31
+
32
+ - Updated dependencies [[`4e7a421`](https://github.com/mastra-ai/mastra/commit/4e7a421dce8a48742f785d1e93ad2f43a572b282), [`242e324`](https://github.com/mastra-ai/mastra/commit/242e3241e73cbd5c9bb86a31ebb49ca0256488d4), [`217e967`](https://github.com/mastra-ai/mastra/commit/217e9672d8b3160eb729d8e9f0044949e88da239), [`d774e89`](https://github.com/mastra-ai/mastra/commit/d774e8930c781df8c9effe3763e6b501c099b6cc), [`9c27a53`](https://github.com/mastra-ai/mastra/commit/9c27a53cd9d3de4f3f025bc387d94ce371c33f95), [`dff25a1`](https://github.com/mastra-ai/mastra/commit/dff25a1103fa72ee082a9b6f805ebeb5ce400753), [`217e967`](https://github.com/mastra-ai/mastra/commit/217e9672d8b3160eb729d8e9f0044949e88da239), [`7f78585`](https://github.com/mastra-ai/mastra/commit/7f785857e401570e2ffb316911f126ed363aa537), [`f2a4afd`](https://github.com/mastra-ai/mastra/commit/f2a4afd7e37e809669001ed17724b341a5c1f45e), [`d438148`](https://github.com/mastra-ai/mastra/commit/d438148e222c1e2fb3c652725ce75680962ebec4), [`ba05fe0`](https://github.com/mastra-ai/mastra/commit/ba05fe0738f70cb686777546e968237d09269142), [`d26a8d4`](https://github.com/mastra-ai/mastra/commit/d26a8d4281f28414715b333c85bedaf70d0b2890), [`677cdc6`](https://github.com/mastra-ai/mastra/commit/677cdc6af564dec29a13464d12b7ab2a4efc22e9), [`a318490`](https://github.com/mastra-ai/mastra/commit/a318490e17da32f338d50929c770d901a9b3dd72), [`763e0c6`](https://github.com/mastra-ai/mastra/commit/763e0c61e04d76ad9a9efd301aa57525ca0cbea9), [`23e0be2`](https://github.com/mastra-ai/mastra/commit/23e0be261381e49534b4ff3101c60ee64a946cbf), [`7fc8806`](https://github.com/mastra-ai/mastra/commit/7fc880627d3cbf995d31ea0e8b807bf15417e651), [`0e02eac`](https://github.com/mastra-ai/mastra/commit/0e02eacdb2e30e1697a41910b41163742a181dc1), [`4df174c`](https://github.com/mastra-ai/mastra/commit/4df174c32bddf093a82f273070b8380aef7c9e90), [`f7c25b5`](https://github.com/mastra-ai/mastra/commit/f7c25b5106ddfb48e591f98df7a51e0f2dd01dba), [`dc09cc1`](https://github.com/mastra-ai/mastra/commit/dc09cc1083d861cde192c1cd235324dc75b8c731), [`36b4649`](https://github.com/mastra-ai/mastra/commit/36b4649045a3a380cbab8ceca866db4086223aff), [`377eb81`](https://github.com/mastra-ai/mastra/commit/377eb81ce43b964e3a6b541df172da74a8ff3716)]:
33
+ - @mastra/core@1.60.0-alpha.8
34
+
3
35
  ## 1.20.1-alpha.0
4
36
 
5
37
  ### Patch Changes
@@ -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.20.1-alpha.0"
6
+ version: "1.20.1-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -19,7 +19,7 @@ Read the individual reference documents for detailed explanations and code examp
19
19
  - [Workers](references/docs-deployment-workers.md) - Separate background processing from the API layer by running workflow execution, cron schedules, and background tasks in dedicated worker processes.
20
20
  - [Semantic recall](references/docs-memory-semantic-recall.md) - Learn how to use semantic recall in Mastra to retrieve relevant messages from past conversations using vector search and embeddings.
21
21
  - [Working memory](references/docs-memory-working-memory.md) - Learn how to configure working memory in Mastra to store persistent user data, preferences.
22
- - [Storage](references/docs-storage-overview.md) - Configure storage for Mastra to persist runtime state across agents, workflows, observability, evals, schedules, and memory.
22
+ - [Storage](references/docs-storage.md) - Configure storage for Mastra to persist runtime state across agents, workflows, observability, evals, schedules, and memory.
23
23
 
24
24
  ### Integrations
25
25
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.20.1-alpha.0",
2
+ "version": "1.20.1-alpha.2",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -339,7 +339,7 @@ MASTRA_STEP_EXECUTION_URL=http://api:4111/api
339
339
 
340
340
  Without this variable, the orchestration worker attempts to execute steps in its own process, which doesn't have access to the full Mastra runtime in a split deployment.
341
341
 
342
- The endpoint uses the server's normal auth pipeline. If the API has an auth provider, set `MASTRA_WORKER_AUTH_TOKEN` to a bearer token that provider accepts. Mastra forwards the value as an `Authorization: Bearer` credential. The configured auth provider validates the token. See [Worker authentication](https://mastra.ai/docs/server/auth/workers) for server configuration and other credential formats.
342
+ The endpoint uses the server's normal auth pipeline. If the API has an auth provider, set `MASTRA_WORKER_AUTH_TOKEN` to a bearer token that provider accepts. Mastra forwards the value as an `Authorization: Bearer` credential. The configured auth provider validates the token. See [Worker authentication](https://mastra.ai/docs/auth/workers) for server configuration and other credential formats.
343
343
 
344
344
  ### Scale workers
345
345
 
@@ -365,18 +365,18 @@ A distributed PubSub backend persists unacknowledged events, which lets orchestr
365
365
 
366
366
  The scheduler calculates the next fire time from the current time after it restarts. It doesn't replay schedules that elapsed while it was unavailable.
367
367
 
368
- If the API crashes while a step is executing, that work can be lost and the workflow run can remain in a `running` state. See [known limitations](#known-limitations) and [durable agent crash recovery](https://mastra.ai/docs/long-running-agents/durable-agents).
368
+ If the API crashes while a step is executing, that work can be lost and the workflow run can remain in a `running` state. See [known limitations](#known-limitations) and [durable agent crash recovery](https://mastra.ai/docs/harness/durable-agents).
369
369
 
370
370
  ## Known limitations
371
371
 
372
372
  - **No dead-letter queue**: Failed events are nacked and retried, but there's no DLQ for events that fail after all retries.
373
373
  - **No built-in health endpoint**: Workers don't expose an HTTP health check. Use container-level liveness probes or process monitoring.
374
374
  - **Scheduler is single-instance**: Running multiple scheduler processes causes duplicate schedule fires.
375
- - **Runs stuck in "running" after API crash**: If the API process crashes while executing a workflow step, the run remains in `running` status with no automatic retry. For [durable agents](https://mastra.ai/docs/long-running-agents/durable-agents), set `recovery.durableAgents` to `'auto'` in the Mastra config to automatically re-drive orphaned runs on server restart. See [Crash recovery](https://mastra.ai/docs/long-running-agents/durable-agents) for details.
375
+ - **Runs stuck in "running" after API crash**: If the API process crashes while executing a workflow step, the run remains in `running` status with no automatic retry. For [durable agents](https://mastra.ai/docs/harness/durable-agents), set `recovery.durableAgents` to `'auto'` in the Mastra config to automatically re-drive orphaned runs on server restart. See [Crash recovery](https://mastra.ai/docs/harness/durable-agents) for details.
376
376
 
377
377
  ## Related
378
378
 
379
- - [Worker authentication](https://mastra.ai/docs/server/auth/workers): Secure worker-to-API communication
379
+ - [Worker authentication](https://mastra.ai/docs/auth/workers): Secure worker-to-API communication
380
380
  - [Workers reference](https://mastra.ai/reference/workers/overview): Details about worker environment variables and types, with a list of supported storage backends
381
381
  - [CLI reference](https://mastra.ai/reference/cli/mastra): `mastra worker build` and `mastra worker start`
382
382
  - [PubSub](https://mastra.ai/docs/server/pubsub): Event delivery backends
@@ -400,7 +400,7 @@ const response = await agent.generate('What do you know about me?', {
400
400
 
401
401
  ## Opt in to state signals (experimental)
402
402
 
403
- By default, working memory reaches the model as part of the system message. You can opt into delivering it as a [state signal](https://mastra.ai/docs/long-running-agents/signals) instead by setting `useStateSignals: true`:
403
+ By default, working memory reaches the model as part of the system message. You can opt into delivering it as a [state signal](https://mastra.ai/docs/harness/signals) instead by setting `useStateSignals: true`:
404
404
 
405
405
  ```typescript
406
406
  const memory = new Memory({
@@ -10,7 +10,7 @@ Storage powers:
10
10
  - [Workflows](https://mastra.ai/docs/workflows/overview): Durable snapshots for suspended and resumed workflow runs.
11
11
  - [Observability](https://mastra.ai/docs/observability/overview): Traces, spans, metrics, logs, and feedback.
12
12
  - [Evals](https://mastra.ai/docs/evals/overview): Scores, datasets, experiments, and evaluation results.
13
- - [Long-running agents](https://mastra.ai/docs/long-running-agents/durable-agents): Background tasks, schedules, goals, and thread state.
13
+ - [Long-running agents](https://mastra.ai/docs/harness/durable-agents): Background tasks, schedules, goals, and thread state.
14
14
 
15
15
  ## When to configure storage
16
16
 
@@ -408,6 +408,7 @@ PostgreSQL storage creates composite indexes during initialization for common qu
408
408
  - `mastra_ai_spans_scope_startedat_idx`: (scope, startedAt DESC)
409
409
  - `mastra_scores_trace_id_span_id_created_at_idx`: (traceId, spanId, createdAt DESC)
410
410
  - `mastra_workflow_snapshot_name_createdat_idx`: (workflow\_name, createdAt DESC)
411
+ - `mastra_workflow_snapshot_name_status_createdat_idx`: (workflow\_name, snapshot->>'status', createdAt DESC), created only when the `snapshot` column is `jsonb`
411
412
 
412
413
  These indexes improve performance for filtered queries with sorting, including `dateRange` filters on message queries and Studio's workflow runs-list.
413
414
 
@@ -145,4 +145,5 @@ export const agent = new Agent({
145
145
  - [listThreads](https://mastra.ai/reference/memory/listThreads)
146
146
  - [deleteMessages](https://mastra.ai/reference/memory/deleteMessages)
147
147
  - [cloneThread](https://mastra.ai/reference/memory/cloneThread)
148
+ - [settled](https://mastra.ai/reference/memory/settled)
148
149
  - [Clone Utility Methods](https://mastra.ai/reference/memory/clone-utilities)
package/dist/index.cjs CHANGED
@@ -565,6 +565,7 @@ function buildFilterQuery(filter, minScore, topK) {
565
565
  }
566
566
  //#endregion
567
567
  //#region src/vector/index.ts
568
+ const MAX_UPSERT_ROWS_PER_STATEMENT = Math.floor(65535 / 3);
568
569
  var PgVector = class extends _mastra_core_vector.MastraVector {
569
570
  pool;
570
571
  describeIndexCache = /* @__PURE__ */ new Map();
@@ -957,23 +958,41 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
957
958
  const indexInfo = await this.getIndexInfo({ indexName });
958
959
  const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType, indexInfo.dimension);
959
960
  const ops = this.getVectorOps(indexInfo.vectorType, indexInfo.metric ?? "cosine");
960
- for (let i = 0; i < vectors.length; i++) {
961
+ if (new Set(vectorIds).size !== vectorIds.length) for (let i = 0; i < vectors.length; i++) {
961
962
  const vectorStr = ops.formatVector(vectors[i], indexInfo.dimension);
962
963
  const query = `
963
- INSERT INTO ${tableName} (vector_id, embedding, metadata)
964
- VALUES ($1, $2::${qualifiedVectorType}, $3::jsonb)
965
- ON CONFLICT (vector_id)
966
- DO UPDATE SET
967
- embedding = $2::${qualifiedVectorType},
968
- metadata = $3::jsonb
969
- RETURNING embedding::text
970
- `;
964
+ INSERT INTO ${tableName} (vector_id, embedding, metadata)
965
+ VALUES ($1, $2::${qualifiedVectorType}, $3::jsonb)
966
+ ON CONFLICT (vector_id)
967
+ DO UPDATE SET
968
+ embedding = $2::${qualifiedVectorType},
969
+ metadata = $3::jsonb
970
+ `;
971
971
  await client.query(query, [
972
972
  vectorIds[i],
973
973
  vectorStr,
974
974
  JSON.stringify(metadata?.[i] || {})
975
975
  ]);
976
976
  }
977
+ else for (let start = 0; start < vectors.length; start += MAX_UPSERT_ROWS_PER_STATEMENT) {
978
+ const end = Math.min(start + MAX_UPSERT_ROWS_PER_STATEMENT, vectors.length);
979
+ const rows = [];
980
+ const values = [];
981
+ for (let i = start; i < end; i++) {
982
+ const base = values.length;
983
+ rows.push(`($${base + 1}, $${base + 2}::${qualifiedVectorType}, $${base + 3}::jsonb)`);
984
+ values.push(vectorIds[i], ops.formatVector(vectors[i], indexInfo.dimension), JSON.stringify(metadata?.[i] || {}));
985
+ }
986
+ const query = `
987
+ INSERT INTO ${tableName} (vector_id, embedding, metadata)
988
+ VALUES ${rows.join(", ")}
989
+ ON CONFLICT (vector_id)
990
+ DO UPDATE SET
991
+ embedding = EXCLUDED.embedding,
992
+ metadata = EXCLUDED.metadata
993
+ `;
994
+ await client.query(query, values);
995
+ }
977
996
  await client.query("COMMIT");
978
997
  this.logger?.debug(`Upserted ${vectors.length} vectors to ${indexName}`, {
979
998
  indexName,
@@ -2176,7 +2195,7 @@ async function loadSchemaSnapshot(client, schemaName) {
2176
2195
  const schema = schemaName || "public";
2177
2196
  const [tableRows, columnRows, indexRows] = await Promise.all([
2178
2197
  client.manyOrNone(`SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = $1`, [schema]),
2179
- client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name
2198
+ client.manyOrNone(`SELECT c.relname AS table_name, a.attname AS column_name, format_type(a.atttypid, a.atttypmod) AS data_type
2180
2199
  FROM pg_catalog.pg_class c
2181
2200
  JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
2182
2201
  JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
@@ -2191,6 +2210,7 @@ async function loadSchemaSnapshot(client, schemaName) {
2191
2210
  WHERE n.nspname = $1`, [schema])
2192
2211
  ]);
2193
2212
  const columns = /* @__PURE__ */ new Map();
2213
+ const columnTypes = /* @__PURE__ */ new Map();
2194
2214
  for (const row of columnRows) {
2195
2215
  let set = columns.get(row.table_name);
2196
2216
  if (!set) {
@@ -2198,6 +2218,12 @@ async function loadSchemaSnapshot(client, schemaName) {
2198
2218
  columns.set(row.table_name, set);
2199
2219
  }
2200
2220
  set.add(row.column_name);
2221
+ let types = columnTypes.get(row.table_name);
2222
+ if (!types) {
2223
+ types = /* @__PURE__ */ new Map();
2224
+ columnTypes.set(row.table_name, types);
2225
+ }
2226
+ types.set(row.column_name, row.data_type);
2201
2227
  }
2202
2228
  const indexes = /* @__PURE__ */ new Set();
2203
2229
  const replicaIdentityIndexes = /* @__PURE__ */ new Set();
@@ -2211,6 +2237,7 @@ async function loadSchemaSnapshot(client, schemaName) {
2211
2237
  schemaName: schema,
2212
2238
  tables: new Set(tableRows.map((r) => r.tablename)),
2213
2239
  columns,
2240
+ columnTypes,
2214
2241
  indexes,
2215
2242
  replicaIdentityIndexes,
2216
2243
  primaryKeyIndexes
@@ -2464,6 +2491,8 @@ var PgDB = class extends _mastra_core_base.MastraBase {
2464
2491
  skipDefaultIndexes;
2465
2492
  /** Cache of actual table columns: tableName -> Set<columnName> */
2466
2493
  tableColumnsCache = /* @__PURE__ */ new Map();
2494
+ /** Cache of column Postgres data types: tableName -> columnName -> data_type */
2495
+ columnTypeCache = /* @__PURE__ */ new Map();
2467
2496
  constructor(config) {
2468
2497
  super({
2469
2498
  component: "STORAGE",
@@ -2538,7 +2567,9 @@ var PgDB = class extends _mastra_core_base.MastraBase {
2538
2567
  }
2539
2568
  }
2540
2569
  this.tableColumnsCache.delete(oldName);
2570
+ this.columnTypeCache.delete(oldName);
2541
2571
  this.tableColumnsCache.delete(newName);
2572
+ this.columnTypeCache.delete(newName);
2542
2573
  }
2543
2574
  /**
2544
2575
  * Records an out-of-band `DROP TABLE` in the init snapshot. See
@@ -2554,8 +2585,10 @@ var PgDB = class extends _mastra_core_base.MastraBase {
2554
2585
  if (snapshot) {
2555
2586
  snapshot.tables.delete(tableName);
2556
2587
  snapshot.columns.delete(tableName);
2588
+ snapshot.columnTypes.delete(tableName);
2557
2589
  }
2558
2590
  this.tableColumnsCache.delete(tableName);
2591
+ this.columnTypeCache.delete(tableName);
2559
2592
  }
2560
2593
  /**
2561
2594
  * Records an out-of-band `ALTER TABLE … ADD COLUMN` in the init snapshot.
@@ -2565,6 +2598,7 @@ var PgDB = class extends _mastra_core_base.MastraBase {
2565
2598
  const snapshot = this.schemaSnapshot;
2566
2599
  if (snapshot) this.snapshotColumns(snapshot, tableName).add(column);
2567
2600
  this.tableColumnsCache.delete(tableName);
2601
+ this.columnTypeCache.delete(tableName);
2568
2602
  }
2569
2603
  /**
2570
2604
  * Gets the set of column names that actually exist in the database table.
@@ -2607,6 +2641,50 @@ var PgDB = class extends _mastra_core_base.MastraBase {
2607
2641
  ]);
2608
2642
  }
2609
2643
  /**
2644
+ * Returns the Postgres data type of a column (e.g. `jsonb`, `json`, `text`),
2645
+ * or null when the table or column does not exist.
2646
+ *
2647
+ * Answered from the init snapshot when one is installed, so a warm `init()`
2648
+ * issues no catalog probe. Outside init, results are cached per instance and
2649
+ * the cache is invalidated alongside {@link tableColumnsCache} whenever DDL
2650
+ * changes a table.
2651
+ */
2652
+ async getColumnType(table, column) {
2653
+ const snapshot = this.schemaSnapshot;
2654
+ if (snapshot) {
2655
+ const types = snapshot.columnTypes.get(table);
2656
+ const known = types?.get(column) ?? types?.get(column.toLowerCase());
2657
+ if (known) return known;
2658
+ if (types) return null;
2659
+ }
2660
+ const cached = this.columnTypeCache.get(table)?.get(column);
2661
+ if (cached !== void 0) return cached;
2662
+ const schema = this.schemaName || "public";
2663
+ const dataType = (await this.client.oneOrNone(`SELECT data_type FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND (column_name = $3 OR column_name = $4)`, [
2664
+ schema,
2665
+ table,
2666
+ column,
2667
+ column.toLowerCase()
2668
+ ]))?.data_type ?? null;
2669
+ if (dataType) {
2670
+ if (snapshot) {
2671
+ let snapshotTypes = snapshot.columnTypes.get(table);
2672
+ if (!snapshotTypes) {
2673
+ snapshotTypes = /* @__PURE__ */ new Map();
2674
+ snapshot.columnTypes.set(table, snapshotTypes);
2675
+ }
2676
+ snapshotTypes.set(column, dataType);
2677
+ }
2678
+ let types = this.columnTypeCache.get(table);
2679
+ if (!types) {
2680
+ types = /* @__PURE__ */ new Map();
2681
+ this.columnTypeCache.set(table, types);
2682
+ }
2683
+ types.set(column, dataType);
2684
+ }
2685
+ return dataType;
2686
+ }
2687
+ /**
2610
2688
  * Prepares values for insertion, handling JSONB columns by stringifying them
2611
2689
  */
2612
2690
  prepareValuesForInsert(record, tableName) {
@@ -2805,6 +2883,7 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
2805
2883
  }, error);
2806
2884
  } finally {
2807
2885
  this.tableColumnsCache.delete(tableName);
2886
+ this.columnTypeCache.delete(tableName);
2808
2887
  }
2809
2888
  }
2810
2889
  async setupTimestampTriggers(tableName) {
@@ -3127,6 +3206,7 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
3127
3206
  }, error);
3128
3207
  } finally {
3129
3208
  this.tableColumnsCache.delete(tableName);
3209
+ this.columnTypeCache.delete(tableName);
3130
3210
  }
3131
3211
  }
3132
3212
  async load({ tableName, keys }) {
@@ -3190,6 +3270,7 @@ MIGRATION REQUIRED: Duplicate spans detected in ${duplicateInfo.tableName}\n====
3190
3270
  }, error);
3191
3271
  } finally {
3192
3272
  this.tableColumnsCache.delete(tableName);
3273
+ this.columnTypeCache.delete(tableName);
3193
3274
  }
3194
3275
  }
3195
3276
  async createIndex(options) {
@@ -3741,6 +3822,7 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
3741
3822
  "workspace",
3742
3823
  "skills",
3743
3824
  "skillsFormat",
3825
+ "durable",
3744
3826
  "browser",
3745
3827
  "toolProviders"
3746
3828
  ]
@@ -4220,10 +4302,10 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
4220
4302
  "defaultOptions", workflows, agents, "integrationTools", "toolProviders",
4221
4303
  "inputProcessors", "outputProcessors", memory, scorers,
4222
4304
  "mcpClients", "requestContextSchema", workspace, skills, "skillsFormat",
4223
- browser,
4305
+ durable, browser,
4224
4306
  "changedFields", "changeMessage",
4225
4307
  "createdAt", "createdAtZ"
4226
- ) 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)`, [
4308
+ ) 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)`, [
4227
4309
  input.id,
4228
4310
  input.agentId,
4229
4311
  input.versionNumber,
@@ -4246,6 +4328,7 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
4246
4328
  input.workspace ? JSON.stringify(input.workspace) : null,
4247
4329
  input.skills ? JSON.stringify(input.skills) : null,
4248
4330
  input.skillsFormat ?? null,
4331
+ input.durable !== void 0 ? JSON.stringify(input.durable) : null,
4249
4332
  input.browser ? JSON.stringify(input.browser) : null,
4250
4333
  input.changedFields ? JSON.stringify(input.changedFields) : null,
4251
4334
  input.changeMessage ?? null,
@@ -4474,6 +4557,7 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
4474
4557
  workspace: parseJsonResilient(row.workspace, "workspace"),
4475
4558
  skills: parseJsonResilient(row.skills, "skills"),
4476
4559
  skillsFormat: row.skillsFormat,
4560
+ durable: parseJsonResilient(row.durable, "durable"),
4477
4561
  browser: parseJsonResilient(row.browser, "browser"),
4478
4562
  changedFields: parseJsonResilient(row.changedFields, "changedFields"),
4479
4563
  changeMessage: row.changeMessage,
@@ -19322,6 +19406,29 @@ function getTableName({ indexName, schemaName }) {
19322
19406
  const quotedIndexName = `"${indexName}"`;
19323
19407
  return schemaName ? `${schemaName}.${quotedIndexName}` : quotedIndexName;
19324
19408
  }
19409
+ /** Base name (before any schema prefix) of the expression index backing the status filter. */
19410
+ const WORKFLOW_SNAPSHOT_STATUS_INDEX = "mastra_workflow_snapshot_name_status_createdat_idx";
19411
+ /**
19412
+ * Schema-prefixed name of the status index, lowercased and truncated the same way Postgres
19413
+ * stores it, so the init snapshot's index set answers "does it exist?" without a probe or a
19414
+ * no-op `CREATE INDEX` (schema-prefixed names routinely exceed the 63-byte limit).
19415
+ */
19416
+ function workflowSnapshotStatusIndexName(schemaName) {
19417
+ return buildConstraintName({
19418
+ baseName: WORKFLOW_SNAPSHOT_STATUS_INDEX,
19419
+ schemaName: schemaName && schemaName !== "public" ? schemaName : void 0
19420
+ });
19421
+ }
19422
+ /**
19423
+ * Expression index on `(workflow_name, snapshot->>'status', "createdAt" DESC)` so
19424
+ * listWorkflowRuns() status filters can use an index instead of scanning every snapshot.
19425
+ */
19426
+ function workflowSnapshotStatusIndexSQL(indexName, schemaName) {
19427
+ return `CREATE INDEX IF NOT EXISTS "${indexName}" ON ${getTableName({
19428
+ indexName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
19429
+ schemaName: getSchemaName(schemaName)
19430
+ })} (workflow_name, (snapshot ->> 'status'), "createdAt" DESC)`;
19431
+ }
19325
19432
  /**
19326
19433
  * Sanitizes JSON string for PostgreSQL jsonb:
19327
19434
  * - Removes problematic Unicode sequences:
@@ -19404,6 +19511,7 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
19404
19511
  includeAllConstraints: true
19405
19512
  }));
19406
19513
  for (const idx of WorkflowsPG.getDefaultIndexDefs(schemaPrefix)) statements.push(generateIndexSQL(idx, schemaName));
19514
+ statements.push(`${workflowSnapshotStatusIndexSQL(workflowSnapshotStatusIndexName(parsedSchema), schemaName)};`);
19407
19515
  return statements;
19408
19516
  }
19409
19517
  /**
@@ -19423,6 +19531,13 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
19423
19531
  } catch (error) {
19424
19532
  this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
19425
19533
  }
19534
+ if (await this.#db.getColumnType(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, "snapshot") !== "jsonb") return;
19535
+ const indexName = workflowSnapshotStatusIndexName(this.#schema);
19536
+ try {
19537
+ await this.#db.createIndexFromStatement(indexName, workflowSnapshotStatusIndexSQL(indexName, this.#schema));
19538
+ } catch (error) {
19539
+ this.logger?.warn?.(`Failed to create index ${indexName}:`, error);
19540
+ }
19426
19541
  }
19427
19542
  async init() {
19428
19543
  await this.#db.createTable({
@@ -19712,7 +19827,8 @@ var WorkflowsPG = class WorkflowsPG extends _mastra_core_storage.WorkflowsStorag
19712
19827
  paramIndex++;
19713
19828
  }
19714
19829
  if (status) {
19715
- conditions.push(`regexp_replace(snapshot::text, '\\\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})', '', 'g')::jsonb ->> 'status' = $${paramIndex}`);
19830
+ const statusExpr = await this.#db.getColumnType(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, "snapshot") === "jsonb" ? `snapshot ->> 'status'` : `regexp_replace(snapshot::text, '\\\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})', '', 'g')::jsonb ->> 'status'`;
19831
+ conditions.push(`${statusExpr} = $${paramIndex}`);
19716
19832
  values.push(status);
19717
19833
  paramIndex++;
19718
19834
  }