@mastra/memory 1.10.1-alpha.2 → 1.11.0-alpha.4

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 (53) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/{chunk-2QSOQQPM.js → chunk-D4D6ZFBQ.js} +567 -182
  3. package/dist/chunk-D4D6ZFBQ.js.map +1 -0
  4. package/dist/{chunk-NS47X3OB.cjs → chunk-VINRPDYQ.cjs} +567 -182
  5. package/dist/chunk-VINRPDYQ.cjs.map +1 -0
  6. package/dist/docs/SKILL.md +1 -1
  7. package/dist/docs/assets/SOURCE_MAP.json +47 -47
  8. package/dist/docs/references/docs-memory-observational-memory.md +49 -4
  9. package/dist/docs/references/reference-memory-observational-memory.md +32 -6
  10. package/dist/index.cjs +577 -36
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts +46 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +570 -29
  15. package/dist/index.js.map +1 -1
  16. package/dist/{observational-memory-I5UTOG63.cjs → observational-memory-FATH657E.cjs} +26 -26
  17. package/dist/{observational-memory-I5UTOG63.cjs.map → observational-memory-FATH657E.cjs.map} +1 -1
  18. package/dist/{observational-memory-WMCWT577.js → observational-memory-SN7GKMHZ.js} +3 -3
  19. package/dist/{observational-memory-WMCWT577.js.map → observational-memory-SN7GKMHZ.js.map} +1 -1
  20. package/dist/processors/index.cjs +24 -24
  21. package/dist/processors/index.js +1 -1
  22. package/dist/processors/observational-memory/observation-strategies/async-buffer.d.ts.map +1 -1
  23. package/dist/processors/observational-memory/observation-strategies/base.d.ts +9 -0
  24. package/dist/processors/observational-memory/observation-strategies/base.d.ts.map +1 -1
  25. package/dist/processors/observational-memory/observation-strategies/resource-scoped.d.ts.map +1 -1
  26. package/dist/processors/observational-memory/observation-strategies/sync.d.ts.map +1 -1
  27. package/dist/processors/observational-memory/observation-strategies/types.d.ts +2 -0
  28. package/dist/processors/observational-memory/observation-strategies/types.d.ts.map +1 -1
  29. package/dist/processors/observational-memory/observation-turn/index.d.ts +1 -1
  30. package/dist/processors/observational-memory/observation-turn/index.d.ts.map +1 -1
  31. package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
  32. package/dist/processors/observational-memory/observation-turn/turn.d.ts +19 -7
  33. package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
  34. package/dist/processors/observational-memory/observation-turn/types.d.ts +4 -0
  35. package/dist/processors/observational-memory/observation-turn/types.d.ts.map +1 -1
  36. package/dist/processors/observational-memory/observational-memory.d.ts +29 -2
  37. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  38. package/dist/processors/observational-memory/observer-runner.d.ts +14 -3
  39. package/dist/processors/observational-memory/observer-runner.d.ts.map +1 -1
  40. package/dist/processors/observational-memory/processor.d.ts +8 -12
  41. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  42. package/dist/processors/observational-memory/reflector-runner.d.ts +11 -1
  43. package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
  44. package/dist/processors/observational-memory/repro-capture.d.ts.map +1 -1
  45. package/dist/processors/observational-memory/tracing.d.ts +17 -0
  46. package/dist/processors/observational-memory/tracing.d.ts.map +1 -0
  47. package/dist/processors/observational-memory/types.d.ts +19 -1
  48. package/dist/processors/observational-memory/types.d.ts.map +1 -1
  49. package/dist/tools/om-tools.d.ts +96 -4
  50. package/dist/tools/om-tools.d.ts.map +1 -1
  51. package/package.json +5 -5
  52. package/dist/chunk-2QSOQQPM.js.map +0 -1
  53. package/dist/chunk-NS47X3OB.cjs.map +0 -1
@@ -9,8 +9,10 @@ import { join } from 'path';
9
9
  import { randomBytes, createHash, randomUUID } from 'crypto';
10
10
  import { estimateTokenCount } from 'tokenx';
11
11
  import { Agent } from '@mastra/core/agent';
12
+ import { getOrCreateSpan, EntityType, SpanType, createObservabilityContext } from '@mastra/core/observability';
12
13
  import { AsyncLocalStorage } from 'async_hooks';
13
14
  import imageSize from 'image-size';
15
+ import { inspect } from 'util';
14
16
 
15
17
  var OM_DEBUG_LOG = process.env.OM_DEBUG ? join(process.cwd(), "om-debug.log") : null;
16
18
  function omDebug(msg) {
@@ -958,7 +960,8 @@ var ObservationStrategy = class _ObservationStrategy {
958
960
  writer,
959
961
  abortSignal,
960
962
  reflectionHooks,
961
- requestContext
963
+ requestContext,
964
+ observabilityContext: this.opts.observabilityContext
962
965
  });
963
966
  }
