@mastra/oracledb 0.4.1 → 0.4.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-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.4.1"
6
+ version: "0.4.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.4.1",
2
+ "version": "0.4.2",
3
3
  "package": "@mastra/oracledb",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -128,7 +128,7 @@ export const agent = new Agent({
128
128
 
129
129
  Mastra inserts a temporal gap marker when the gap is at least 10 minutes. The marker is stored in memory and also emitted as a transient reminder event, so clients can render it as a lightweight timeline hint.
130
130
 
131
- The observer also sees these markers when it processes the thread, so the observations it writes can anchor memories to when they happened (for example, "User asked about deployment after a 2-day gap").
131
+ The observer also sees these markers when it processes the thread. The observations it writes can anchor memories to when they happened (for example, "User asked about deployment after a 2-day gap").
132
132
 
133
133
  See [the API reference](https://mastra.ai/reference/memory/observational-memory) for the full configuration shape.
134
134
 
@@ -191,13 +191,47 @@ const memory = new Memory({
191
191
 
192
192
  `bufferOnIdle` is off by default. It's separate from `bufferTokens`: `bufferTokens` controls step-time async buffering, while `bufferOnIdle` controls end-of-turn buffering for idle turns.
193
193
 
194
+ ### Retries and failure policy
195
+
196
+ Observer and Reflector model calls are retried on transient provider errors, and a turn aborts if they still fail. Each stage is controlled independently by:
197
+
198
+ - `maxRetries`: retries after the initial model call (default `8`).
199
+ - `failurePolicy`: what happens once retries are exhausted, either `'abort'` (default) or `'continue'`.
200
+
201
+ ```typescript
202
+ const memory = new Memory({
203
+ options: {
204
+ observationalMemory: {
205
+ observation: {
206
+ maxRetries: 8,
207
+ failurePolicy: 'continue',
208
+ },
209
+ reflection: {
210
+ maxRetries: 8,
211
+ failurePolicy: 'continue',
212
+ },
213
+ },
214
+ },
215
+ })
216
+ ```
217
+
218
+ `maxRetries` governs OM's own retry ladder; the underlying model call is configured with no provider-level retries, so the option is the single retry knob for the stage.
219
+
220
+ With `failurePolicy: 'continue'`, Mastra retries as configured, reports the failure through the existing OM diagnostics, keeps the failed input pending for a later cycle, and lets the main agent turn continue. It doesn't advance observation boundaries or discard unobserved messages. A Reflector failure under `'continue'` leaves any already-persisted observations committed and defers reflection to the next threshold crossing.
221
+
222
+ A provider outage usually takes out both stages, so set the policy on both if you want the turn to survive one.
223
+
224
+ This policy applies only to Observer and Reflector model and provider failures in synchronous, resource-scoped, and buffered observation. Persistence, indexing, transform, locking, invariant, and explicit abort failures remain fatal. It doesn't prevent the underlying provider or network error, change `blockAfter`, or change attachment handling.
225
+
226
+ > **Warning:** `'continue'` has no backstop for a sustained outage. Unobserved messages stay pending and keep accruing in the main agent's context. A long outage moves the failure from the memory layer to the model's context limit.
227
+
194
228
  See [the API reference](https://mastra.ai/reference/memory/observational-memory) for the full configuration shape.
195
229
 
196
230
  ## Benefits
197
231
 
198
232
  - **Prompt caching**: OM's context is stable and observations append over time rather than being retrieved at runtime each turn. This keeps the prompt prefix cacheable, which reduces costs.
199
233
  - **Compression**: Raw message history and tool results get compressed into a dense observation log. Smaller context means faster responses and longer coherent conversations.
200
- - **Zero context rot**: The agent sees relevant information instead of noisy tool calls and irrelevant tokens, so the agent stays on task over long sessions.
234
+ - **Zero context rot**: The agent sees relevant information instead of noisy tool calls and irrelevant tokens, which keeps the agent on task over long sessions.
201
235
 
202
236
  ## How it works
203
237
 
@@ -615,29 +649,42 @@ const memory = new Memory({
615
649
 
616
650
  Thread scope requires a valid `threadId` to be provided when calling the agent. If `threadId` is missing, Observational Memory throws an error. This prevents multiple threads from silently sharing a single observation record, which can cause database deadlocks.
617
651
 
618
- ### Resource scope (experimental)
652
+ ### Resource scope (deprecated)
653
+
654
+ > **Deprecated:** `scope: 'resource'` is deprecated and will be removed in a future release. Mastra logs a warning the first time Observational Memory is created with resource scope. Remove the `scope` option to use the default thread scope, and use the [alternatives below](#cross-thread-continuity-without-resource-scope) for cross-conversation continuity.
655
+
656
+ In resource scope, observations are shared across all threads for a resource (typically a user). Resource scope works much worse than thread scope for prompt caching and for the agent's understanding of the conversation:
657
+
658
+ - **Prompt caching:** Observations from every thread share one record. When any thread is observed, the observation context changes for all other threads, which invalidates their cached prompt prefix.
659
+ - **Agent understanding:** Each thread sees a mix of observations from every thread for the resource. Every new thread starts with context from earlier threads, and the agent may continue work that another thread started but didn't finish.
660
+ - **Performance:** Unobserved messages across _all_ threads are processed together, which is slow for users with many existing threads.
661
+
662
+ A new knowledge and subconscious memory primitive for cross-thread memory is coming soon and will replace resource scope. Until then, use the alternatives below.
663
+
664
+ #### Cross-thread continuity without resource scope
665
+
666
+ Switching from resource scope to thread scope doesn't migrate resource-scoped observations. Each thread uses its existing thread-scoped record if it has one, or starts a new, empty one, and messages already observed under resource scope aren't observed again. Keep facts that must carry over in resource-scoped working memory.
619
667
 
620
- Observations are shared across all threads for a resource (typically a user). Enables cross-conversation memory.
668
+ Use thread scope with one or both of these features instead:
669
+
670
+ - [Retrieval mode](#retrieval-mode): The agent gets a `recall` tool that can list and browse other threads for the same resource, and optionally search them semantically. The agent looks up earlier conversations only when it needs them.
671
+ - [Resource-scoped working memory](https://mastra.ai/docs/memory/working-memory): Stores small, durable facts about the user that every thread can read.
621
672
 
622
673
  ```typescript
623
674
  const memory = new Memory({
624
675
  options: {
625
676
  observationalMemory: {
626
677
  model: 'google/gemini-2.5-flash',
678
+ retrieval: true,
679
+ },
680
+ workingMemory: {
681
+ enabled: true,
627
682
  scope: 'resource',
628
683
  },
629
684
  },
630
685
  })
631
686
  ```
632
687
 
633
- Resource scope works, however it's marked as experimental for now until we prove task adherence/continuity across multiple ongoing simultaneous threads. As of today, you may need to tweak your system prompt to prevent one thread from continuing the work that another had already started (but hadn't finished).
634
-
635
- This is because in resource scope, each thread is a perspective on _all_ threads for the resource.
636
-
637
- For your use-case this may not be a problem, so your mileage may vary.
638
-
639
- > **Warning:** In resource scope, unobserved messages across _all_ threads are processed together. For users with many existing threads, this can be slow. Use thread scope for existing apps.
640
-
641
688
  ## Token budgets
642
689
 
643
690
  OM uses token thresholds to decide when to observe and reflect. See [token budget configuration](https://mastra.ai/reference/memory/observational-memory) for details.
@@ -786,7 +833,7 @@ const memory = new Memory({
786
833
 
787
834
  Setting `bufferTokens: false` disables both observation and reflection async buffering. See [async buffering configuration](https://mastra.ai/reference/memory/observational-memory) for the full API.
788
835
 
789
- > **Note:** Resource scope automatically disables async buffering.
836
+ > **Note:** Resource scope (deprecated) automatically disables async buffering.
790
837
 
791
838
  ## Observer Context Optimization
792
839
 
@@ -889,7 +936,7 @@ hooks: {
889
936
  No manual migration needed. OM reads existing messages and observes them lazily when thresholds are exceeded.
890
937
 
891
938
  - **Thread scope**: The first time a thread exceeds `observation.messageTokens`, the Observer processes the backlog.
892
- - **Resource scope**: All unobserved messages across all threads for a resource are processed together. For users with many existing threads, this could take substantial time.
939
+ - **Resource scope (deprecated)**: All unobserved messages across all threads for a resource are processed together. For users with many existing threads, this could take substantial time.
893
940
 
894
941
  ## Comparing OM with other memory features
895
942
 
@@ -202,7 +202,7 @@ async function retentionTick() {
202
202
  }
203
203
  ```
204
204
 
205
- You can also cancel a long-running prune with an `AbortSignal`: the loop stops between batches and returns partial results with `done: false`, so the next run resumes cleanly.
205
+ You can also cancel a long-running prune with an `AbortSignal`: the loop stops between batches and returns partial results with `done: false`. The next run resumes cleanly.
206
206
 
207
207
  ## ClickHouse native TTL
208
208
 
package/dist/index.cjs CHANGED
@@ -562,7 +562,7 @@ async function upsert(registry, withConnection, upsertBatchSize, { indexName, ve
562
562
  if (error instanceof _mastra_core_error.MastraError) throw error;
563
563
  throw asMastraError("UPSERT", "INVALID_INPUT", { indexName }, error, _mastra_core_error.ErrorCategory.USER);
564
564
  }
565
- const vectorIds = ids ?? vectors.map(() => (0, crypto$1.randomUUID)());
565
+ const vectorIds = ids ?? vectors.map(() => globalThis.crypto.randomUUID());
566
566
  return withConnection(async (connection) => {
567
567
  const indexInfo = await registry.getIndexMetadata(connection, indexName);
568
568
  try {
@@ -3464,7 +3464,7 @@ function parseBufferedChunks(value) {
3464
3464
  return parsed.map((chunk) => {
3465
3465
  const item = chunk;
3466
3466
  return {
3467
- id: String(item.id ?? `ombuf-${(0, crypto$1.randomUUID)()}`),
3467
+ id: String(item.id ?? `ombuf-${globalThis.crypto.randomUUID()}`),
3468
3468
  cycleId: String(item.cycleId ?? ""),
3469
3469
  observations: String(item.observations ?? ""),
3470
3470
  tokenCount: Math.round(numberOrZero(item.tokenCount)),
@@ -4348,7 +4348,7 @@ async function getObservationalMemoryHistory(ctx, threadId, resourceId, limit =
4348
4348
  async function initializeObservationalMemory(ctx, input) {
4349
4349
  const now = /* @__PURE__ */ new Date();
4350
4350
  const record = {
4351
- id: (0, crypto$1.randomUUID)(),
4351
+ id: globalThis.crypto.randomUUID(),
4352
4352
  scope: input.scope,
4353
4353
  threadId: input.threadId,
4354
4354
  resourceId: input.resourceId,
@@ -4425,7 +4425,7 @@ async function updateActiveObservations(ctx, input) {
4425
4425
  async function createReflectionGeneration(ctx, input) {
4426
4426
  const now = /* @__PURE__ */ new Date();
4427
4427
  const record = {
4428
- id: (0, crypto$1.randomUUID)(),
4428
+ id: globalThis.crypto.randomUUID(),
4429
4429
  scope: input.currentRecord.scope,
4430
4430
  threadId: input.currentRecord.threadId,
4431
4431
  resourceId: input.currentRecord.resourceId,
@@ -4749,7 +4749,7 @@ async function updateBufferedObservations(ctx, input) {
4749
4749
  await ctx.db.tx(async (_client, connection) => {
4750
4750
  const existingChunks = parseBufferedChunks((await lockOMRow(ctx, connection, input.id, "UPDATE_BUFFERED_OBSERVATIONS")).bufferedObservationChunks);
4751
4751
  const newChunk = {
4752
- id: `ombuf-${(0, crypto$1.randomUUID)()}`,
4752
+ id: `ombuf-${globalThis.crypto.randomUUID()}`,
4753
4753
  cycleId: input.chunk.cycleId,
4754
4754
  observations: input.chunk.observations,
4755
4755
  tokenCount: Math.round(input.chunk.tokenCount),
@@ -4855,7 +4855,7 @@ async function swapBufferedReflectionToActive(ctx, input) {
4855
4855
  const now = /* @__PURE__ */ new Date();
4856
4856
  const lockedRecord = parseOMRow(row);
4857
4857
  const newRecord = {
4858
- id: (0, crypto$1.randomUUID)(),
4858
+ id: globalThis.crypto.randomUUID(),
4859
4859
  scope: lockedRecord.scope,
4860
4860
  threadId: lockedRecord.threadId,
4861
4861
  resourceId: lockedRecord.resourceId,
@@ -5489,7 +5489,7 @@ var MemoryOracle = class MemoryOracle extends _mastra_core_storage.MemoryStorage
5489
5489
  const sourceThread = await this.getThreadById({ threadId: args.sourceThreadId });
5490
5490
  if (!sourceThread) throw storageError$1("CLONE_THREAD", "FAILED", { threadId: args.sourceThreadId }, /* @__PURE__ */ new Error(`Thread ${args.sourceThreadId} not found`), _mastra_core_error.ErrorCategory.USER);
5491
5491
  const sourceMessages = await this.messagesForClone(args);
5492
- const newThreadId = args.newThreadId ?? (0, crypto$1.randomUUID)();
5492
+ const newThreadId = args.newThreadId ?? globalThis.crypto.randomUUID();
5493
5493
  if (await this.getThreadById({ threadId: newThreadId })) throw storageError$1("CLONE_THREAD", "DESTINATION_EXISTS", { threadId: newThreadId }, /* @__PURE__ */ new Error(`Thread ${newThreadId} already exists`), _mastra_core_error.ErrorCategory.USER);
5494
5494
  const now = /* @__PURE__ */ new Date();
5495
5495
  const cloneMetadata = {
@@ -5511,7 +5511,7 @@ var MemoryOracle = class MemoryOracle extends _mastra_core_storage.MemoryStorage
5511
5511
  };
5512
5512
  const messageIdMap = {};
5513
5513
  const clonedMessages = sourceMessages.map((message) => {
5514
- const newMessageId = (0, crypto$1.randomUUID)();
5514
+ const newMessageId = globalThis.crypto.randomUUID();
5515
5515
  messageIdMap[message.id] = newMessageId;
5516
5516
  return {
5517
5517
  ...message,
@@ -5988,7 +5988,7 @@ async function batchCreateLogs(db, schemaName, args) {
5988
5988
  try {
5989
5989
  const binds = args.logs.map((log) => logRecordBinds({
5990
5990
  ...log,
5991
- logId: log.logId ?? (0, crypto$1.randomUUID)(),
5991
+ logId: log.logId ?? globalThis.crypto.randomUUID(),
5992
5992
  executionSource: log.executionSource ?? log.source ?? null
5993
5993
  }));
5994
5994
  await db.tx(async (client) => {
@@ -6245,7 +6245,7 @@ function transformObservabilityScoreRow(row) {
6245
6245
  };
6246
6246
  }
6247
6247
  function scoreRecordToTableRecord(score) {
6248
- const id = score.scoreId ?? (0, crypto$1.randomUUID)();
6248
+ const id = score.scoreId ?? globalThis.crypto.randomUUID();
6249
6249
  const timestamp = score.timestamp instanceof Date ? score.timestamp : new Date(score.timestamp ?? Date.now());
6250
6250
  const source = score.scoreSource ?? score.source ?? "observability";
6251
6251
  const contextualMetadata = removeUndefined({
@@ -7594,7 +7594,7 @@ var ScoresOracle = class ScoresOracle extends _mastra_core_storage.ScoresStorage
7594
7594
  }, error, _mastra_core_error.ErrorCategory.USER);
7595
7595
  }
7596
7596
  try {
7597
- const id = (0, crypto$1.randomUUID)();
7597
+ const id = globalThis.crypto.randomUUID();
7598
7598
  const now = /* @__PURE__ */ new Date();
7599
7599
  await this.db.insert({
7600
7600
  tableName: _mastra_core_storage.TABLE_SCORERS,