@mastra/memory 1.16.0-alpha.1 → 1.16.0-alpha.3

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/_types/@internal_ai-sdk-v4/dist/index.d.ts +51 -5
  3. package/dist/{chunk-HB6AYAFD.js → chunk-25XLVCFF.js} +150 -15
  4. package/dist/chunk-25XLVCFF.js.map +1 -0
  5. package/dist/{chunk-3NECGYWZ.cjs → chunk-3MHY4GB4.cjs} +150 -15
  6. package/dist/chunk-3MHY4GB4.cjs.map +1 -0
  7. package/dist/docs/SKILL.md +1 -1
  8. package/dist/docs/assets/SOURCE_MAP.json +47 -47
  9. package/dist/docs/references/docs-agents-supervisor-agents.md +18 -0
  10. package/dist/docs/references/docs-memory-observational-memory.md +4 -0
  11. package/dist/index.cjs +14 -13
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.ts +1 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +5 -4
  16. package/dist/index.js.map +1 -1
  17. package/dist/{observational-memory-X4N2R4CA.cjs → observational-memory-FPGLTCDV.cjs} +26 -26
  18. package/dist/{observational-memory-X4N2R4CA.cjs.map → observational-memory-FPGLTCDV.cjs.map} +1 -1
  19. package/dist/{observational-memory-WWAB2MMI.js → observational-memory-IL63MWVI.js} +3 -3
  20. package/dist/{observational-memory-WWAB2MMI.js.map → observational-memory-IL63MWVI.js.map} +1 -1
  21. package/dist/processors/index.cjs +24 -24
  22. package/dist/processors/index.js +1 -1
  23. package/dist/processors/observational-memory/markers.d.ts +3 -1
  24. package/dist/processors/observational-memory/markers.d.ts.map +1 -1
  25. package/dist/processors/observational-memory/message-utils.d.ts.map +1 -1
  26. package/dist/processors/observational-memory/model-context.d.ts +10 -0
  27. package/dist/processors/observational-memory/model-context.d.ts.map +1 -0
  28. package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
  29. package/dist/processors/observational-memory/observation-turn/turn.d.ts +3 -0
  30. package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
  31. package/dist/processors/observational-memory/observational-memory.d.ts +9 -1
  32. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  33. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  34. package/dist/processors/observational-memory/reflector-runner.d.ts +5 -2
  35. package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
  36. package/dist/processors/observational-memory/types.d.ts +19 -2
  37. package/dist/processors/observational-memory/types.d.ts.map +1 -1
  38. package/package.json +4 -4
  39. package/dist/chunk-3NECGYWZ.cjs.map +0 -1
  40. package/dist/chunk-HB6AYAFD.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 1.16.0-alpha.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed a security issue where several parsing and tracing paths could slow down on malformed or attacker-crafted input. Normal behavior is unchanged, and these packages now handle pathological input in linear time. ([#15566](https://github.com/mastra-ai/mastra/pull/15566))
8
+
9
+ - Updated dependencies [[`aba393e`](https://github.com/mastra-ai/mastra/commit/aba393e2da7390c69b80e516a4f153cda6f09376), [`0a5fa1d`](https://github.com/mastra-ai/mastra/commit/0a5fa1d3cb0583889d06687155f26fd7d2edc76c), [`ea43e64`](https://github.com/mastra-ai/mastra/commit/ea43e646dd95d507694b6112b0bf1df22ad552b2), [`00d1b16`](https://github.com/mastra-ai/mastra/commit/00d1b16b401199cb294fa23f43336547db4dca9b), [`af8a57e`](https://github.com/mastra-ai/mastra/commit/af8a57ed9ba9685ad8601d5b71ae3706da6222f9)]:
10
+ - @mastra/core@1.26.0-alpha.10
11
+
12
+ ## 1.16.0-alpha.2
13
+
14
+ ### Minor Changes
15
+
16
+ - Added `activateOnProviderChange` so observational memory can activate buffered observations and reflections before switching to a different provider or model. ([#15420](https://github.com/mastra-ai/mastra/pull/15420))
17
+
18
+ ```ts
19
+ const memory = new Memory({
20
+ options: {
21
+ observationalMemory: {
22
+ model: 'google/gemini-2.5-flash',
23
+ activateOnProviderChange: true,
24
+ },
25
+ },
26
+ });
27
+ ```
28
+
29
+ This helps keep prompt-cache savings when the next step cannot reuse the previous provider's cache.
30
+
31
+ ### Patch Changes
32
+
33
+ - Fixed early observational memory activations so buffered reflections are only activated when they still leave a healthy active observation set. ([#15462](https://github.com/mastra-ai/mastra/pull/15462))
34
+
35
+ Before this change, idle-timeout (`activateAfterIdle`) and model/provider-change (`activateOnProviderChange`) activations could swap in a buffered reflection too early. In bad cases, that replaced a large raw observation tail with a much smaller mostly-compressed result, which hurt reflection quality.
36
+
37
+ Early activations now stay buffered unless both of these checks pass:
38
+ - The unreflected observation tail is at least as large as the buffered reflection, so the activated result is not dominated by compressed content.
39
+ - The combined post-activation size is at least 75% of what a normal threshold activation would produce, so early activations do not cliff far below the regular target.
40
+
41
+ This update also fixes false `provider_change` activations when older persisted messages only contain a bare model id like `gpt-5.4` while newer turns use the fully qualified `provider/modelId` form.
42
+
43
+ - Updated dependencies [[`0474c2b`](https://github.com/mastra-ai/mastra/commit/0474c2b2e7c7e1ad8691dca031284841391ff1ef), [`f607106`](https://github.com/mastra-ai/mastra/commit/f607106854c6416c4a07d4082604b9f66d047221), [`62919a6`](https://github.com/mastra-ai/mastra/commit/62919a6ee0fbf3779ad21a97b1ec6696515d5104), [`0fd90a2`](https://github.com/mastra-ai/mastra/commit/0fd90a215caf5fca8099c15a67ca03e4427747a3)]:
44
+ - @mastra/core@1.26.0-alpha.4
45
+
3
46
  ## 1.16.0-alpha.1
4
47
 
5
48
  ### Patch Changes
@@ -195,6 +195,8 @@ export declare interface Attachment {
195
195
  * Attributes is a map from string to attribute values.
196
196
  *
197
197
  * Note: only the own enumerable keys are counted as valid attribute keys.
198
+ *
199
+ * @since 1.3.0
198
200
  */
199
201
  declare interface Attributes {
200
202
  [attributeKey: string]: AttributeValue | undefined;
@@ -204,6 +206,8 @@ declare interface Attributes {
204
206
  * Attribute values may be any non-nullish primitive value except an object.
205
207
  *
206
208
  * null or undefined attribute values are invalid and will result in undefined behavior.
209
+ *
210
+ * @since 1.3.0
207
211
  */
208
212
  declare type AttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
209
213
 
@@ -1057,6 +1061,9 @@ declare type ConsumeStreamOptions = {
1057
1061
  onError?: (error: unknown) => void;
1058
1062
  };
1059
1063
 
1064
+ /**
1065
+ * @since 1.0.0
1066
+ */
1060
1067
  declare interface Context {
1061
1068
  /**
1062
1069
  * Get a value from the context.
@@ -1735,6 +1742,8 @@ declare const errorStreamPart: AssistantStreamPart<'3', 'error', string>;
1735
1742
  * Defines Exception.
1736
1743
  *
1737
1744
  * string or an object with one of (message or name or code) and optional stack
1745
+ *
1746
+ * @since 1.0.0
1738
1747
  */
1739
1748
  declare type Exception = ExceptionWithCode | ExceptionWithMessage | ExceptionWithName | string;
1740
1749
 
@@ -2770,6 +2779,8 @@ export declare interface GenerateTextResult<TOOLS extends ToolSet, OUTPUT> {
2770
2779
  * The second number is calculated by converting the digits after the decimal point of the subtraction, (1609504210150 / 1000) - HrTime[0], to nanoseconds:
2771
2780
  * HrTime[1] = Number((1609504210.150 - HrTime[0]).toFixed(9)) * 1e9 = 150000000.
2772
2781
  * This is represented in HrTime format as [1609504210, 150000000].
2782
+ *
2783
+ * @since 1.0.0
2773
2784
  */
2774
2785
  declare type HrTime = [number, number];
2775
2786
 
@@ -4420,6 +4431,8 @@ declare interface LanguageModelV1ToolResultPart {
4420
4431
  * However, it is desirable to associate incoming SpanContext to new trace
4421
4432
  * initiated on service provider side so two traces (from Client and from
4422
4433
  * Service Provider) can be correlated.
4434
+ *
4435
+ * @since 1.0.0
4423
4436
  */
4424
4437
  declare interface Link {
4425
4438
  /** The {@link SpanContext} of a linked span. */
@@ -5289,6 +5302,8 @@ declare type SourceUIPart = {
5289
5302
  * may have children.
5290
5303
  *
5291
5304
  * Spans are created by the {@link Tracer.startSpan} method.
5305
+ *
5306
+ * @since 1.0.0
5292
5307
  */
5293
5308
  declare interface Span {
5294
5309
  /**
@@ -5348,11 +5363,21 @@ declare interface Span {
5348
5363
  */
5349
5364
  addLinks(links: Link[]): this;
5350
5365
  /**
5351
- * Sets a status to the span. If used, this will override the default Span
5352
- * status. Default is {@link SpanStatusCode.UNSET}. SetStatus overrides the value
5353
- * of previous calls to SetStatus on the Span.
5366
+ * Sets the status of the span.
5367
+ *
5368
+ * By default, a span has status {@link SpanStatusCode.UNSET}.
5369
+ * Calling this method overrides that default.
5370
+ *
5371
+ * The status codes have a total order: `OK > ERROR > UNSET`.
5372
+ *
5373
+ * - Once {@link SpanStatusCode.OK} is set, any further attempts to change
5374
+ * the status are ignored.
5375
+ * - Any attempt to set {@link SpanStatusCode.UNSET} is always ignored.
5376
+ *
5377
+ * The `message` field is only used when {@link SpanStatusCode.ERROR} is set.
5378
+ * For all other status codes, `message` is ignored.
5354
5379
  *
5355
- * @param status the SpanStatus to set.
5380
+ * @param status The {@link SpanStatus} to set.
5356
5381
  */
5357
5382
  setStatus(status: SpanStatus): this;
5358
5383
  /**
@@ -5397,17 +5422,21 @@ declare interface Span {
5397
5422
 
5398
5423
  /**
5399
5424
  * @deprecated please use {@link Attributes}
5425
+ * @since 1.0.0
5400
5426
  */
5401
5427
  declare type SpanAttributes = Attributes;
5402
5428
 
5403
5429
  /**
5404
5430
  * @deprecated please use {@link AttributeValue}
5431
+ * @since 1.0.0
5405
5432
  */
5406
5433
  declare type SpanAttributeValue = AttributeValue;
5407
5434
 
5408
5435
  /**
5409
5436
  * A SpanContext represents the portion of a {@link Span} which must be
5410
5437
  * serialized and propagated along side of a {@link Baggage}.
5438
+ *
5439
+ * @since 1.0.0
5411
5440
  */
5412
5441
  declare interface SpanContext {
5413
5442
  /**
@@ -5457,6 +5486,9 @@ declare interface SpanContext {
5457
5486
  traceState?: TraceState;
5458
5487
  }
5459
5488
 
5489
+ /**
5490
+ * @since 1.0.0
5491
+ */
5460
5492
  declare enum SpanKind {
5461
5493
  /** Default value. Indicates that the span is used internally. */
5462
5494
  INTERNAL = 0,
@@ -5486,6 +5518,8 @@ declare enum SpanKind {
5486
5518
 
5487
5519
  /**
5488
5520
  * Options needed for span creation
5521
+ *
5522
+ * @since 1.0.0
5489
5523
  */
5490
5524
  declare interface SpanOptions {
5491
5525
  /**
@@ -5494,7 +5528,7 @@ declare interface SpanOptions {
5494
5528
  */
5495
5529
  kind?: SpanKind;
5496
5530
  /** A span's attributes */
5497
- attributes?: SpanAttributes;
5531
+ attributes?: Attributes;
5498
5532
  /** {@link Link}s span to other spans */
5499
5533
  links?: Link[];
5500
5534
  /** A manually specified start time for the created `Span` object. */
@@ -5503,6 +5537,9 @@ declare interface SpanOptions {
5503
5537
  root?: boolean;
5504
5538
  }
5505
5539
 
5540
+ /**
5541
+ * @since 1.0.0
5542
+ */
5506
5543
  declare interface SpanStatus {
5507
5544
  /** The status code of this message. */
5508
5545
  code: SpanStatusCode;
@@ -5512,6 +5549,8 @@ declare interface SpanStatus {
5512
5549
 
5513
5550
  /**
5514
5551
  * An enumeration of status codes.
5552
+ *
5553
+ * @since 1.0.0
5515
5554
  */
5516
5555
  declare enum SpanStatusCode {
5517
5556
  /**
@@ -6741,6 +6780,8 @@ declare type TextUIPart = {
6741
6780
  * Defines TimeInput.
6742
6781
  *
6743
6782
  * hrtime, epoch milliseconds, performance.now() or Date
6783
+ *
6784
+ * @since 1.0.0
6744
6785
  */
6745
6786
  declare type TimeInput = HrTime | number | Date;
6746
6787
 
@@ -7087,6 +7128,8 @@ declare type ToToolsWithExecute<TOOLS extends ToolSet> = {
7087
7128
 
7088
7129
  /**
7089
7130
  * Tracer provides an interface for creating {@link Span}s.
7131
+ *
7132
+ * @since 1.0.0
7090
7133
  */
7091
7134
  declare interface Tracer {
7092
7135
  /**
@@ -7153,6 +7196,9 @@ declare interface Tracer {
7153
7196
  startActiveSpan<F extends (span: Span) => unknown>(name: string, options: SpanOptions, context: Context, fn: F): ReturnType<F>;
7154
7197
  }
7155
7198
 
7199
+ /**
7200
+ * @since 1.0.0
7201
+ */
7156
7202
  declare interface TraceState {
7157
7203
  /**
7158
7204
  * Create a new TraceState which inherits from this TraceState and has the
@@ -201,6 +201,19 @@ var BufferingCoordinator = class _BufferingCoordinator {
201
201
  }
202
202
  };
203
203
 
204
+ // src/processors/observational-memory/model-context.ts
205
+ function didProviderChange(actorModel, lastModel) {
206
+ if (actorModel === void 0 || lastModel === void 0) return false;
207
+ const actorHasSlash = actorModel.includes("/");
208
+ const lastHasSlash = lastModel.includes("/");
209
+ if (actorHasSlash && lastHasSlash) {
210
+ return actorModel !== lastModel;
211
+ }
212
+ const actorModelId = actorHasSlash ? actorModel.slice(actorModel.indexOf("/") + 1) : actorModel;
213
+ const lastModelId = lastHasSlash ? lastModel.slice(lastModel.indexOf("/") + 1) : lastModel;
214
+ return actorModelId !== lastModelId;
215
+ }
216
+
204
217
  // src/processors/observational-memory/date-utils.ts
205
218
  function formatRelativeTime(date, currentDate) {
206
219
  const diffMs = currentDate.getTime() - date.getTime();
@@ -487,7 +500,9 @@ function createActivationMarker(params) {
487
500
  observations: params.observations,
488
501
  triggeredBy: params.triggeredBy,
489
502
  lastActivityAt: params.lastActivityAt,
490
- ttlExpiredMs: params.ttlExpiredMs
503
+ ttlExpiredMs: params.ttlExpiredMs,
504
+ previousModel: params.previousModel,
505
+ currentModel: params.currentModel
491
506
  }
492
507
  };
493
508
  }
@@ -637,7 +652,7 @@ function sortThreadsByOldestMessage(messagesByThread) {
637
652
  })).sort((a, b) => a.oldestTimestamp - b.oldestTimestamp).map((t) => t.threadId);
638
653
  }
639
654
  function stripThreadTags(observations) {
640
- return observations.replace(/<thread[^>]*>|<\/thread>/gi, "").trim();
655
+ return observations.replace(/<\/?thread\b[^>]{0,1024}>/gi, "").trim();
641
656
  }
642
657
 
643
658
  // src/processors/observational-memory/model-by-input-tokens.ts
@@ -1982,6 +1997,7 @@ var ObservationStep = class {
1982
1997
  resourceId,
1983
1998
  checkThreshold: true,
1984
1999
  messages: step0Messages,
2000
+ currentModel: this.turn.actorModelContext,
1985
2001
  writer: this.turn.writer,
1986
2002
  messageList
1987
2003
  });
@@ -2005,6 +2021,8 @@ var ObservationStep = class {
2005
2021
  observationTokens: obsTokens,
2006
2022
  threadId,
2007
2023
  writer: this.turn.writer,
2024
+ messageList,
2025
+ currentModel: this.turn.actorModelContext,
2008
2026
  requestContext: this.turn.requestContext,
2009
2027
  observabilityContext: this.turn.observabilityContext,
2010
2028
  lastActivityAt: getLastActivityFromMessages(messageList.get.all.db())
@@ -2171,6 +2189,7 @@ var ObservationStep = class {
2171
2189
  threadId,
2172
2190
  resourceId,
2173
2191
  messages: messageList.get.all.db(),
2192
+ currentModel: this.turn.actorModelContext,
2174
2193
  writer: this.turn.writer,
2175
2194
  messageList
2176
2195
  });
@@ -2182,6 +2201,7 @@ var ObservationStep = class {
2182
2201
  threadId,
2183
2202
  writer: this.turn.writer,
2184
2203
  messageList,
2204
+ currentModel: this.turn.actorModelContext,
2185
2205
  requestContext: this.turn.requestContext,
2186
2206
  observabilityContext: this.turn.observabilityContext,
2187
2207
  lastActivityAt: getLastActivityFromMessages(messageList.get.all.db())
@@ -2226,6 +2246,8 @@ var ObservationTurn = class {
2226
2246
  requestContext;
2227
2247
  /** Optional observability context for nested OM spans. */
2228
2248
  observabilityContext;
2249
+ /** Current actor model for this step. Updated by the processor before prepare(). */
2250
+ actorModelContext;
2229
2251
  /** Optional processor-provided hooks for turn/step lifecycle integration. */
2230
2252
  hooks;
2231
2253
  constructor(opts) {
@@ -4094,12 +4116,44 @@ function validateCompression(reflectedTokens, targetThreshold) {
4094
4116
  }
4095
4117
 
4096
4118
  // src/processors/observational-memory/reflector-runner.ts
4119
+ function formatModelContext(provider, modelId) {
4120
+ if (provider && modelId) {
4121
+ return `${provider}/${modelId}`;
4122
+ }
4123
+ return modelId;
4124
+ }
4125
+ function getCurrentModel(model) {
4126
+ return formatModelContext(model?.provider, model?.modelId);
4127
+ }
4128
+ function getLastModelFromMessageList(messageList) {
4129
+ const messages = messageList?.get.all.db();
4130
+ if (!messages) return void 0;
4131
+ for (let i = messages.length - 1; i >= 0; i--) {
4132
+ const message = messages[i];
4133
+ if (!message || message.role !== "assistant" || !message.content || typeof message.content === "string") {
4134
+ continue;
4135
+ }
4136
+ for (let j = message.content.parts.length - 1; j >= 0; j--) {
4137
+ const part = message.content.parts[j];
4138
+ if (part?.type === "step-start" && typeof part.model === "string" && part.model.length > 0) {
4139
+ return part.model;
4140
+ }
4141
+ }
4142
+ const metadata = message.content.metadata;
4143
+ const model = formatModelContext(metadata?.provider, metadata?.modelId);
4144
+ if (model) {
4145
+ return model;
4146
+ }
4147
+ }
4148
+ return void 0;
4149
+ }
4097
4150
  async function withAbortCheck(fn, abortSignal) {
4098
4151
  if (abortSignal?.aborted) throw new Error("The operation was aborted.");
4099
4152
  const result = await fn();
4100
4153
  if (abortSignal?.aborted) throw new Error("The operation was aborted.");
4101
4154
  return result;
4102
4155
  }
4156
+ var EARLY_ACTIVATION_SIZE_FLOOR_RATIO = 0.75;
4103
4157
  var ReflectorRunner = class {
4104
4158
  reflectionConfig;
4105
4159
  observationConfig;
@@ -4424,7 +4478,9 @@ var ReflectorRunner = class {
4424
4478
  }
4425
4479
  /**
4426
4480
  * Try to activate buffered reflection when threshold is reached.
4427
- * Returns true if activation succeeded.
4481
+ * Returns a discriminated result so the caller can distinguish between
4482
+ * "activated", "no buffer present", and "suppressed by overshoot guard"
4483
+ * without re-deriving that state.
4428
4484
  */
4429
4485
  async tryActivateBufferedReflection(record, lockKey, writer, messageList, activationMetadata) {
4430
4486
  const bufferKey = this.buffering.getReflectionBufferKey(lockKey);
@@ -4447,8 +4503,8 @@ var ReflectorRunner = class {
4447
4503
  `[OM:reflect] tryActivateBufferedReflection: freshRecord.id=${freshRecord?.id}, freshBufferedReflection=${freshRecord?.bufferedReflection ? "present (" + freshRecord.bufferedReflection.length + " chars)" : "empty"}, freshObsTokens=${freshRecord?.observationTokenCount}`
4448
4504
  );
4449
4505
  if (!freshRecord?.bufferedReflection) {
4450
- omDebug(`[OM:reflect] tryActivateBufferedReflection: no buffered reflection after re-fetch, returning false`);
4451
- return false;
4506
+ omDebug(`[OM:reflect] tryActivateBufferedReflection: no buffered reflection after re-fetch`);
4507
+ return { status: "no-buffer" };
4452
4508
  }
4453
4509
  const beforeTokens = freshRecord.observationTokenCount ?? 0;
4454
4510
  const reflectedLineCount = freshRecord.reflectedObservationLineCount ?? 0;
@@ -4460,6 +4516,26 @@ var ReflectorRunner = class {
4460
4516
 
4461
4517
  ${unreflectedContent}` : freshRecord.bufferedReflection;
4462
4518
  const combinedTokenCount = this.tokenCounter.countObservations(combinedObservations);
4519
+ if (activationMetadata?.triggeredBy === "ttl" || activationMetadata?.triggeredBy === "provider_change") {
4520
+ const unreflectedTailTokens = unreflectedContent ? this.tokenCounter.countObservations(unreflectedContent) : 0;
4521
+ const bufferedReflectionTokens = freshRecord.bufferedReflectionTokens ?? 0;
4522
+ if (unreflectedTailTokens < bufferedReflectionTokens) {
4523
+ omDebug(
4524
+ `[OM:reflect] tryActivateBufferedReflection: suppressing early ${activationMetadata.triggeredBy} activation \u2014 unreflectedTailTokens=${unreflectedTailTokens} < bufferedReflectionTokens=${bufferedReflectionTokens}; keeping buffer for threshold activation`
4525
+ );
4526
+ return { status: "suppressed", reason: "composition" };
4527
+ }
4528
+ const bufferActivation = this.reflectionConfig.bufferActivation;
4529
+ const reflectThreshold = getMaxThreshold(this.getEffectiveReflectionTokens(freshRecord));
4530
+ const regularActivationTarget = reflectThreshold * (1 - bufferActivation);
4531
+ const minCombinedTokens = Math.round(regularActivationTarget * EARLY_ACTIVATION_SIZE_FLOOR_RATIO);
4532
+ if (combinedTokenCount < minCombinedTokens) {
4533
+ omDebug(
4534
+ `[OM:reflect] tryActivateBufferedReflection: suppressing early ${activationMetadata.triggeredBy} activation \u2014 combinedTokenCount=${combinedTokenCount} < minCombinedTokens=${minCombinedTokens} (${EARLY_ACTIVATION_SIZE_FLOOR_RATIO * 100}% of regular activation target ${Math.round(regularActivationTarget)}, threshold=${reflectThreshold}, bufferActivation=${bufferActivation}); keeping buffer for threshold activation`
4535
+ );
4536
+ return { status: "suppressed", reason: "size" };
4537
+ }
4538
+ }
4463
4539
  omDebug(
4464
4540
  `[OM:reflect] tryActivateBufferedReflection: activating, beforeTokens=${beforeTokens}, combinedTokenCount=${combinedTokenCount}, reflectedLineCount=${reflectedLineCount}, unreflectedLines=${unreflectedLines.length}`
4465
4541
  );
@@ -4489,6 +4565,8 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4489
4565
  triggeredBy: activationMetadata?.triggeredBy,
4490
4566
  lastActivityAt: activationMetadata?.lastActivityAt,
4491
4567
  ttlExpiredMs: activationMetadata?.ttlExpiredMs,
4568
+ previousModel: activationMetadata?.previousModel,
4569
+ currentModel: activationMetadata?.currentModel,
4492
4570
  config: this.getObservationMarkerConfig(freshRecord)
4493
4571
  });
4494
4572
  void writer.custom(activationMarker).catch(() => {
@@ -4501,7 +4579,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4501
4579
  );
4502
4580
  }
4503
4581
  BufferingCoordinator.reflectionBufferCycleIds.delete(bufferKey);
4504
- return true;
4582
+ return { status: "activated" };
4505
4583
  }
4506
4584
  /**
4507
4585
  * Check if reflection needed and trigger if so.
@@ -4515,6 +4593,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4515
4593
  writer,
4516
4594
  abortSignal,
4517
4595
  messageList,
4596
+ currentModel,
4518
4597
  reflectionHooks,
4519
4598
  requestContext,
4520
4599
  observabilityContext,
@@ -4554,13 +4633,19 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4554
4633
  const activateAfterIdle = this.reflectionConfig.activateAfterIdle;
4555
4634
  const ttlExpiredMs = activateAfterIdle !== void 0 && lastActivityAt !== void 0 ? Date.now() - lastActivityAt : void 0;
4556
4635
  const ttlExpired = ttlExpiredMs !== void 0 && activateAfterIdle !== void 0 && ttlExpiredMs >= activateAfterIdle;
4557
- if (observationTokens < reflectThreshold && !ttlExpired) {
4636
+ const actorModel = getCurrentModel(currentModel);
4637
+ const lastModel = getLastModelFromMessageList(messageList);
4638
+ const providerChanged = this.reflectionConfig.activateOnProviderChange === true && didProviderChange(actorModel, lastModel);
4639
+ if (observationTokens < reflectThreshold && !ttlExpired && !providerChanged) {
4558
4640
  return;
4559
4641
  }
4642
+ const activationTriggeredBy = observationTokens >= reflectThreshold ? "threshold" : providerChanged ? "provider_change" : "ttl";
4560
4643
  const activationMetadata = {
4561
- triggeredBy: ttlExpired ? "ttl" : "threshold",
4562
- lastActivityAt: ttlExpired ? lastActivityAt : void 0,
4563
- ttlExpiredMs: ttlExpired ? ttlExpiredMs : void 0
4644
+ triggeredBy: activationTriggeredBy,
4645
+ lastActivityAt: activationTriggeredBy === "ttl" ? lastActivityAt : void 0,
4646
+ ttlExpiredMs: activationTriggeredBy === "ttl" ? ttlExpiredMs : void 0,
4647
+ previousModel: activationTriggeredBy === "provider_change" ? lastModel : void 0,
4648
+ currentModel: activationTriggeredBy === "provider_change" ? actorModel : void 0
4564
4649
  };
4565
4650
  if (record.isReflecting) {
4566
4651
  if (isOpActiveInProcess(record.id, "reflecting")) {
@@ -4571,14 +4656,20 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4571
4656
  await this.storage.setReflectingFlag(record.id, false);
4572
4657
  }
4573
4658
  if (this.buffering.isAsyncReflectionEnabled()) {
4574
- const activationSuccess = await this.tryActivateBufferedReflection(
4659
+ const activationResult = await this.tryActivateBufferedReflection(
4575
4660
  record,
4576
4661
  lockKey,
4577
4662
  writer,
4578
4663
  messageList,
4579
4664
  activationMetadata
4580
4665
  );
4581
- if (activationSuccess) {
4666
+ if (activationResult.status === "activated") {
4667
+ return;
4668
+ }
4669
+ if (activationResult.status === "suppressed") {
4670
+ omDebug(
4671
+ `[OM:reflect] skipping sync fallback / re-buffer after suppressed early ${activationMetadata.triggeredBy} activation (reason=${activationResult.reason})`
4672
+ );
4582
4673
  return;
4583
4674
  }
4584
4675
  if (this.reflectionConfig.blockAfter && observationTokens >= this.reflectionConfig.blockAfter) {
@@ -6279,6 +6370,36 @@ function getLastActivityFromMessages(messages) {
6279
6370
  }
6280
6371
  return void 0;
6281
6372
  }
6373
+ function formatModelContext2(provider, modelId) {
6374
+ if (provider && modelId) {
6375
+ return `${provider}/${modelId}`;
6376
+ }
6377
+ return modelId;
6378
+ }
6379
+ function getLastModelFromMessages(messages) {
6380
+ if (!messages) return void 0;
6381
+ for (let i = messages.length - 1; i >= 0; i--) {
6382
+ const message = messages[i];
6383
+ if (!message || message.role !== "assistant" || !message.content || typeof message.content === "string") {
6384
+ continue;
6385
+ }
6386
+ for (let j = message.content.parts.length - 1; j >= 0; j--) {
6387
+ const part = message.content.parts[j];
6388
+ if (part?.type === "step-start" && typeof part.model === "string" && part.model.length > 0) {
6389
+ return part.model;
6390
+ }
6391
+ }
6392
+ const metadata = message.content.metadata;
6393
+ const model = formatModelContext2(metadata?.provider, metadata?.modelId);
6394
+ if (model) {
6395
+ return model;
6396
+ }
6397
+ }
6398
+ return void 0;
6399
+ }
6400
+ function getCurrentModel2(model) {
6401
+ return formatModelContext2(model?.provider, model?.modelId);
6402
+ }
6282
6403
  function parseActivationTTL(value, fieldPath) {
6283
6404
  if (value === void 0) {
6284
6405
  return void 0;
@@ -6455,6 +6576,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
6455
6576
  ),
6456
6577
  bufferActivation: asyncBufferingDisabled ? void 0 : config.observation?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferActivation,
6457
6578
  activateAfterIdle: parseActivationTTL(config.activateAfterIdle, "activateAfterIdle"),
6579
+ activateOnProviderChange: config.activateOnProviderChange ?? false,
6458
6580
  blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(
6459
6581
  config.observation?.blockAfter ?? (config.observation?.bufferTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferTokens ? 1.2 : void 0),
6460
6582
  config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens
@@ -6474,6 +6596,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
6474
6596
  providerOptions: config.reflection?.providerOptions ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.providerOptions,
6475
6597
  bufferActivation: asyncBufferingDisabled ? void 0 : config?.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation,
6476
6598
  activateAfterIdle: parseActivationTTL(config.activateAfterIdle, "activateAfterIdle"),
6599
+ activateOnProviderChange: config.activateOnProviderChange ?? false,
6477
6600
  blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(
6478
6601
  config.reflection?.blockAfter ?? (config.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation ? 1.2 : void 0),
6479
6602
  config.reflection?.observationTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens
@@ -8370,6 +8493,8 @@ ${grouped}` : grouped;
8370
8493
  let activationTriggeredBy = "threshold";
8371
8494
  let activationLastActivityAt;
8372
8495
  let activateAfterIdleExpiredMs;
8496
+ let previousModel;
8497
+ let currentModel;
8373
8498
  if (opts.checkThreshold) {
8374
8499
  const thresholdMessages = opts.messages ?? await this.loadMessagesFromStorage(
8375
8500
  threadId,
@@ -8380,7 +8505,14 @@ ${grouped}` : grouped;
8380
8505
  const lastActivityAt = getLastActivityFromMessages(thresholdMessages);
8381
8506
  const ttlExpiredMs = activateAfterIdle !== void 0 && lastActivityAt !== void 0 ? Date.now() - lastActivityAt : void 0;
8382
8507
  const ttlExpired = ttlExpiredMs !== void 0 && activateAfterIdle !== void 0 && ttlExpiredMs >= activateAfterIdle;
8383
- if (ttlExpired) {
8508
+ const actorModel = getCurrentModel2(opts.currentModel);
8509
+ const lastModel = getLastModelFromMessages(thresholdMessages);
8510
+ const providerChanged = this.observationConfig.activateOnProviderChange === true && didProviderChange(actorModel, lastModel);
8511
+ if (providerChanged) {
8512
+ activationTriggeredBy = "provider_change";
8513
+ previousModel = lastModel;
8514
+ currentModel = actorModel;
8515
+ } else if (ttlExpired) {
8384
8516
  activationTriggeredBy = "ttl";
8385
8517
  activationLastActivityAt = lastActivityAt;
8386
8518
  activateAfterIdleExpiredMs = ttlExpiredMs;
@@ -8449,6 +8581,8 @@ ${grouped}` : grouped;
8449
8581
  triggeredBy: activationTriggeredBy,
8450
8582
  lastActivityAt: activationLastActivityAt,
8451
8583
  ttlExpiredMs: activateAfterIdleExpiredMs,
8584
+ previousModel,
8585
+ currentModel,
8452
8586
  config: this.getObservationMarkerConfig()
8453
8587
  });
8454
8588
  void opts.writer.custom(activationMarker).catch(() => {
@@ -8806,6 +8940,7 @@ var ObservationalMemoryProcessor = class {
8806
8940
  const observabilityContext = getOmObservabilityContext(args);
8807
8941
  state.__omObservabilityContext = observabilityContext;
8808
8942
  this.turn.observabilityContext = observabilityContext;
8943
+ this.turn.actorModelContext = actorModelContext;
8809
8944
  {
8810
8945
  const step = this.turn.step(stepNumber);
8811
8946
  let ctx;
@@ -8939,5 +9074,5 @@ function getObservationsAsOf(activeObservations, asOf) {
8939
9074
  }
8940
9075
 
8941
9076
  export { ModelByInputTokens, OBSERVER_SYSTEM_PROMPT, ObservationalMemory, ObservationalMemoryProcessor, TokenCounter, buildObserverPrompt, buildObserverSystemPrompt, combineObservationGroupRanges, deriveObservationGroupProvenance, extractCurrentTask, formatMessagesForObserver, formatToolResultForObserver, getObservationsAsOf, hasCurrentTaskSection, injectAnchorIds, optimizeObservationsForContext, parseAnchorId, parseObservationGroups, parseObserverOutput, reconcileObservationGroupsFromReflection, renderObservationGroupsForReflection, resolveToolResultValue, stripEphemeralAnchorIds, stripObservationGroups, truncateStringByTokens, wrapInObservationGroup };
8942
- //# sourceMappingURL=chunk-HB6AYAFD.js.map
8943
- //# sourceMappingURL=chunk-HB6AYAFD.js.map
9077
+ //# sourceMappingURL=chunk-25XLVCFF.js.map
9078
+ //# sourceMappingURL=chunk-25XLVCFF.js.map