964
967
  } catch (error) {
@@ -1099,6 +1102,27 @@ ${threadClose}`;
1099
1102
  const boundary = lastObservedAt ? _ObservationStrategy.createMessageBoundary(lastObservedAt) : "\n\n";
1100
1103
  return `${existingObservations}${boundary}${newThreadSection}`;
1101
1104
  }
1105
+ async indexObservationGroups(observations, threadId, resourceId, observedAt) {
1106
+ if (!resourceId || !this.deps.onIndexObservations) {
1107
+ return;
1108
+ }
1109
+ const groups = parseObservationGroups(observations);
1110
+ if (groups.length === 0) {
1111
+ return;
1112
+ }
1113
+ await Promise.all(
1114
+ groups.map(
1115
+ (group) => this.deps.onIndexObservations({
1116
+ text: group.content,
1117
+ groupId: group.id,
1118
+ range: group.range,
1119
+ threadId,
1120
+ resourceId,
1121
+ observedAt
1122
+ })
1123
+ )
1124
+ );
1125
+ }
1102
1126
  // ── Marker persistence ──────────────────────────────────────
1103
1127
  /**
1104
1128
  * Persist a marker to the last assistant message in storage.
@@ -1232,6 +1256,7 @@ var SyncObservationStrategy = class extends ObservationStrategy {
1232
1256
  const omMeta = thread ? getThreadOMMetadata(thread.metadata) : void 0;
1233
1257
  const result = await this.deps.observer.call(existingObservations, messages, this.opts.abortSignal, {
1234
1258
  requestContext: this.opts.requestContext,
1259
+ observabilityContext: this.opts.observabilityContext,
1235
1260
  priorCurrentTask: omMeta?.currentTask,
1236
1261
  priorSuggestedResponse: omMeta?.suggestedResponse,
1237
1262
  priorThreadTitle: omMeta?.threadTitle
@@ -1281,7 +1306,7 @@ var SyncObservationStrategy = class extends ObservationStrategy {
1281
1306
  };
1282
1307
  }
1283
1308
  async persist(processed) {
1284
- const { record, threadId, messages } = this.opts;
1309
+ const { record, threadId, resourceId, messages } = this.opts;
1285
1310
  const thread = await this.storage.getThreadById({ threadId });
1286
1311
  let threadUpdateMarker;
1287
1312
  if (thread) {
@@ -1318,6 +1343,7 @@ var SyncObservationStrategy = class extends ObservationStrategy {
1318
1343
  lastObservedAt: processed.lastObservedAt,
1319
1344
  observedMessageIds: processed.observedMessageIds
1320
1345
  });
1346
+ await this.indexObservationGroups(processed.observations, threadId, resourceId, processed.lastObservedAt);
1321
1347
  }
1322
1348
  async emitEndMarkers(cycleId, processed) {
1323
1349
  const actualTokensObserved = await this.tokenCounter.countMessagesAsync(this.opts.messages);
@@ -1383,7 +1409,8 @@ var AsyncBufferObservationStrategy = class extends ObservationStrategy {
1383
1409
  async observe(existingObservations, messages) {
1384
1410
  return this.deps.observer.call(existingObservations, messages, void 0, {
1385
1411
  skipContinuationHints: true,
1386
- requestContext: this.opts.requestContext
1412
+ requestContext: this.opts.requestContext,
1413
+ observabilityContext: this.opts.observabilityContext
1387
1414
  });
1388
1415
  }
1389
1416
  async process(output, _existingObservations) {
@@ -1422,7 +1449,7 @@ var AsyncBufferObservationStrategy = class extends ObservationStrategy {
1422
1449
  }
1423
1450
  async persist(processed) {
1424
1451
  if (!processed.observations) return;
1425
- const { record, messages } = this.opts;
1452
+ const { record, threadId, resourceId, messages } = this.opts;
1426
1453
  const messageTokens = await this.tokenCounter.countMessagesAsync(messages);
1427
1454
  await this.storage.updateBufferedObservations({
1428
1455
  id: record.id,
@@ -1439,6 +1466,7 @@ var AsyncBufferObservationStrategy = class extends ObservationStrategy {
1439
1466
  },
1440
1467
  lastBufferedAtTime: processed.lastObservedAt
1441
1468
  });
1469
+ await this.indexObservationGroups(processed.observations, threadId, resourceId, processed.lastObservedAt);
1442
1470
  }
1443
1471
  async emitEndMarkers(_cycleId, processed) {
1444
1472
  if (!processed.observations || !this.opts.writer) return;
@@ -1653,7 +1681,8 @@ var ResourceScopedObservationStrategy = class extends ObservationStrategy {
1653
1681
  batch.threadIds,
1654
1682
  this.opts.abortSignal,
1655
1683
  this.opts.requestContext,
1656
- this.priorMetadataByThread
1684
+ this.priorMetadataByThread,
1685
+ this.opts.observabilityContext
1657
1686
  );
1658
1687
  })
1659
1688
  );
@@ -1737,7 +1766,7 @@ var ResourceScopedObservationStrategy = class extends ObservationStrategy {
1737
1766
  };
1738
1767
  }
1739
1768
  async persist(processed) {
1740
- const { record } = this.opts;
1769
+ const { record, resourceId } = this.opts;
1741
1770
  const threadUpdateMarkers = [];
1742
1771
  if (processed.threadMetadataUpdates) {
1743
1772
  for (const update of processed.threadMetadataUpdates) {
@@ -1781,6 +1810,18 @@ var ResourceScopedObservationStrategy = class extends ObservationStrategy {
1781
1810
  lastObservedAt: processed.lastObservedAt,
1782
1811
  observedMessageIds: processed.observedMessageIds
1783
1812
  });
1813
+ if (resourceId) {
1814
+ await Promise.all(
1815
+ this.observationResults.map(
1816
+ ({ threadId, threadMessages, result }) => this.indexObservationGroups(
1817
+ result.observations,
1818
+ threadId,
1819
+ resourceId,
1820
+ this.getMaxMessageTimestamp(threadMessages)
1821
+ )
1822
+ )
1823
+ );
1824
+ }
1784
1825
  }
1785
1826
  async emitEndMarkers(cycleId, processed) {
1786
1827
  for (const obsResult of this.observationResults) {
@@ -1838,6 +1879,7 @@ ObservationStrategy.create = ((om, opts) => {
1838
1879
  reflector: om.reflector,
1839
1880
  observedMessageIds: om.observedMessageIds,
1840
1881
  obscureThreadIds: om.getObscureThreadIds(),
1882
+ onIndexObservations: om.onIndexObservations,
1841
1883
  emitDebugEvent: (e) => om.emitDebugEvent(e)
1842
1884
  };
1843
1885
  if (opts.cycleId) return new AsyncBufferObservationStrategy(deps, opts);
@@ -1906,7 +1948,8 @@ var ObservationStep = class {
1906
1948
  observationTokens: obsTokens,
1907
1949
  threadId,
1908
1950
  writer: this.turn.writer,
1909
- requestContext: this.turn.requestContext
1951
+ requestContext: this.turn.requestContext,
1952
+ observabilityContext: this.turn.observabilityContext
1910
1953
  });
1911
1954
  await this.turn.refreshRecord();
1912
1955
  if (this.turn.record.generationCount > preReflectGeneration) {
@@ -1938,8 +1981,19 @@ var ObservationStep = class {
1938
1981
  record: statusSnapshot.record,
1939
1982
  writer: this.turn.writer,
1940
1983
  requestContext: this.turn.requestContext,
1984
+ observabilityContext: this.turn.observabilityContext,
1941
1985
  beforeBuffer: async (candidates) => {
1986
+ if (candidates.length === 0) {
1987
+ return;
1988
+ }
1942
1989
  om.sealMessagesForBuffering(candidates);
1990
+ try {
1991
+ await this.turn.hooks?.onBufferChunkSealed?.();
1992
+ } catch (error) {
1993
+ omDebug(
1994
+ `[OM:buffer] onBufferChunkSealed hook failed: ${error instanceof Error ? error.message : String(error)}`
1995
+ );
1996
+ }
1943
1997
  if (this.turn.memory) {
1944
1998
  await this.turn.memory.persistMessages(candidates);
1945
1999
  }
@@ -2064,7 +2118,8 @@ var ObservationStep = class {
2064
2118
  threadId,
2065
2119
  writer: this.turn.writer,
2066
2120
  messageList,
2067
- requestContext: this.turn.requestContext
2121
+ requestContext: this.turn.requestContext,
2122
+ observabilityContext: this.turn.observabilityContext
2068
2123
  });
2069
2124
  return {
2070
2125
  succeeded: true,
@@ -2078,7 +2133,8 @@ var ObservationStep = class {
2078
2133
  resourceId,
2079
2134
  messages: messageList.get.all.db(),
2080
2135
  requestContext: this.turn.requestContext,
2081
- writer: this.turn.writer
2136
+ writer: this.turn.writer,
2137
+ observabilityContext: this.turn.observabilityContext
2082
2138
  });
2083
2139
  return { succeeded: obsResult.observed, record: obsResult.record };
2084
2140
  }
@@ -2086,12 +2142,6 @@ var ObservationStep = class {
2086
2142
 
2087
2143
  // src/processors/observational-memory/observation-turn/turn.ts
2088
2144
  var ObservationTurn = class {
2089
- constructor(om, threadId, resourceId, messageList) {
2090
- this.om = om;
2091
- this.threadId = threadId;
2092
- this.resourceId = resourceId;
2093
- this.messageList = messageList;
2094
- }
2095
2145
  _record;
2096
2146
  _context;
2097
2147
  _currentStep;
@@ -2105,6 +2155,22 @@ var ObservationTurn = class {
2105
2155
  writer;
2106
2156
  /** Optional request context for observation calls. */
2107
2157
  requestContext;
2158
+ /** Optional observability context for nested OM spans. */
2159
+ observabilityContext;
2160
+ /** Optional processor-provided hooks for turn/step lifecycle integration. */
2161
+ hooks;
2162
+ constructor(opts) {
2163
+ this.om = opts.om;
2164
+ this.threadId = opts.threadId;
2165
+ this.resourceId = opts.resourceId;
2166
+ this.messageList = opts.messageList;
2167
+ this.observabilityContext = opts.observabilityContext;
2168
+ this.hooks = opts.hooks;
2169
+ }
2170
+ om;
2171
+ threadId;
2172
+ resourceId;
2173
+ messageList;
2108
2174
  /** The current cached record. Refreshed after mutations (activate/observe/reflect). */
2109
2175
  get record() {
2110
2176
  if (!this._record) throw new Error("Turn not started \u2014 call start() first");
@@ -2167,7 +2233,7 @@ var ObservationTurn = class {
2167
2233
  return this._currentStep;
2168
2234
  }
2169
2235
  /**
2170
- * Finalize the turn: save any remaining messages, await in-flight buffering, return final state.
2236
+ * Finalize the turn: save any remaining messages and return the latest record state.
2171
2237
  */
2172
2238
  async end() {
2173
2239
  if (this._ended) throw new Error("Turn already ended");
@@ -2178,22 +2244,6 @@ var ObservationTurn = class {
2178
2244
  if (unsavedMessages.length > 0) {
2179
2245
  await this.om.persistMessages(unsavedMessages, this.threadId, this.resourceId);
2180
2246
  }
2181
- await this.om.waitForBuffering(this.threadId, this.resourceId);
2182
- const status = await this.om.getStatus({
2183
- threadId: this.threadId,
2184
- resourceId: this.resourceId,
2185
- messages: this.messageList.get.all.db()
2186
- });
2187
- if (status.shouldObserve) {
2188
- await this.om.observe({
2189
- threadId: this.threadId,
2190
- resourceId: this.resourceId,
2191
- messages: this.messageList.get.all.db(),
2192
- requestContext: this.requestContext,
2193
- writer: this.writer
2194
- });
2195
- }
2196
- await this.refreshRecord();
2197
2247
  return { record: this._record };
2198
2248
  }
2199
2249
  /**
@@ -3359,13 +3409,64 @@ function optimizeObservationsForContext(observations) {
3359
3409
  optimized = optimized.replace(/\n{3,}/g, "\n\n");
3360
3410
  return optimized.trim();
3361
3411
  }
3412
+ var PHASE_CONFIG = {
3413
+ observer: {
3414
+ name: "om.observer",
3415
+ entityName: "Observer"
3416
+ },
3417
+ "observer-multi-thread": {
3418
+ name: "om.observer.multi-thread",
3419
+ entityName: "MultiThreadObserver"
3420
+ },
3421
+ reflector: {
3422
+ name: "om.reflector",
3423
+ entityName: "Reflector"
3424
+ }
3425
+ };
3426
+ async function withOmTracingSpan({
3427
+ phase,
3428
+ model,
3429
+ inputTokens,
3430
+ requestContext,
3431
+ observabilityContext,
3432
+ metadata,
3433
+ callback
3434
+ }) {
3435
+ const config = PHASE_CONFIG[phase];
3436
+ const span = getOrCreateSpan({
3437
+ type: SpanType.GENERIC,
3438
+ name: config.name,
3439
+ entityType: EntityType.OUTPUT_STEP_PROCESSOR,
3440
+ entityName: config.entityName,
3441
+ tracingContext: observabilityContext?.tracingContext ?? observabilityContext?.tracing,
3442
+ attributes: {
3443
+ metadata: {
3444
+ omPhase: phase,
3445
+ omInputTokens: inputTokens,
3446
+ omSelectedModel: typeof model === "string" ? model : "(dynamic-model)",
3447
+ ...metadata
3448
+ }
3449
+ },
3450
+ requestContext
3451
+ });
3452
+ const childObservabilityContext = createObservabilityContext({ currentSpan: span });
3453
+ if (!span) {
3454
+ return callback(childObservabilityContext);
3455
+ }
3456
+ return span.executeInContext(() => callback(childObservabilityContext));
3457
+ }
3458
+
3459
+ // src/processors/observational-memory/observer-runner.ts
3362
3460
  var ObserverRunner = class {
3363
3461
  observationConfig;
3364
3462
  observedMessageIds;
3365
- observerAgent;
3463
+ resolveModel;
3464
+ tokenCounter;
3366
3465
  constructor(opts) {
3367
3466
  this.observationConfig = opts.observationConfig;
3368
3467
  this.observedMessageIds = opts.observedMessageIds;
3468
+ this.resolveModel = opts.resolveModel;
3469
+ this.tokenCounter = opts.tokenCounter;
3369
3470
  }
3370
3471
  createAgent(model, isMultiThread = false) {
3371
3472
  return new Agent({
@@ -3379,10 +3480,6 @@ var ObserverRunner = class {
3379
3480
  model
3380
3481
  });
3381
3482
  }
3382
- getAgent(model) {
3383
- this.observerAgent ??= this.createAgent(model);
3384
- return this.observerAgent;
3385
- }
3386
3483
  async withAbortCheck(fn, abortSignal) {
3387
3484
  if (abortSignal?.aborted) {
3388
3485
  throw new Error("The operation was aborted.");
@@ -3397,7 +3494,9 @@ var ObserverRunner = class {
3397
3494
  * Call the Observer agent for a single thread.
3398
3495
  */
3399
3496
  async call(existingObservations, messagesToObserve, abortSignal, options) {
3400
- const agent = options?.model ? this.createAgent(options.model) : this.getAgent(this.observationConfig.model);
3497
+ const inputTokens = this.tokenCounter.countMessages(messagesToObserve);
3498
+ const resolvedModel = options?.model ? { model: options.model } : this.resolveModel(inputTokens);
3499
+ const agent = this.createAgent(resolvedModel.model);
3401
3500
  const observerMessages = [
3402
3501
  {
3403
3502
  role: "user",
@@ -3409,15 +3508,32 @@ var ObserverRunner = class {
3409
3508
  buildObserverHistoryMessage(messagesToObserve)
3410
3509
  ];
3411
3510
  const doGenerate = async () => {
3412
- return this.withAbortCheck(async () => {
3413
- const streamResult = await agent.stream(observerMessages, {
3414
- modelSettings: { ...this.observationConfig.modelSettings },
3415
- providerOptions: this.observationConfig.providerOptions,
3416
- ...abortSignal ? { abortSignal } : {},
3417
- ...options?.requestContext ? { requestContext: options.requestContext } : {}
3418
- });
3419
- return streamResult.getFullOutput();
3420
- }, abortSignal);
3511
+ return withOmTracingSpan({
3512
+ phase: "observer",
3513
+ model: resolvedModel.model,
3514
+ inputTokens,
3515
+ requestContext: options?.requestContext,
3516
+ observabilityContext: options?.observabilityContext,
3517
+ metadata: {
3518
+ omPreviousObserverTokens: this.observationConfig.previousObserverTokens,
3519
+ omThreadTitleEnabled: this.observationConfig.threadTitle,
3520
+ omSkipContinuationHints: options?.skipContinuationHints ?? false,
3521
+ omWasTruncated: options?.wasTruncated ?? false,
3522
+ ...resolvedModel.selectedThreshold !== void 0 ? { omSelectedThreshold: resolvedModel.selectedThreshold } : {},
3523
+ ...resolvedModel.routingStrategy ? { omRoutingStrategy: resolvedModel.routingStrategy } : {},
3524
+ ...resolvedModel.routingThresholds ? { omRoutingThresholds: resolvedModel.routingThresholds } : {}
3525
+ },
3526
+ callback: (childObservabilityContext) => this.withAbortCheck(async () => {
3527
+ const streamResult = await agent.stream(observerMessages, {
3528
+ modelSettings: { ...this.observationConfig.modelSettings },
3529
+ providerOptions: this.observationConfig.providerOptions,
3530
+ ...abortSignal ? { abortSignal } : {},
3531
+ ...options?.requestContext ? { requestContext: options.requestContext } : {},
3532
+ ...childObservabilityContext
3533
+ });
3534
+ return streamResult.getFullOutput();
3535
+ }, abortSignal)
3536
+ });
3421
3537
  };
3422
3538
  let result = await doGenerate();
3423
3539
  let parsed = parseObserverOutput(result.text);
@@ -3442,8 +3558,13 @@ var ObserverRunner = class {
3442
3558
  /**
3443
3559
  * Call the Observer agent for multiple threads in a single batched request.
3444
3560
  */
3445
- async callMultiThread(existingObservations, messagesByThread, threadOrder, abortSignal, requestContext, priorMetadataByThread, model) {
3446
- const agent = this.createAgent(model ?? this.observationConfig.model, true);
3561
+ async callMultiThread(existingObservations, messagesByThread, threadOrder, abortSignal, requestContext, priorMetadataByThread, observabilityContext, model) {
3562
+ const inputTokens = Array.from(messagesByThread.values()).reduce(
3563
+ (total, messages) => total + this.tokenCounter.countMessages(messages),
3564
+ 0
3565
+ );
3566
+ const resolvedModel = model ? { model } : this.resolveModel(inputTokens);
3567
+ const agent = this.createAgent(resolvedModel.model, true);
3447
3568
  const observerMessages = [
3448
3569
  {
3449
3570
  role: "user",
@@ -3463,15 +3584,31 @@ var ObserverRunner = class {
3463
3584
  }
3464
3585
  }
3465
3586
  const doGenerate = async () => {
3466
- return this.withAbortCheck(async () => {
3467
- const streamResult = await agent.stream(observerMessages, {
3468
- modelSettings: { ...this.observationConfig.modelSettings },
3469
- providerOptions: this.observationConfig.providerOptions,
3470
- ...abortSignal ? { abortSignal } : {},
3471
- ...requestContext ? { requestContext } : {}
3472
- });
3473
- return streamResult.getFullOutput();
3474
- }, abortSignal);
3587
+ return withOmTracingSpan({
3588
+ phase: "observer-multi-thread",
3589
+ model: resolvedModel.model,
3590
+ inputTokens,
3591
+ requestContext,
3592
+ observabilityContext,
3593
+ metadata: {
3594
+ omThreadCount: threadOrder.length,
3595
+ omPreviousObserverTokens: this.observationConfig.previousObserverTokens,
3596
+ omThreadTitleEnabled: this.observationConfig.threadTitle,
3597
+ ...resolvedModel.selectedThreshold !== void 0 ? { omSelectedThreshold: resolvedModel.selectedThreshold } : {},
3598
+ ...resolvedModel.routingStrategy ? { omRoutingStrategy: resolvedModel.routingStrategy } : {},
3599
+ ...resolvedModel.routingThresholds ? { omRoutingThresholds: resolvedModel.routingThresholds } : {}
3600
+ },
3601
+ callback: (childObservabilityContext) => this.withAbortCheck(async () => {
3602
+ const streamResult = await agent.stream(observerMessages, {
3603
+ modelSettings: { ...this.observationConfig.modelSettings },
3604
+ providerOptions: this.observationConfig.providerOptions,
3605
+ ...abortSignal ? { abortSignal } : {},
3606
+ ...requestContext ? { requestContext } : {},
3607
+ ...childObservabilityContext
3608
+ });
3609
+ return streamResult.getFullOutput();
3610
+ }, abortSignal)
3611
+ });
3475
3612
  };
3476
3613
  let result = await doGenerate();
3477
3614
  let parsed = parseMultiThreadObserverOutput(result.text);
@@ -3778,6 +3915,7 @@ var ReflectorRunner = class {
3778
3915
  reflectionConfig;
3779
3916
  observationConfig;
3780
3917
  tokenCounter;
3918
+ resolveModel;
3781
3919
  storage;
3782
3920
  scope;
3783
3921
  buffering;
@@ -3789,6 +3927,7 @@ var ReflectorRunner = class {
3789
3927
  this.reflectionConfig = opts.reflectionConfig;
3790
3928
  this.observationConfig = opts.observationConfig;
3791
3929
  this.tokenCounter = opts.tokenCounter;
3930
+ this.resolveModel = opts.resolveModel;
3792
3931
  this.storage = opts.storage;
3793
3932
  this.scope = opts.scope;
3794
3933
  this.buffering = opts.buffering;
@@ -3815,9 +3954,10 @@ var ReflectorRunner = class {
3815
3954
  /**
3816
3955
  * Call the Reflector agent with escalating compression levels.
3817
3956
  */
3818
- async call(observations, manualPrompt, streamContext, observationTokensThreshold, abortSignal, skipContinuationHints, compressionStartLevel, requestContext, model) {
3819
- const agent = this.createAgent(model ?? this.reflectionConfig.model);
3957
+ async call(observations, manualPrompt, streamContext, observationTokensThreshold, abortSignal, skipContinuationHints, compressionStartLevel, requestContext, observabilityContext, model) {
3820
3958
  const originalTokens = this.tokenCounter.countObservations(observations);
3959
+ const resolvedModel = model ? { model } : this.resolveModel(originalTokens);
3960
+ const agent = this.createAgent(resolvedModel.model);
3821
3961
  const targetThreshold = observationTokensThreshold ?? getMaxThreshold(this.reflectionConfig.observationTokens);
3822
3962
  let totalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
3823
3963
  const startLevel = compressionStartLevel ?? 0;
@@ -3834,37 +3974,54 @@ var ReflectorRunner = class {
3834
3974
  `[OM:callReflector] ${isRetry ? `retry #${attemptNumber - 1}` : "first attempt"}: level=${currentLevel}, originalTokens=${originalTokens}, targetThreshold=${targetThreshold}, promptLen=${prompt.length}, skipContinuationHints=${skipContinuationHints}`
3835
3975
  );
3836
3976
  let chunkCount = 0;
3837
- const result = await withAbortCheck(async () => {
3838
- const streamResult = await agent.stream(prompt, {
3839
- modelSettings: {
3840
- ...this.reflectionConfig.modelSettings
3841
- },
3842
- providerOptions: this.reflectionConfig.providerOptions,
3843
- ...abortSignal ? { abortSignal } : {},
3844
- ...requestContext ? { requestContext } : {},
3845
- ...attemptNumber === 1 ? {
3846
- onChunk(chunk) {
3847
- chunkCount++;
3848
- if (chunkCount === 1 || chunkCount % 50 === 0) {
3849
- const preview = chunk.type === "text-delta" ? ` text="${chunk.textDelta?.slice(0, 80)}..."` : chunk.type === "tool-call" ? ` tool=${chunk.toolName}` : "";
3850
- omDebug(`[OM:callReflector] chunk#${chunkCount}: type=${chunk.type}${preview}`);
3851
- }
3852
- },
3853
- onFinish(event) {
3854
- omDebug(
3855
- `[OM:callReflector] onFinish: chunks=${chunkCount}, finishReason=${event.finishReason}, inputTokens=${event.usage?.inputTokens}, outputTokens=${event.usage?.outputTokens}, textLen=${event.text?.length}`
3856
- );
3857
- },
3858
- onAbort(event) {
3859
- omDebug(`[OM:callReflector] onAbort: chunks=${chunkCount}, reason=${event?.reason ?? "unknown"}`);
3977
+ const result = await withOmTracingSpan({
3978
+ phase: "reflector",
3979
+ model: resolvedModel.model,
3980
+ inputTokens: originalTokens,
3981
+ requestContext,
3982
+ observabilityContext,
3983
+ metadata: {
3984
+ omCompressionLevel: currentLevel,
3985
+ omCompressionAttempt: attemptNumber,
3986
+ omTargetThreshold: targetThreshold,
3987
+ omSkipContinuationHints: skipContinuationHints ?? false,
3988
+ ...resolvedModel.selectedThreshold !== void 0 ? { omSelectedThreshold: resolvedModel.selectedThreshold } : {},
3989
+ ...resolvedModel.routingStrategy ? { omRoutingStrategy: resolvedModel.routingStrategy } : {},
3990
+ ...resolvedModel.routingThresholds ? { omRoutingThresholds: resolvedModel.routingThresholds } : {}
3991
+ },
3992
+ callback: (childObservabilityContext) => withAbortCheck(async () => {
3993
+ const streamResult = await agent.stream(prompt, {
3994
+ modelSettings: {
3995
+ ...this.reflectionConfig.modelSettings
3860
3996
  },
3861
- onError({ error }) {
3862
- omError(`[OM:callReflector] onError after ${chunkCount} chunks`, error);
3863
- }
3864
- } : {}
3865
- });
3866
- return streamResult.getFullOutput();
3867
- }, abortSignal);
3997
+ providerOptions: this.reflectionConfig.providerOptions,
3998
+ ...abortSignal ? { abortSignal } : {},
3999
+ ...requestContext ? { requestContext } : {},
4000
+ ...childObservabilityContext,
4001
+ ...attemptNumber === 1 ? {
4002
+ onChunk(chunk) {
4003
+ chunkCount++;
4004
+ if (chunkCount === 1 || chunkCount % 50 === 0) {
4005
+ const preview = chunk.type === "text-delta" ? ` text="${chunk.textDelta?.slice(0, 80)}..."` : chunk.type === "tool-call" ? ` tool=${chunk.toolName}` : "";
4006
+ omDebug(`[OM:callReflector] chunk#${chunkCount}: type=${chunk.type}${preview}`);
4007
+ }
4008
+ },
4009
+ onFinish(event) {
4010
+ omDebug(
4011
+ `[OM:callReflector] onFinish: chunks=${chunkCount}, finishReason=${event.finishReason}, inputTokens=${event.usage?.inputTokens}, outputTokens=${event.usage?.outputTokens}, textLen=${event.text?.length}`
4012
+ );
4013
+ },
4014
+ onAbort(event) {
4015
+ omDebug(`[OM:callReflector] onAbort: chunks=${chunkCount}, reason=${event?.reason ?? "unknown"}`);
4016
+ },
4017
+ onError({ error }) {
4018
+ omError(`[OM:callReflector] onError after ${chunkCount} chunks`, error);
4019
+ }
4020
+ } : {}
4021
+ });
4022
+ return streamResult.getFullOutput();
4023
+ }, abortSignal)
4024
+ });
3868
4025
  omDebug(
3869
4026
  `[OM:callReflector] attempt #${attemptNumber} returned: textLen=${result.text?.length}, textPreview="${result.text?.slice(0, 120)}...", inputTokens=${result.usage?.inputTokens ?? result.totalUsage?.inputTokens}, outputTokens=${result.usage?.outputTokens ?? result.totalUsage?.outputTokens}`
3870
4027
  );
