@mastra/oracledb 0.5.0 → 0.5.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-oracledb
3
3
  description: Documentation for @mastra/oracledb. Use when working with @mastra/oracledb APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/oracledb"
6
- version: "0.5.0"
6
+ version: "0.5.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.5.0",
2
+ "version": "0.5.1",
3
3
  "package": "@mastra/oracledb",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -76,7 +76,7 @@ console.log(secondResponse.text)
76
76
 
77
77
  The `resource` identifies the user or entity, while the `thread` identifies the conversation. Reuse both values to continue the same conversation. Observational Memory processes the stored history as it grows and replaces older messages with observations when its activation conditions are met.
78
78
 
79
- The agent now has humanlike long-term memory that persists across conversations. Setting `observationalMemory: true` uses `google/gemini-2.5-flash` by default. To use a different model, pass it in the config object:
79
+ The agent now has humanlike long-term memory that persists across conversations. Setting `observationalMemory: true` uses automatic model selection. To use a specific model, pass it in the config object:
80
80
 
81
81
  ```typescript
82
82
  const memory = new Memory({
@@ -98,7 +98,17 @@ See [configuration options](https://mastra.ai/reference/memory/observational-mem
98
98
  >
99
99
  > For an AI SDK example, see [Using Mastra Memory](https://mastra.ai/integrations/agentic-ui/ai-sdk-ui).
100
100
 
101
- > **Note:** OM currently only supports `@mastra/pg`, `@mastra/libsql`, `@mastra/mysql`, `@mastra/mongodb`, `@mastra/convex`, and `@mastra/oracledb` storage adapters. It uses background agents for managing memory. When no model is set, the default model is `google/gemini-2.5-flash`.
101
+ > **Note:** OM currently only supports `@mastra/pg`, `@mastra/libsql`, `@mastra/mysql`, `@mastra/mongodb`, `@mastra/convex`, and `@mastra/oracledb` storage adapters. It uses background agents for managing memory. When no model is set, the default is `model: 'auto'`.
102
+
103
+ ### Automatic models in Mastra Code and Factory
104
+
105
+ Mastra Code and Factory surface the same automatic selection as a per-role **Auto** option in their settings.
106
+
107
+ An automatic Observer or Reflector follows the active main model provider. Mastra Code uses that provider's built-in low-cost Observational Memory model when one is configured. For custom providers and providers without a built-in choice, it uses the active main model. The effective model is resolved when the role runs, so changing the main model doesn't rewrite the saved automatic selection.
108
+
109
+ Select an explicit model to pin one role independently. Reset that role to **Auto** to resume following the main model provider. Existing saved concrete model IDs remain explicit until you reset them.
110
+
111
+ Factory stores automatic intent separately from the effective model shown in settings. A missing provider credential can mark that effective model unavailable, but it doesn't replace the saved selection or prevent Factory from starting.
102
112
 
103
113
  ## Temporal gap markers
104
114
 
@@ -418,6 +428,8 @@ new Agent({
418
428
 
419
429
  You can also pass an allowlist of mimeType globs (for example `['image/*']`) to forward only the kinds the Observer can handle. Alternatively, set `observeAttachments: 'auto'` so Mastra consults the provider capabilities registry. It forwards attachments when the Observer model supports multimodal input and drops them otherwise. If capability data is unavailable for the model, the setting falls back to `true`.
420
430
 
431
+ Attachments that the agent recorded as unavailable, because they could no longer be downloaded, are never sent to the Observer. The Observer still sees their `[Image #1: ...]` or `[File #1: ...]` line. See [attachment download failures](https://mastra.ai/docs/agents/processors) for how Mastra records them.
432
+
421
433
  ```md
422
434
  Date: 2026-01-15
423
435
 
@@ -568,11 +580,30 @@ The progress bars update live while the agent is observing or reflecting, showin
568
580
 
569
581
  ## Models
570
582
 
571
- The Observer and Reflector run in the background. Any model that works with Mastra's [model routing](https://mastra.ai/models) (`provider/model`) can be used. When no model is set, the default model is `google/gemini-2.5-flash`.
583
+ The Observer and Reflector run in the background. Any model that works with Mastra's [model routing](https://mastra.ai/models) (`provider/model`) can be used. When no model is set, the default is `model: 'auto'`.
584
+
585
+ Automatic selection uses `google/gemini-2.5-flash` when `GOOGLE_GENERATIVE_AI_API_KEY` is configured. Otherwise, it selects a low-cost model for the active main model's provider, then falls back to the active main model. Observer and Reflector resolve independently before each invocation.
586
+
587
+ Automatic selection reads the main model's `provider/model` ID. Models created from a plain model string carry that ID, and a dynamic model function can label a custom model by returning `{ model, id }`. When the ID is unknown, such as a model with a custom URL, API key, headers, or gateway, automatic selection reuses the main model itself because a sibling model isn't known to share that route. Pass a concrete model ID to the role to override either behavior.
588
+
589
+ Use `autoModels` to change the model picked for a provider, and `resolveModel` to create the picked model with your own credentials or routing:
590
+
591
+ ```typescript
592
+ const memory = new Memory({
593
+ options: {
594
+ observationalMemory: {
595
+ autoModels: { openai: 'openai/gpt-5-nano' },
596
+ resolveModel: (modelId, { requestContext }) => createRoutedModel(modelId, requestContext),
597
+ },
598
+ },
599
+ })
600
+ ```
601
+
602
+ `resolveAutoModelId(mainModelId, { autoModels })` from `@mastra/memory` returns the model automatic selection would pick, which is useful for showing the effective model in a settings UI.
572
603
 
573
604
  Mastra recommends using a model that has a large context window (128K+ tokens) and is fast enough to run in the background without slowing down your actions.
574
605
 
575
- If you're unsure which model to use, start with the default `google/gemini-2.5-flash`. We've also successfully tested `openai/gpt-5-mini`, `anthropic/claude-haiku-4-5`, `deepseek/deepseek-reasoner`, `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`, `xai/grok-4-1-fast`, `qwen3`, and `glm-4.7`.
606
+ To pin a model instead, set a concrete model ID. We've also successfully tested `openai/gpt-5-mini`, `anthropic/claude-haiku-4-5`, `deepseek/deepseek-reasoner`, `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`, `xai/grok-4-1-fast`, `qwen3`, and `glm-4.7`.
576
607
 
577
608
  ```typescript
578
609
  const memory = new Memory({
@@ -765,7 +796,7 @@ When message tokens reach the `messageTokens` threshold, buffered chunks activat
765
796
 
766
797
  Async buffered Observer calls don't generate continuation hints because delayed hints can be stale by activation time. When buffered chunks activate, any previously stored suggested response and current task are cleared. The main agent receives the compressed observations without those hints.
767
798
 
768
- When message production outpaces the Observer, the `blockAfter` safety threshold allows activation to overshoot the retention target instead of using fewer chunks. Activation still uses no more chunks than needed to reach the target, and the default settings remain unaffected. A synchronous observation runs when the `messageTokens` threshold is reached and buffered activation didn't happen. Buffered activation usually preserves a minimum remaining context (the smaller of \~1k tokens or the configured retention floor), but a single buffered chunk that covers the whole pending window still activates and can leave less.
799
+ When message production outpaces the Observer, the `blockAfter` safety threshold allows activation to overshoot the retention target instead of using fewer chunks. Activation still uses no more chunks than needed to reach the target, and the default settings remain unaffected. A synchronous observation runs when the `messageTokens` threshold is reached and activating buffered chunks doesn't bring pending tokens back under it. For example, this happens when a large tool result arrives after buffering has stopped. Buffered activation usually preserves a minimum remaining context (the smaller of \~1k tokens or the configured retention floor), but a single buffered chunk that covers the whole pending window still activates and can leave less.
769
800
 
770
801
  Reflection works similarly: the Reflector runs in the background when observations reach a fraction of the reflection threshold.
771
802
 
@@ -776,7 +807,7 @@ Reflection works similarly: the Reflector runs in the background when observatio
776
807
  | `observation.bufferTokens` | `0.2` | How often to buffer. `0.2` means every 20% of `messageTokens`. With the default 30k threshold, that's roughly every 6k tokens. Can also be an absolute token count (e.g. `5000`). |
777
808
  | `observation.bufferActivation` | `0.8` | How aggressively to clear the message window on activation. `0.8` means remove enough messages to keep only 20% of `messageTokens` remaining. Lower values keep more message history. |
778
809
  | `observation.blockAfter` | `1.2` | Safety net if buffering can't keep up. Values from 1 up to (but not including) 100 multiply `messageTokens`. For example, `1.2` creates a threshold of 36k tokens (1.2 × 30k), above which activation may overshoot the retention target rather than use fewer chunks. Values of 100 or more are absolute token counts (e.g. `50_000`) and must be greater than `messageTokens`. |
779
- | `activateAfterIdle` | none | Forces buffered observations to activate after a period of inactivity, even before `observation.messageTokens` is reached. Accepts a numeric millisecond value such as `300_000`, duration strings like `"5m"` or `"1hr"`, or `"auto"` for a provider-aware prompt cache TTL. |
810
+ | `activateAfterIdle` | none | Forces buffered observations to activate after a period of inactivity, even before `observation.messageTokens` is reached. Accepts a numeric millisecond value such as `300_000`, duration strings like `"5m"` or `"1hr"`, `"auto"` for a provider-aware prompt cache TTL, or an object of per-provider TTLs such as `{ default: 'auto', anthropic: '1h' }`. |
780
811
  | `activateOnProviderChange` | `false` | Forces buffered observations to activate when the next step uses a different `provider/model` than the one that produced the latest assistant step. Use this when switching providers or models would invalidate prompt cache reuse. |
781
812
  | `reflection.bufferActivation` | `0.5` | When to start background reflection. `0.5` means reflection begins when observations reach 50% of the `observationTokens` threshold. |
782
813
  | `reflection.activateAfterIdle` | none | Opts buffered reflections into idle activation. Reflections don't inherit top-level `activateAfterIdle`. |
@@ -814,6 +845,30 @@ With `"auto"`, this activates buffered observations based on the active provider
814
845
 
815
846
  Changing models or providers mid-thread will invalidate the prompt cache. If your agent can switch between providers or models mid-thread, `activateOnProviderChange: true` forces buffered observations to activate before the new provider runs. That avoids sending a large raw window to a provider that can't reuse the previous prompt cache.
816
847
 
848
+ #### Per-provider idle TTLs
849
+
850
+ `"auto"` can't see a cache TTL that you set on individual messages, such as Anthropic's `cacheControl: { type: 'ephemeral', ttl: '1h' }`. It keeps using the provider's 5-minute default, so buffered observations activate while the 1-hour cache is still warm. Pass an object to set the TTL per provider instead:
851
+
852
+ ```typescript
853
+ const memory = new Memory({
854
+ options: {
855
+ observationalMemory: {
856
+ model: 'google/gemini-2.5-flash',
857
+ activateAfterIdle: { default: 'auto', anthropic: '1h' },
858
+ },
859
+ },
860
+ })
861
+ ```
862
+
863
+ Set the `anthropic` entry to the same TTL as your `cacheControl.ttl`. Mastra doesn't read the per-message cache setting, so the two must be kept in sync by hand.
864
+
865
+ How the object resolves:
866
+
867
+ - Keys are provider names. Mastra compares them case-insensitively with the part of the model's provider before the first `.`, so `anthropic` matches both `anthropic` and `anthropic.messages`. Claude served through another provider uses that provider's key instead, for example `amazon-bedrock`. Keys must not contain `.` or `/`.
868
+ - Each value accepts the same forms as a single TTL: milliseconds, a duration string, `"auto"`, or `false` to turn off idle activation for that provider.
869
+ - `default` applies to every provider without its own key. Without `default`, those providers don't idle-activate.
870
+ - `observation.activateAfterIdle` and `reflection.activateAfterIdle` accept the same object. An `observation.activateAfterIdle` object replaces the top-level value and isn't merged with it.
871
+
817
872
  ### Disabling
818
873
 
819
874
  To disable async buffering and use synchronous observation/reflection instead:
@@ -20,7 +20,7 @@ After getting a response from the LLM, all new messages (user, assistant, and to
20
20
 
21
21
  ## Quickstart
22
22
 
23
- Semantic recall is disabled by default. To enable it, set `semanticRecall: true` in `options` and provide a `vector` store and `embedder`:
23
+ Semantic recall is disabled by default. To enable it, set `semanticRecall: true` in `options` and provide a `vector` store and an `embedder`. A store that generates embeddings itself, such as MongoDB with Automated Embedding, works without one. See [Server-side embeddings](#server-side-embeddings).
24
24
 
25
25
  **LibSQL**:
26
26
 
@@ -242,6 +242,40 @@ const options = {
242
242
  }
243
243
  ```
244
244
 
245
+ ## Server-side embeddings
246
+
247
+ Some vector stores generate the embeddings themselves. With one of those, semantic recall runs without an `embedder`: the database embeds each message on write and the search string on arrival. The embedding provider stays out of your application entirely.
248
+
249
+ MongoDB does this through [Automated Embedding](https://mastra.ai/reference/vectors/mongodb): name a Voyage AI model on the vector store and leave the `embedder` out.
250
+
251
+ ```typescript
252
+ import { Memory } from '@mastra/memory'
253
+ import { MongoDBStore, MongoDBVector } from '@mastra/mongodb'
254
+
255
+ const memory = new Memory({
256
+ storage: new MongoDBStore({
257
+ id: 'agent-storage',
258
+ uri: process.env.MONGODB_URI,
259
+ dbName: process.env.MONGODB_DB_NAME,
260
+ }),
261
+ vector: new MongoDBVector({
262
+ id: 'agent-vector',
263
+ uri: process.env.MONGODB_URI,
264
+ dbName: process.env.MONGODB_DB_NAME,
265
+ autoEmbed: { model: 'voyage-4' },
266
+ }),
267
+ options: {
268
+ semanticRecall: { topK: 3, messageRange: 2 },
269
+ },
270
+ })
271
+ ```
272
+
273
+ Messages are stored as text and MongoDB embeds them, so the model choice and the vector size belong to the index rather than to your application. Recall works the same way through an agent and through [`recall()`](#using-the-recall-method).
274
+
275
+ MongoDB embeds newly written messages in the background. A message saved moments ago may not be recallable immediately.
276
+
277
+ Every other store expects your application to supply the vectors, and keeps requiring an `embedder`. Enabling semantic recall with neither an `embedder` nor a store that embeds server-side raises an error naming both options.
278
+
245
279
  ## Embedder configuration
246
280
 
247
281
  Semantic recall relies on an [embedding model](https://mastra.ai/reference/memory/memory-class) to convert messages into embeddings. Mastra supports embedding models through the model router using `provider/model` strings, or you can use any [embedding model](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings) compatible with the AI SDK.
@@ -377,11 +411,11 @@ PostgreSQL supports both IVFFlat and HNSW indexes. By default, Mastra creates an
377
411
 
378
412
  ```typescript
379
413
  import { Memory } from '@mastra/memory'
380
- import { PgStore, PgVector } from '@mastra/pg'
414
+ import { PostgresStore, PgVector } from '@mastra/pg'
381
415
 
382
416
  const agent = new Agent({
383
417
  memory: new Memory({
384
- storage: new PgStore({
418
+ storage: new PostgresStore({
385
419
  id: 'agent-storage',
386
420
  connectionString: process.env.DATABASE_URL,
387
421
  }),
@@ -272,6 +272,22 @@ Schema-based working memory uses **merge semantics**, meaning the agent only nee
272
272
  - **Set a field to `null` to delete it:** This explicitly removes the field from memory
273
273
  - **Arrays are replaced entirely:** When an array field is provided, it replaces the existing array (arrays aren't merged element-by-element)
274
274
 
275
+ ### Concurrent updates
276
+
277
+ With `scope: 'resource'` and a storage adapter that supports atomic merges (currently `@mastra/pg`), each merge runs inside a row-locked database transaction. Concurrent updates to different fields from separate processes are all kept. Other adapters merge in the application, which only serializes writers inside a single process.
278
+
279
+ To merge a partial update from your own code, call `memory.mergeWorkingMemory()`:
280
+
281
+ ```typescript
282
+ await memory.mergeWorkingMemory({
283
+ threadId: 'thread-1',
284
+ resourceId: 'user-123',
285
+ workingMemory: { preferences: { tone: 'formal' } },
286
+ })
287
+ ```
288
+
289
+ It throws if working memory isn't schema-based and resource-scoped, or if the storage adapter doesn't support atomic merges. Check `await memory.supportsAtomicWorkingMemoryMerge()` first if you need to fall back.
290
+
275
291
  ## Choosing between template and schema
276
292
 
277
293
  - Use a **template** (Markdown) if you want the agent to maintain memory as a free-form text block, such as a user profile or scratchpad. Templates use **replace semantics**: the agent must provide the complete memory content on each update.
@@ -194,6 +194,7 @@ Each provider page includes installation instructions, configuration parameters,
194
194
 
195
195
  - [Aurora DSQL](https://mastra.ai/integrations/databases/aurora-dsql)
196
196
  - [ClickHouse](https://mastra.ai/integrations/databases/clickhouse)
197
+ - [ClickHouse Managed Postgres](https://mastra.ai/integrations/databases/clickhouse-managed-postgres)
197
198
  - [Cloudflare D1](https://mastra.ai/integrations/databases/cloudflare-d1)
198
199
  - [Cloudflare KV](https://mastra.ai/integrations/databases/cloudflare-kv)
199
200
  - [Convex](https://mastra.ai/integrations/databases/convex)
@@ -231,7 +231,7 @@ await store.createIndex({
231
231
  - [libSQL](https://mastra.ai/reference/vectors/libsql)
232
232
  - [MongoDB](https://mastra.ai/reference/vectors/mongodb)
233
233
  - [OracleDB](https://mastra.ai/reference/vectors/oracledb)
234
- - [PgStore](https://mastra.ai/reference/vectors/pg)
234
+ - [PgVector](https://mastra.ai/reference/vectors/pg)
235
235
  - [Pinecone](https://mastra.ai/reference/vectors/pinecone)
236
236
  - [Qdrant](https://mastra.ai/reference/vectors/qdrant)
237
237
  - [Upstash](https://mastra.ai/reference/vectors/upstash)
@@ -50,23 +50,25 @@ console.log(results)
50
50
 
51
51
  The `topK` parameter specifies the maximum number of most similar results to return from the vector search.
52
52
 
53
- Results include both the text content and a similarity score:
53
+ Each result includes an `id`, a similarity `score`, and the stored `metadata`. When you store chunk text in metadata, it's available as `metadata.text`:
54
54
 
55
55
  ```ts
56
56
  [
57
57
  {
58
- text: 'Climate change poses significant challenges...',
58
+ id: 'chunk-1',
59
59
  score: 0.89,
60
- metadata: { source: 'article1.txt' },
60
+ metadata: { text: 'Climate change poses significant challenges...', source: 'article1.txt' },
61
61
  },
62
62
  {
63
- text: 'Rising temperatures affect crop yields...',
63
+ id: 'chunk-2',
64
64
  score: 0.82,
65
- metadata: { source: 'article1.txt' },
65
+ metadata: { text: 'Rising temperatures affect crop yields...', source: 'article1.txt' },
66
66
  },
67
67
  ]
68
68
  ```
69
69
 
70
+ Results can also include `vector` when you set `includeVector: true`, and `document` when the store returns the original document (Chroma only).
71
+
70
72
  ## Advanced retrieval options
71
73
 
72
74
  ### Metadata Filtering
@@ -230,7 +230,7 @@ await store.upsert({
230
230
  **libSQL**:
231
231
 
232
232
  ```ts
233
- import { LibSQLVector } from '@mastra/core/vector/libsql'
233
+ import { LibSQLVector } from '@mastra/libsql'
234
234
 
235
235
  const store = new LibSQLVector({
236
236
  id: 'libsql-vector',
@@ -95,29 +95,32 @@ Set the `retention` field on the store config.
95
95
 
96
96
  Each domain specifies its age-prunable tables and the timestamp column that anchors comparison, chosen so `maxAge` matches the meaning of the data. Append-only logs use creation time, live state uses last activity, and jobs or runs use completion time so in-flight work isn't pruned.
97
97
 
98
- | Domain | Table key | Anchor column | `maxAge` measures |
99
- | ----------------- | ------------------ | ---------------- | ---------------------------------------------------------------- |
100
- | `memory` | `threads` | `createdAt` | Thread age |
101
- | `memory` | `messages` | `createdAt` | Message age |
102
- | `memory` | `resources` | `createdAt` | Resource age |
103
- | `threadState` | `threadState` | `updatedAt` | Inactivity: state for still-active threads survives |
104
- | `observability` | `spans` | `startedAt` | Span age |
105
- | `observability` | `metrics` | `timestamp` | Metric event age (vNext only) |
106
- | `observability` | `logs` | `timestamp` | Log event age (vNext only) |
107
- | `observability` | `scores` | `timestamp` | Score event age (vNext only) |
108
- | `observability` | `feedback` | `timestamp` | Feedback event age (vNext only) |
109
- | `scores` | `scorers` | `createdAt` | Score record age |
110
- | `workflows` | `workflowSnapshot` | `updatedAt` | Inactivity, suspended or long-running workflows survive |
111
- | `backgroundTasks` | `backgroundTasks` | `completedAt` | Time since completion, in-flight tasks (`NULL`) are never pruned |
112
- | `experiments` | `experiments` | `completedAt` | Time since completion, running experiments are never pruned |
113
- | `notifications` | `notifications` | `createdAt` | Notification age |
114
- | `harness` | `sessions` | `createdAt` | Session record age |
115
- | `schedules` | `triggers` | `actual_fire_at` | Fire-history age (epoch-ms column) |
98
+ | Domain | Table key | Anchor column | `maxAge` measures |
99
+ | ----------------- | ------------------ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------- |
100
+ | `memory` | `threads` | `createdAt` | Thread age |
101
+ | `memory` | `messages` | `createdAt` | Message age |
102
+ | `memory` | `resources` | `createdAt` | Resource age |
103
+ | `memory` | `runFences` | `retiredAt` | Time since the durable agent execution holding the fence settled. Fences of running executions (`NULL`) are never pruned |
104
+ | `threadState` | `threadState` | `updatedAt` | Inactivity: state for still-active threads survives |
105
+ | `observability` | `spans` | `startedAt` | Span age |
106
+ | `observability` | `metrics` | `timestamp` | Metric event age (vNext only) |
107
+ | `observability` | `logs` | `timestamp` | Log event age (vNext only) |
108
+ | `observability` | `scores` | `timestamp` | Score event age (vNext only) |
109
+ | `observability` | `feedback` | `timestamp` | Feedback event age (vNext only) |
110
+ | `scores` | `scorers` | `createdAt` | Score record age |
111
+ | `workflows` | `workflowSnapshot` | `updatedAt` | Inactivity, suspended or long-running workflows survive |
112
+ | `workflows` | `runOwnership` | `updatedAt` | Inactivity. A running durable agent execution renews its claim every 10 seconds, so keep `maxAge` well above its 30-second lease |
113
+ | `backgroundTasks` | `backgroundTasks` | `completedAt` | Time since completion, in-flight tasks (`NULL`) are never pruned |
114
+ | `experiments` | `experiments` | `completedAt` | Time since completion, running experiments are never pruned |
115
+ | `notifications` | `notifications` | `createdAt` | Notification age |
116
+ | `harness` | `sessions` | `createdAt` | Session record age |
117
+ | `schedules` | `triggers` | `actual_fire_at` | Fire-history age (epoch-ms column) |
116
118
 
117
119
  > **Note:**
118
120
  >
119
121
  > - The memory `observational_memory` table has no timestamp anchor, so it can't be age-pruned and isn't a valid retention key.
120
122
  > - Experiments prune as whole units: an aged experiment's result rows are deleted together with it (results cascade with their parent), so a run is never left partially deleted. Retention doesn't have a separate `results` key.
123
+ > - `runOwnership` and `runFences` hold the run fencing records of durable agents, one small record per run in each. If the `runOwnership` `maxAge` is too short, a running execution can lose its run, but an execution that lost a run still can't write. A fence is retired only when its execution settles, so the fence of a run that crashed and was never recovered is never pruned.
121
124
  > - For `schedules`, the growth table is the fire history (`schedule_triggers`, one row per fire): schedule definitions are config and aren't pruned.
122
125
  > - On PostgreSQL, timestamp anchors use the timezone-aware mirror columns (for example `createdAtZ`, `completedAtZ`).
123
126
  > - DuckDB observability stores append-only events for all five signals. Its `spans` policy uses the event `timestamp` column rather than `startedAt`.
package/dist/index.cjs CHANGED
@@ -7999,7 +7999,7 @@ var WorkflowsOracle = class WorkflowsOracle extends _mastra_core_storage.Workflo
7999
7999
  async dangerouslyClearAll() {
8000
8000
  await this.db.clearTable(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
8001
8001
  }
8002
- async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext }) {
8002
+ async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state }) {
8003
8003
  try {
8004
8004
  return await this.db.tx(async (client) => {
8005
8005
  await this.ensureWorkflowRunRow(client, workflowName, runId);
@@ -8009,6 +8009,7 @@ var WorkflowsOracle = class WorkflowsOracle extends _mastra_core_storage.Workflo
8009
8009
  });
8010
8010
  const snapshot = parseSnapshot(existing.snapshot);
8011
8011
  snapshot.context[stepId] = result;
8012
+ if (state !== void 0) snapshot.context.__state = state;
8012
8013
  snapshot.requestContext = {
8013
8014
  ...snapshot.requestContext ?? {},
8014
8015
  ...requestContext