@@ -3931,7 +4088,7 @@ var ReflectorRunner = class {
3931
4088
  /**
3932
4089
  * Start an async buffered reflection in the background.
3933
4090
  */
3934
- startAsyncBufferedReflection(record, observationTokens, lockKey, writer, requestContext) {
4091
+ startAsyncBufferedReflection(record, observationTokens, lockKey, writer, requestContext, observabilityContext) {
3935
4092
  const bufferKey = this.buffering.getReflectionBufferKey(lockKey);
3936
4093
  if (this.buffering.isAsyncBufferingInProgress(bufferKey)) {
3937
4094
  return;
@@ -3941,7 +4098,7 @@ var ReflectorRunner = class {
3941
4098
  this.storage.setBufferingReflectionFlag(record.id, true).catch((err) => {
3942
4099
  omError("[OM] Failed to set buffering reflection flag", err);
3943
4100
  });
3944
- const asyncOp = this.doAsyncBufferedReflection(record, bufferKey, writer, requestContext).catch(async (error) => {
4101
+ const asyncOp = this.doAsyncBufferedReflection(record, bufferKey, writer, requestContext, observabilityContext).catch(async (error) => {
3945
4102
  if (writer) {
3946
4103
  const failedMarker = createBufferingFailedMarker({
3947
4104
  cycleId: `reflect-buf-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
@@ -3971,7 +4128,7 @@ var ReflectorRunner = class {
3971
4128
  * Perform async buffered reflection — reflects observations and stores to bufferedReflection.
3972
4129
  * Does NOT create a new generation or update activeObservations.
3973
4130
  */
3974
- async doAsyncBufferedReflection(record, _bufferKey, writer, requestContext) {
4131
+ async doAsyncBufferedReflection(record, _bufferKey, writer, requestContext, observabilityContext) {
3975
4132
  const freshRecord = await this.storage.getObservationalMemory(record.threadId, record.resourceId);
3976
4133
  const currentRecord = freshRecord ?? record;
3977
4134
  const observationTokens = currentRecord.observationTokenCount ?? 0;
@@ -4018,7 +4175,8 @@ var ReflectorRunner = class {
4018
4175
  void 0,
4019
4176
  true,
4020
4177
  compressionStartLevel,
4021
- requestContext
4178
+ requestContext,
4179
+ observabilityContext
4022
4180
  );
4023
4181
  const reflectionTokenCount = this.tokenCounter.countObservations(reflectResult.observations);
4024
4182
  omDebug(
@@ -4134,7 +4292,16 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4134
4292
  * @internal Used by observation strategies. Do not call directly.
4135
4293
  */
4136
4294
  async maybeReflect(opts) {
4137
- const { record, observationTokens, writer, abortSignal, messageList, reflectionHooks, requestContext } = opts;
4295
+ const {
4296
+ record,
4297
+ observationTokens,
4298
+ writer,
4299
+ abortSignal,
4300
+ messageList,
4301
+ reflectionHooks,
4302
+ requestContext,
4303
+ observabilityContext
4304
+ } = opts;
4138
4305
  const lockKey = this.buffering.getLockKey(record.threadId, record.resourceId);
4139
4306
  const reflectThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
4140
4307
  if (this.buffering.isAsyncReflectionEnabled() && observationTokens < reflectThreshold) {
@@ -4154,7 +4321,14 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4154
4321
  return observationTokens >= activationPoint;
4155
4322
  })();
4156
4323
  if (shouldTrigger) {
4157
- this.startAsyncBufferedReflection(record, observationTokens, lockKey, writer, requestContext);
4324
+ this.startAsyncBufferedReflection(
4325
+ record,
4326
+ observationTokens,
4327
+ lockKey,
4328
+ writer,
4329
+ requestContext,
4330
+ observabilityContext
4331
+ );
4158
4332
  }
4159
4333
  }
4160
4334
  if (observationTokens < reflectThreshold) {
@@ -4181,7 +4355,14 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4181
4355
  omDebug(
4182
4356
  `[OM:reflect] async activation failed, no blockAfter or below it (obsTokens=${observationTokens}, blockAfter=${this.reflectionConfig.blockAfter}) \u2014 starting background reflection`
4183
4357
  );
4184
- this.startAsyncBufferedReflection(record, observationTokens, lockKey, writer, requestContext);
4358
+ this.startAsyncBufferedReflection(
4359
+ record,
4360
+ observationTokens,
4361
+ lockKey,
4362
+ writer,
4363
+ requestContext,
4364
+ observabilityContext
4365
+ );
4185
4366
  return;
4186
4367
  }
4187
4368
  }
@@ -4229,7 +4410,8 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4229
4410
  abortSignal,
4230
4411
  void 0,
4231
4412
  compressionStartLevel,
4232
- requestContext
4413
+ requestContext,
4414
+ observabilityContext
4233
4415
  );
4234
4416
  const reflectionTokenCount = this.tokenCounter.countObservations(reflectResult.observations);
4235
4417
  await this.storage.createReflectionGeneration({
@@ -5517,11 +5699,12 @@ var ObservationalMemory = class _ObservationalMemory {
5517
5699
  storage;
5518
5700
  tokenCounter;
5519
5701
  scope;
5520
- /** Whether retrieval-mode observation groups are enabled (thread scope only). */
5702
+ /** Whether retrieval-mode observation groups are enabled. */
5521
5703
  retrieval;
5522
5704
  observationConfig;
5523
5705
  reflectionConfig;
5524
5706
  onDebugEvent;
5707
+ onIndexObservations;
5525
5708
  /** Observer agent runner — handles LLM calls for extracting observations. */
5526
5709
  observer;
5527
5710
  /** Reflector agent runner — handles LLM calls for compressing observations. */
@@ -5594,7 +5777,8 @@ var ObservationalMemory = class _ObservationalMemory {
5594
5777
  this.shouldObscureThreadIds = config.obscureThreadIds || false;
5595
5778
  this.storage = config.storage;
5596
5779
  this.scope = config.scope ?? "thread";
5597
- this.retrieval = this.scope === "thread" && (config.retrieval ?? false);
5780
+ this.retrieval = Boolean(config.retrieval);
5781
+ this.onIndexObservations = config.onIndexObservations;
5598
5782
  const resolveModel = (m) => m === "default" ? OBSERVATIONAL_MEMORY_DEFAULTS.observation.model : m;
5599
5783
  const observationModel = resolveModel(config.model) ?? resolveModel(config.observation?.model) ?? resolveModel(config.reflection?.model);
5600
5784
  const reflectionModel = resolveModel(config.model) ?? resolveModel(config.reflection?.model) ?? resolveModel(config.observation?.model);
@@ -5688,7 +5872,9 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
5688
5872
  this.messageHistory = new MessageHistory({ storage: this.storage });
5689
5873
  this.observer = new ObserverRunner({
5690
5874
  observationConfig: this.observationConfig,
5691
- observedMessageIds: this.observedMessageIds
5875
+ observedMessageIds: this.observedMessageIds,
5876
+ resolveModel: (inputTokens) => this.resolveObservationModel(inputTokens),
5877
+ tokenCounter: this.tokenCounter
5692
5878
  });
5693
5879
  this.buffering = new BufferingCoordinator({
5694
5880
  observationConfig: this.observationConfig,
@@ -5705,7 +5891,8 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
5705
5891
  emitDebugEvent: (e) => this.emitDebugEvent(e),
5706
5892
  persistMarkerToStorage: (m, t, r) => this.persistMarkerToStorage(m, t, r),
5707
5893
  persistMarkerToMessage: (m, ml, t, r) => this.persistMarkerToMessage(m, ml, t, r),
5708
- getCompressionStartLevel: (rc) => this.getCompressionStartLevel(rc)
5894
+ getCompressionStartLevel: (rc) => this.getCompressionStartLevel(rc),
5895
+ resolveModel: (inputTokens) => this.resolveReflectionModel(inputTokens)
5709
5896
  });
5710
5897
  this.validateBufferConfig();
5711
5898
  omDebug(
@@ -5767,6 +5954,54 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
5767
5954
  }
5768
5955
  return model.provider ? `${model.provider}/${model.modelId}` : model.modelId;
5769
5956
  }
5957
+ resolveObservationModel(inputTokens) {
5958
+ return this.resolveTieredModel(this.observationConfig.model, inputTokens);
5959
+ }
5960
+ resolveReflectionModel(inputTokens) {
5961
+ return this.resolveTieredModel(this.reflectionConfig.model, inputTokens);
5962
+ }
5963
+ resolveTieredModel(model, inputTokens) {
5964
+ if (!(model instanceof ModelByInputTokens)) {
5965
+ return {
5966
+ model
5967
+ };
5968
+ }
5969
+ const thresholds = model.getThresholds();
5970
+ const selectedThreshold = thresholds.find((upTo) => inputTokens <= upTo) ?? thresholds.at(-1);
5971
+ return {
5972
+ model: model.resolve(inputTokens),
5973
+ selectedThreshold,
5974
+ routingStrategy: "model-by-input-tokens",
5975
+ routingThresholds: thresholds.join(",")
5976
+ };
5977
+ }
5978
+ async resolveModelRouting(modelConfig, requestContext) {
5979
+ try {
5980
+ if (modelConfig instanceof ModelByInputTokens) {
5981
+ const routing = await Promise.all(
5982
+ modelConfig.getThresholds().map(async (upTo) => {
5983
+ const resolvedModel = modelConfig.resolve(upTo);
5984
+ const resolved2 = await this.resolveModelContext(resolvedModel, requestContext);
5985
+ return {
5986
+ upTo,
5987
+ model: resolved2?.modelId ? this.formatModelName(resolved2) : "(unknown)"
5988
+ };
5989
+ })
5990
+ );
5991
+ return {
5992
+ model: routing[0]?.model ?? "(unknown)",
5993
+ routing
5994
+ };
5995
+ }
5996
+ const resolved = await this.resolveModelContext(modelConfig, requestContext);
5997
+ return {
5998
+ model: resolved?.modelId ? this.formatModelName(resolved) : "(unknown)"
5999
+ };
6000
+ } catch (error) {
6001
+ omError("[OM] Failed to resolve model config", error);
6002
+ return { model: "(unknown)" };
6003
+ }
6004
+ }
5770
6005
  async resolveModelContext(modelConfig, requestContext, inputTokens) {
5771
6006
  const modelToResolve = this.getModelToResolve(modelConfig, inputTokens);
5772
6007
  if (!modelToResolve) {
@@ -5799,29 +6034,22 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
5799
6034
  * This is async because it needs to resolve the model configs.
5800
6035
  */
5801
6036
  async getResolvedConfig(requestContext) {
5802
- const safeResolveModel = async (modelConfig) => {
5803
- try {
5804
- const resolved = await this.resolveModelContext(modelConfig, requestContext);
5805
- return resolved?.modelId ? this.formatModelName(resolved) : "(unknown)";
5806
- } catch (error) {
5807
- omError("[OM] Failed to resolve model config", error);
5808
- return "(unknown)";
5809
- }
5810
- };
5811
- const [observationModelName, reflectionModelName] = await Promise.all([
5812
- safeResolveModel(this.observationConfig.model),
5813
- safeResolveModel(this.reflectionConfig.model)
6037
+ const [observationResolved, reflectionResolved] = await Promise.all([
6038
+ this.resolveModelRouting(this.observationConfig.model, requestContext),
6039
+ this.resolveModelRouting(this.reflectionConfig.model, requestContext)
5814
6040
  ]);
5815
6041
  return {
5816
6042
  scope: this.scope,
5817
6043
  observation: {
5818
6044
  messageTokens: this.observationConfig.messageTokens,
5819
- model: observationModelName,
5820
- previousObserverTokens: this.observationConfig.previousObserverTokens
6045
+ model: observationResolved.model,
6046
+ previousObserverTokens: this.observationConfig.previousObserverTokens,
6047
+ routing: observationResolved.routing
5821
6048
  },
5822
6049
  reflection: {
5823
6050
  observationTokens: this.reflectionConfig.observationTokens,
5824
- model: reflectionModelName
6051
+ model: reflectionResolved.model,
6052
+ routing: reflectionResolved.routing
5825
6053
  }
5826
6054
  };
5827
6055
  }
@@ -6628,7 +6856,7 @@ ${grouped}` : grouped;
6628
6856
  * @param lockKey - Lock key for this scope
6629
6857
  * @param writer - Optional stream writer for emitting buffering markers
6630
6858
  */
6631
- async startAsyncBufferedObservation(record, threadId, unobservedMessages, lockKey, writer, contextWindowTokens, requestContext) {
6859
+ async startAsyncBufferedObservation(record, threadId, unobservedMessages, lockKey, writer, contextWindowTokens, requestContext, observabilityContext) {
6632
6860
  const bufferKey = this.buffering.getObservationBufferKey(lockKey);
6633
6861
  const currentTokens = contextWindowTokens ?? await this.tokenCounter.countMessagesAsync(unobservedMessages) + (record.pendingMessageTokens ?? 0);
6634
6862
  BufferingCoordinator.lastBufferedBoundary.set(bufferKey, currentTokens);
@@ -6642,7 +6870,8 @@ ${grouped}` : grouped;
6642
6870
  unobservedMessages,
6643
6871
  bufferKey,
6644
6872
  writer,
6645
- requestContext
6873
+ requestContext,
6874
+ observabilityContext
6646
6875
  ).finally(() => {
6647
6876
  BufferingCoordinator.asyncBufferingOps.delete(bufferKey);
6648
6877
  unregisterOp(record.id, "bufferingObservation");
@@ -6656,7 +6885,7 @@ ${grouped}` : grouped;
6656
6885
  * Internal method that waits for existing buffering operation and then runs new buffering.
6657
6886
  * This implements the mutex-wait behavior.
6658
6887
  */
6659
- async runAsyncBufferedObservation(record, threadId, unobservedMessages, bufferKey, writer, requestContext) {
6888
+ async runAsyncBufferedObservation(record, threadId, unobservedMessages, bufferKey, writer, requestContext, observabilityContext) {
6660
6889
  const existingOp = BufferingCoordinator.asyncBufferingOps.get(bufferKey);
6661
6890
  if (existingOp) {
6662
6891
  try {
@@ -6728,7 +6957,8 @@ ${grouped}` : grouped;
6728
6957
  cycleId,
6729
6958
  startedAt,
6730
6959
  writer,
6731
- requestContext
6960
+ requestContext,
6961
+ observabilityContext
6732
6962
  }).run();
6733
6963
  const maxTs = this.getMaxMessageTimestamp(messagesToBuffer);
6734
6964
  const cursor = new Date(maxTs.getTime() + 1);
@@ -7275,7 +7505,7 @@ ${grouped}` : grouped;
7275
7505
  */
7276
7506
  /** @internal Used by ObservationStep. */
7277
7507
  async buffer(opts) {
7278
- const { threadId, resourceId, requestContext } = opts;
7508
+ const { threadId, resourceId, requestContext, observabilityContext } = opts;
7279
7509
  let record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
7280
7510
  if (!this.buffering.isAsyncObservationEnabled()) {
7281
7511
  return { buffered: false, record };
@@ -7371,7 +7601,8 @@ ${grouped}` : grouped;
7371
7601
  cycleId,
7372
7602
  startedAt,
7373
7603
  writer,
7374
- requestContext
7604
+ requestContext,
7605
+ observabilityContext
7375
7606
  }).run();
7376
7607
  await this.storage.setBufferingObservationFlag(record.id, false, newTokens).catch(() => {
7377
7608
  });
@@ -7575,7 +7806,8 @@ ${grouped}` : grouped;
7575
7806
  messages: unobservedMessages,
7576
7807
  reflectionHooks,
7577
7808
  requestContext,
7578
- writer: opts.writer
7809
+ writer: opts.writer,
7810
+ observabilityContext: opts.observabilityContext
7579
7811
  }).run();
7580
7812
  observed = true;
7581
7813
  } finally {
@@ -7597,7 +7829,7 @@ ${grouped}` : grouped;
7597
7829
  * );
7598
7830
  * ```
7599
7831
  */
7600
- async reflect(threadId, resourceId, prompt, requestContext) {
7832
+ async reflect(threadId, resourceId, prompt, requestContext, observabilityContext) {
7601
7833
  const record = await this.getOrCreateRecord(threadId, resourceId);
7602
7834
  if (!record.activeObservations) {
7603
7835
  return { reflected: false, record };
@@ -7614,7 +7846,9 @@ ${grouped}` : grouped;
7614
7846
  void 0,
7615
7847
  void 0,
7616
7848
  void 0,
7617
- requestContext
7849
+ requestContext,
7850
+ observabilityContext,
7851
+ void 0
7618
7852
  );
7619
7853
  const reflectionTokenCount = this.tokenCounter.countObservations(reflectResult.observations);
7620
7854
  await this.storage.createReflectionGeneration({
@@ -7716,7 +7950,14 @@ ${grouped}` : grouped;
7716
7950
  * ```
7717
7951
  */
7718
7952
  beginTurn(opts) {
7719
- return new ObservationTurn(this, opts.threadId, opts.resourceId, opts.messageList);
7953
+ return new ObservationTurn({
7954
+ om: this,
7955
+ threadId: opts.threadId,
7956
+ resourceId: opts.resourceId,
7957
+ messageList: opts.messageList,
7958
+ observabilityContext: opts.observabilityContext,
7959
+ hooks: opts.hooks
7960
+ });
7720
7961
  }
7721
7962
  };
7722
7963
  var OM_REPRO_CAPTURE_DIR = process.env.OM_REPRO_CAPTURE_DIR ?? ".mastra-om-repro";
@@ -7732,6 +7973,7 @@ function safeCaptureJson(value) {
7732
7973
  JSON.stringify(value, (_key, current) => {
7733
7974
  if (typeof current === "bigint") return current.toString();
7734
7975
  if (typeof current === "function") return "[function]";
7976
+ if (typeof current === "symbol") return current.toString();
7735
7977
  if (current instanceof Error) return { name: current.name, message: current.message, stack: current.stack };
7736
7978
  if (current instanceof Set) return { __type: "Set", values: Array.from(current.values()) };
7737
7979
  if (current instanceof Map) return { __type: "Map", entries: Array.from(current.entries()) };
@@ -7739,6 +7981,87 @@ function safeCaptureJson(value) {
7739
7981
  })
7740
7982
  );
7741
7983
  }
7984
+ function safeCaptureJsonOrError(value) {
7985
+ try {
7986
+ return { ok: true, value: safeCaptureJson(value) };
7987
+ } catch (error) {
7988
+ return {
7989
+ ok: false,
7990
+ error: safeCaptureJson({
7991
+ message: error instanceof Error ? error.message : String(error),
7992
+ stack: error instanceof Error ? error.stack : void 0,
7993
+ inspected: inspect(value, { depth: 3, maxArrayLength: 20, breakLength: 120 })
7994
+ })
7995
+ };
7996
+ }
7997
+ }
7998
+ function formatCaptureDate(value) {
7999
+ if (!value) return void 0;
8000
+ if (value instanceof Date) return value.toISOString();
8001
+ try {
8002
+ return new Date(value).toISOString();
8003
+ } catch {
8004
+ return void 0;
8005
+ }
8006
+ }
8007
+ function summarizeOmTurn(value) {
8008
+ if (!value || typeof value !== "object") {
8009
+ return value;
8010
+ }
8011
+ const turn = value;
8012
+ return {
8013
+ __type: "ObservationTurn",
8014
+ threadId: turn.threadId,
8015
+ resourceId: turn.resourceId,
8016
+ started: turn._started,
8017
+ ended: turn._ended,
8018
+ generationCountAtStart: turn._generationCountAtStart,
8019
+ record: turn._record ? {
8020
+ id: turn._record.id,
8021
+ scope: turn._record.scope,
8022
+ threadId: turn._record.threadId,
8023
+ resourceId: turn._record.resourceId,
8024
+ createdAt: formatCaptureDate(turn._record.createdAt),
8025
+ updatedAt: formatCaptureDate(turn._record.updatedAt),
8026
+ lastObservedAt: formatCaptureDate(turn._record.lastObservedAt),
8027
+ generationCount: turn._record.generationCount,
8028
+ observationTokenCount: turn._record.observationTokenCount,
8029
+ pendingMessageTokens: turn._record.pendingMessageTokens,
8030
+ isBufferingObservation: turn._record.isBufferingObservation,
8031
+ isBufferingReflection: turn._record.isBufferingReflection
8032
+ } : void 0,
8033
+ context: turn._context ? {
8034
+ messageCount: Array.isArray(turn._context.messages) ? turn._context.messages.length : void 0,
8035
+ hasSystemMessage: Array.isArray(turn._context.systemMessage) ? turn._context.systemMessage.length > 0 : Boolean(turn._context.systemMessage),
8036
+ continuationId: turn._context.continuation?.id,
8037
+ hasOtherThreadsContext: Boolean(turn._context.otherThreadsContext),
8038
+ recordId: turn._context.record?.id
8039
+ } : void 0,
8040
+ currentStep: turn._currentStep ? {
8041
+ stepNumber: turn._currentStep.stepNumber,
8042
+ prepared: turn._currentStep._prepared,
8043
+ context: turn._currentStep._context ? {
8044
+ activated: turn._currentStep._context.activated,
8045
+ observed: turn._currentStep._context.observed,
8046
+ buffered: turn._currentStep._context.buffered,
8047
+ reflected: turn._currentStep._context.reflected,
8048
+ didThresholdCleanup: turn._currentStep._context.didThresholdCleanup,
8049
+ messageCount: Array.isArray(turn._currentStep._context.messages) ? turn._currentStep._context.messages.length : void 0,
8050
+ systemMessageCount: Array.isArray(turn._currentStep._context.systemMessage) ? turn._currentStep._context.systemMessage.length : void 0
8051
+ } : void 0
8052
+ } : void 0
8053
+ };
8054
+ }
8055
+ function sanitizeCaptureState(rawState) {
8056
+ return Object.fromEntries(
8057
+ Object.entries(rawState).map(([key, value]) => {
8058
+ if (key === "__omTurn") {
8059
+ return [key, summarizeOmTurn(value)];
8060
+ }
8061
+ return [key, value];
8062
+ })
8063
+ );
8064
+ }
7742
8065
  function buildReproMessageFingerprint(message) {
7743
8066
  const createdAt = message.createdAt instanceof Date ? message.createdAt.toISOString() : message.createdAt ? new Date(message.createdAt).toISOString() : "";
7744
8067
  return JSON.stringify({
@@ -7794,60 +8117,88 @@ function writeProcessInputStepReproCapture(params) {
7794
8117
  const addedMessageIds = contextMessages.map((message) => message.id).filter((id) => Boolean(id) && !preMessageIds.has(id));
7795
8118
  const idRemap = inferReproIdRemap(params.preMessages, contextMessages);
7796
8119
  const rawState = params.args.state ?? {};
7797
- const inputPayload = safeCaptureJson({
7798
- stepNumber: params.stepNumber,
7799
- threadId: params.threadId,
7800
- resourceId: params.resourceId,
7801
- readOnly: memoryContext?.memoryConfig?.readOnly,
7802
- messageCount: contextMessages.length,
7803
- messageIds: contextMessages.map((message) => message.id),
7804
- stateKeys: Object.keys(rawState),
7805
- state: rawState,
7806
- args: {
7807
- messages: params.args.messages,
7808
- steps: params.args.steps,
7809
- systemMessages: params.args.systemMessages,
7810
- retryCount: params.args.retryCount,
7811
- tools: params.args.tools,
7812
- toolChoice: params.args.toolChoice,
7813
- activeTools: params.args.activeTools,
7814
- providerOptions: params.args.providerOptions,
7815
- modelSettings: params.args.modelSettings,
7816
- structuredOutput: params.args.structuredOutput
7817
- }
7818
- });
7819
- const preStatePayload = safeCaptureJson({
7820
- record: params.preRecord,
7821
- bufferedChunks: params.preBufferedChunks,
7822
- contextTokenCount: params.preContextTokenCount,
7823
- messages: params.preMessages,
7824
- messageList: params.preSerializedMessageList
7825
- });
7826
- const outputPayload = safeCaptureJson({
7827
- details: params.details,
7828
- messageDiff: {
7829
- removedMessageIds,
7830
- addedMessageIds,
7831
- idRemap
8120
+ const sanitizedState = sanitizeCaptureState(rawState);
8121
+ const payloads = [
8122
+ {
8123
+ fileName: "input.json",
8124
+ data: {
8125
+ stepNumber: params.stepNumber,
8126
+ threadId: params.threadId,
8127
+ resourceId: params.resourceId,
8128
+ readOnly: memoryContext?.memoryConfig?.readOnly,
8129
+ messageCount: contextMessages.length,
8130
+ messageIds: contextMessages.map((message) => message.id),
8131
+ stateKeys: Object.keys(rawState),
8132
+ state: sanitizedState,
8133
+ args: {
8134
+ messages: params.args.messages,
8135
+ steps: params.args.steps,
8136
+ systemMessages: params.args.systemMessages,
8137
+ retryCount: params.args.retryCount,
8138
+ toolChoice: params.args.toolChoice,
8139
+ activeTools: params.args.activeTools,
8140
+ modelSettings: params.args.modelSettings,
8141
+ structuredOutput: params.args.structuredOutput
8142
+ }
8143
+ }
8144
+ },
8145
+ {
8146
+ fileName: "pre-state.json",
8147
+ data: {
8148
+ record: params.preRecord,
8149
+ bufferedChunks: params.preBufferedChunks,
8150
+ contextTokenCount: params.preContextTokenCount,
8151
+ messages: params.preMessages,
8152
+ messageList: params.preSerializedMessageList
8153
+ }
8154
+ },
8155
+ {
8156
+ fileName: "output.json",
8157
+ data: {
8158
+ details: params.details,
8159
+ messageDiff: {
8160
+ removedMessageIds,
8161
+ addedMessageIds,
8162
+ idRemap
8163
+ }
8164
+ }
8165
+ },
8166
+ {
8167
+ fileName: "post-state.json",
8168
+ data: {
8169
+ record: params.postRecord,
8170
+ bufferedChunks: params.postBufferedChunks,
8171
+ contextTokenCount: params.postContextTokenCount,
8172
+ messageCount: contextMessages.length,
8173
+ messageIds: contextMessages.map((message) => message.id),
8174
+ messages: contextMessages,
8175
+ messageList: params.messageList.serialize()
8176
+ }
7832
8177
  }
7833
- });
7834
- const postStatePayload = safeCaptureJson({
7835
- record: params.postRecord,
7836
- bufferedChunks: params.postBufferedChunks,
7837
- contextTokenCount: params.postContextTokenCount,
7838
- messageCount: contextMessages.length,
7839
- messageIds: contextMessages.map((message) => message.id),
7840
- messages: contextMessages,
7841
- messageList: params.messageList.serialize()
7842
- });
7843
- writeFileSync(join(captureDir, "input.json"), `${JSON.stringify(inputPayload, null, 2)}
7844
- `);
7845
- writeFileSync(join(captureDir, "pre-state.json"), `${JSON.stringify(preStatePayload, null, 2)}
7846
- `);
7847
- writeFileSync(join(captureDir, "output.json"), `${JSON.stringify(outputPayload, null, 2)}
8178
+ ];
8179
+ const captureErrors = [];
8180
+ for (const payload of payloads) {
8181
+ const serialized = safeCaptureJsonOrError(payload.data);
8182
+ if (serialized.ok) {
8183
+ writeFileSync(join(captureDir, payload.fileName), `${JSON.stringify(serialized.value, null, 2)}
7848
8184
  `);
7849
- writeFileSync(join(captureDir, "post-state.json"), `${JSON.stringify(postStatePayload, null, 2)}
8185
+ continue;
8186
+ }
8187
+ captureErrors.push({ fileName: payload.fileName, error: serialized.error });
8188
+ writeFileSync(
8189
+ join(captureDir, payload.fileName),
8190
+ `${JSON.stringify({ __captureError: serialized.error }, null, 2)}
8191
+ `
8192
+ );
8193
+ }
8194
+ if (captureErrors.length > 0) {
8195
+ writeFileSync(join(captureDir, "capture-error.json"), `${JSON.stringify(captureErrors, null, 2)}
7850
8196
  `);
8197
+ params.debug?.(
8198
+ `[OM:repro-capture] wrote processInputStep capture with ${captureErrors.length} serialization error(s) to ${captureDir}`
8199
+ );
8200
+ return;
8201
+ }
7851
8202
  params.debug?.(`[OM:repro-capture] wrote processInputStep capture to ${captureDir}`);
7852
8203
  } catch (error) {
7853
8204
  params.debug?.(`[OM:repro-capture] failed to write processInputStep capture: ${String(error)}`);
@@ -7855,6 +8206,17 @@ function writeProcessInputStepReproCapture(params) {
7855
8206
  }
7856
8207
 
7857
8208
  // src/processors/observational-memory/processor.ts
8209
+ function getOmObservabilityContext(args) {
8210
+ if (!args.tracing || !args.tracingContext || !args.loggerVNext || !args.metrics) {
8211
+ return void 0;
8212
+ }
8213
+ return {
8214
+ tracing: args.tracing,
8215
+ tracingContext: args.tracingContext,
8216
+ loggerVNext: args.loggerVNext,
8217
+ metrics: args.metrics
8218
+ };
8219
+ }
7858
8220
  var ObservationalMemoryProcessor = class {
7859
8221
  id = "observational-memory";
7860
8222
  name = "Observational Memory";
@@ -7870,7 +8232,17 @@ var ObservationalMemoryProcessor = class {
7870
8232
  }
7871
8233
  // ─── Processor lifecycle hooks ──────────────────────────────────────────
7872
8234
  async processInputStep(args) {
7873
- const { messageList, requestContext, stepNumber, state: _state, writer, model, abortSignal, abort } = args;
8235
+ const {
8236
+ messageList,
8237
+ requestContext,
8238
+ stepNumber,
8239
+ state: _state,
8240
+ writer,
8241
+ model,
8242
+ abortSignal,
8243
+ abort,
8244
+ rotateResponseMessageId
8245
+ } = args;
7874
8246
  const state = _state ?? {};
7875
8247
  omDebug(
7876
8248
  `[OM:processInputStep:ENTER] step=${stepNumber}, hasMastraMemory=${!!requestContext?.get("MastraMemory")}, hasMemoryInfo=${!!messageList?.serialize()?.memoryInfo?.threadId}`
@@ -7898,12 +8270,23 @@ var ObservationalMemoryProcessor = class {
7898
8270
  await this.turn.end().catch(() => {
7899
8271
  });
7900
8272
  }
7901
- this.turn = this.engine.beginTurn({ threadId, resourceId, messageList });
8273
+ this.turn = this.engine.beginTurn({
8274
+ threadId,
8275
+ resourceId,
8276
+ messageList,
8277
+ observabilityContext: getOmObservabilityContext(args),
8278
+ hooks: {
8279
+ onBufferChunkSealed: rotateResponseMessageId
8280
+ }
8281
+ });
7902
8282
  this.turn.writer = writer;
7903
8283
  this.turn.requestContext = requestContext;
7904
8284
  await this.turn.start(this.memory);
7905
8285
  state.__omTurn = this.turn;
7906
8286
  }
8287
+ const observabilityContext = getOmObservabilityContext(args);
8288
+ state.__omObservabilityContext = observabilityContext;
8289
+ this.turn.observabilityContext = observabilityContext;
7907
8290
  {
7908
8291
  const step = this.turn.step(stepNumber);
7909
8292
  let ctx;
@@ -7984,6 +8367,8 @@ var ObservationalMemoryProcessor = class {
7984
8367
  const state = _state ?? {};
7985
8368
  const context = this.engine.getThreadContext(requestContext, messageList);
7986
8369
  if (!context) return messageList;
8370
+ const observabilityContext = getOmObservabilityContext(args);
8371
+ state.__omObservabilityContext = observabilityContext;
7987
8372
  return this.engine.getTokenCounter().runWithModelContext(state.__omActorModelContext, async () => {
7988
8373
  const memoryContext = parseMemoryRequestContext(requestContext);
7989
8374
  if (memoryContext?.memoryConfig?.readOnly) return messageList;
@@ -8033,5 +8418,5 @@ function getObservationsAsOf(activeObservations, asOf) {
8033
8418
  }
8034
8419
 
8035
8420
  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 };
8036
- //# sourceMappingURL=chunk-2QSOQQPM.js.map
8037
- //# sourceMappingURL=chunk-2QSOQQPM.js.map
8421
+ //# sourceMappingURL=chunk-D4D6ZFBQ.js.map
8422
+ //# sourceMappingURL=chunk-D4D6ZFBQ.js.map