@mastra/memory 1.30.0-alpha.2 → 1.30.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.
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-guides-context-engineering.md +1 -1
- package/dist/docs/references/docs-memory-observational-memory.md +2 -2
- package/dist/docs/references/reference-memory-observational-memory.md +3 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/processors/index.cjs +1 -1
- package/dist/processors/index.js +1 -1
- package/dist/processors/observational-memory/observation-turn/load-memory-context.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/safe-buffer-prefix.d.ts +35 -0
- package/dist/processors/observational-memory/observation-turn/safe-buffer-prefix.d.ts.map +1 -0
- package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/processor.d.ts.map +1 -1
- package/dist/processors/observational-memory/tracing.d.ts.map +1 -1
- package/dist/processors/observational-memory/types.d.ts +6 -0
- package/dist/processors/observational-memory/types.d.ts.map +1 -1
- package/dist/{src-TN3MwGgP.js → src-Dt8oPiQN.js} +113 -36
- package/dist/src-Dt8oPiQN.js.map +1 -0
- package/dist/{src-Bs9_1MCb.cjs → src-oL_dDHN9.cjs} +113 -36
- package/dist/src-oL_dDHN9.cjs.map +1 -0
- package/package.json +4 -4
- package/dist/src-Bs9_1MCb.cjs.map +0 -1
- package/dist/src-TN3MwGgP.js.map +0 -1
|
@@ -19797,19 +19797,28 @@ const PHASE_CONFIG = {
|
|
|
19797
19797
|
};
|
|
19798
19798
|
async function withOmTracingSpan({ phase, model, inputTokens, requestContext, observabilityContext, metadata, callback }) {
|
|
19799
19799
|
const config = PHASE_CONFIG[phase];
|
|
19800
|
+
const tracingContext = observabilityContext?.tracingContext ?? observabilityContext?.tracing;
|
|
19801
|
+
const callerMetadata = tracingContext?.currentSpan?.metadata;
|
|
19802
|
+
const inheritedCallerThreadId = callerMetadata?.__mastraObservationalMemoryCallerThreadId;
|
|
19803
|
+
const callerThreadId = callerMetadata?.threadId;
|
|
19804
|
+
const requestThreadId = requestContext?.get(MASTRA_THREAD_ID_KEY);
|
|
19805
|
+
const omCallerThreadId = typeof inheritedCallerThreadId === "string" && inheritedCallerThreadId ? inheritedCallerThreadId : typeof callerThreadId === "string" && callerThreadId ? callerThreadId : typeof requestThreadId === "string" && requestThreadId ? requestThreadId : void 0;
|
|
19800
19806
|
const span = getOrCreateSpan({
|
|
19801
19807
|
type: SpanType.MEMORY_OPERATION,
|
|
19802
19808
|
name: config.name,
|
|
19803
19809
|
entityType: EntityType.MEMORY,
|
|
19804
19810
|
entityName: config.entityName,
|
|
19805
|
-
tracingContext
|
|
19811
|
+
tracingContext,
|
|
19806
19812
|
attributes: {
|
|
19807
19813
|
operationType: config.operationType,
|
|
19808
19814
|
inputTokens,
|
|
19809
19815
|
selectedModel: typeof model === "string" ? model : "(dynamic-model)",
|
|
19810
19816
|
...config.multiThread ? { multiThread: true } : {}
|
|
19811
19817
|
},
|
|
19812
|
-
metadata
|
|
19818
|
+
metadata: omCallerThreadId !== void 0 ? {
|
|
19819
|
+
...metadata,
|
|
19820
|
+
__mastraObservationalMemoryCallerThreadId: omCallerThreadId
|
|
19821
|
+
} : metadata,
|
|
19813
19822
|
requestContext
|
|
19814
19823
|
});
|
|
19815
19824
|
const childObservabilityContext = createObservabilityContext({ currentSpan: span });
|
|
@@ -25257,10 +25266,61 @@ async function loadMemoryContextMessages({ memory, messageList, threadId, resour
|
|
|
25257
25266
|
resourceId,
|
|
25258
25267
|
runState
|
|
25259
25268
|
});
|
|
25260
|
-
|
|
25269
|
+
const existingIds = new Set(messageList.get.all.db().map((message) => message.id));
|
|
25270
|
+
for (const msg of ctx.messages) if (msg.role !== "system" && !existingIds.has(msg.id)) messageList.add(msg, "memory");
|
|
25261
25271
|
return ctx;
|
|
25262
25272
|
}
|
|
25263
25273
|
//#endregion
|
|
25274
|
+
//#region src/processors/observational-memory/observation-turn/safe-buffer-prefix.ts
|
|
25275
|
+
function hasPendingToolCall(message) {
|
|
25276
|
+
return message.content.parts?.some((part) => part.type === "tool-invocation" && part.toolInvocation.state === "call") ?? false;
|
|
25277
|
+
}
|
|
25278
|
+
/**
|
|
25279
|
+
* Selects the unobserved messages that are safe to buffer while a tool call
|
|
25280
|
+
* may still be in flight.
|
|
25281
|
+
*
|
|
25282
|
+
* Only the chronologically last candidate can hold a live pending call: a
|
|
25283
|
+
* `tool-invocation` still in state `call` (client- or provider-executed) on the
|
|
25284
|
+
* newest message means the request ended waiting for its result. Any earlier
|
|
25285
|
+
* `call` is an orphan — the conversation already continued past it, and core's
|
|
25286
|
+
* output converter drops or placeholder-pairs it before the prompt reaches a
|
|
25287
|
+
* provider — so it is buffered like any other message.
|
|
25288
|
+
*
|
|
25289
|
+
* When the last candidate is pending, the prefix before it is buffered, but only
|
|
25290
|
+
* when the cut is clean. The cut is unsafe — and the whole attempt is deferred —
|
|
25291
|
+
* when:
|
|
25292
|
+
*
|
|
25293
|
+
* - Cursor collision: buffering advances the persisted cursor to
|
|
25294
|
+
* `max(buffered.createdAt) + 1ms`, and later candidate selection requires
|
|
25295
|
+
* `createdAt > cursor`. If the retained message sits at the same or +1ms
|
|
25296
|
+
* timestamp, the cursor would permanently hide it even after its result
|
|
25297
|
+
* arrives.
|
|
25298
|
+
* - Split tool exchange: a `toolCallId` appears on both sides of the cut, so
|
|
25299
|
+
* the observer would see half of a tool exchange.
|
|
25300
|
+
* - Ambiguous tail: several candidates share the newest timestamp and one of
|
|
25301
|
+
* them holds a pending call. `createdAt` alone cannot say which is really
|
|
25302
|
+
* last, so the pending call is treated as the tail and the attempt deferred.
|
|
25303
|
+
*
|
|
25304
|
+
* The result is always in chronological order. When the tail has no pending
|
|
25305
|
+
* call, every message is returned. An empty result means "defer this buffering
|
|
25306
|
+
* attempt" — callers must skip buffering entirely. Raw message persistence is
|
|
25307
|
+
* unaffected and happens elsewhere; the retained message becomes eligible again
|
|
25308
|
+
* once its tool call completes.
|
|
25309
|
+
*/
|
|
25310
|
+
function selectSafeBufferPrefix(messages) {
|
|
25311
|
+
const chronological = [...messages].sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
25312
|
+
const last = chronological[chronological.length - 1];
|
|
25313
|
+
if (!last) return chronological;
|
|
25314
|
+
const newestTime = new Date(last.createdAt).getTime();
|
|
25315
|
+
const newestGroup = chronological.filter((message) => new Date(message.createdAt).getTime() === newestTime);
|
|
25316
|
+
if (!newestGroup.some(hasPendingToolCall)) return chronological;
|
|
25317
|
+
if (newestGroup.length > 1) return [];
|
|
25318
|
+
const prefix = chronological.slice(0, -1);
|
|
25319
|
+
const retainedTime = new Date(last.createdAt).getTime();
|
|
25320
|
+
const retainedToolIds = new Set((last.content.parts ?? []).flatMap((part) => part.type === "tool-invocation" ? [part.toolInvocation.toolCallId] : []));
|
|
25321
|
+
return prefix.some((message) => new Date(message.createdAt).getTime() + 1 >= retainedTime || message.content.parts?.some((part) => part.type === "tool-invocation" && retainedToolIds.has(part.toolInvocation.toolCallId))) ? [] : prefix;
|
|
25322
|
+
}
|
|
25323
|
+
//#endregion
|
|
25264
25324
|
//#region src/processors/observational-memory/observation-turn/step.ts
|
|
25265
25325
|
/**
|
|
25266
25326
|
* Represents a single step in the agentic loop within an observation turn.
|
|
@@ -25383,37 +25443,41 @@ var ObservationStep = class {
|
|
|
25383
25443
|
record: this.turn.record,
|
|
25384
25444
|
messages: getObservableMessages(messageList)
|
|
25385
25445
|
});
|
|
25386
|
-
if (statusSnapshot.shouldBuffer
|
|
25446
|
+
if (statusSnapshot.shouldBuffer) {
|
|
25387
25447
|
const allMessages = getObservableMessages(messageList);
|
|
25388
25448
|
const unobservedMessages = om.getUnobservedMessages(allMessages, statusSnapshot.record);
|
|
25389
25449
|
const candidates = om.getUnobservedMessages(unobservedMessages, statusSnapshot.record, { excludeBuffered: true });
|
|
25390
|
-
|
|
25391
|
-
|
|
25450
|
+
const safeCandidates = selectSafeBufferPrefix(candidates);
|
|
25451
|
+
const deferred = candidates.length > 0 && safeCandidates.length === 0;
|
|
25452
|
+
if (safeCandidates.length > 0) {
|
|
25453
|
+
om.sealMessagesForBuffering(safeCandidates);
|
|
25392
25454
|
try {
|
|
25393
25455
|
await this.turn.hooks?.onBufferChunkSealed?.();
|
|
25394
25456
|
} catch (error) {
|
|
25395
25457
|
omDebug(`[OM:buffer] onBufferChunkSealed hook failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
25396
25458
|
}
|
|
25397
|
-
if (this.turn.memory) await this.turn.memory.persistMessages(
|
|
25398
|
-
messageList.removeByIds(
|
|
25399
|
-
for (const msg of
|
|
25459
|
+
if (this.turn.memory) await this.turn.memory.persistMessages(safeCandidates);
|
|
25460
|
+
messageList.removeByIds(safeCandidates.map((msg) => msg.id));
|
|
25461
|
+
for (const msg of safeCandidates) messageList.add(msg, "memory");
|
|
25462
|
+
}
|
|
25463
|
+
if (!deferred) {
|
|
25464
|
+
om.trackBackgroundWork(om.buffer({
|
|
25465
|
+
threadId,
|
|
25466
|
+
resourceId,
|
|
25467
|
+
messages: safeCandidates,
|
|
25468
|
+
pendingTokens: statusSnapshot.pendingTokens,
|
|
25469
|
+
record: statusSnapshot.record,
|
|
25470
|
+
writer: this.turn.writer,
|
|
25471
|
+
agent: this.turn.agent,
|
|
25472
|
+
sendSignal: this.turn.sendSignal,
|
|
25473
|
+
sendStateSignal: this.turn.sendStateSignal,
|
|
25474
|
+
requestContext: this.turn.requestContext,
|
|
25475
|
+
observabilityContext: this.turn.observabilityContext
|
|
25476
|
+
}).catch((err) => {
|
|
25477
|
+
omDebug(`[OM:buffer] fire-and-forget buffer failed: ${err?.message}`);
|
|
25478
|
+
}));
|
|
25479
|
+
buffered = true;
|
|
25400
25480
|
}
|
|
25401
|
-
om.trackBackgroundWork(om.buffer({
|
|
25402
|
-
threadId,
|
|
25403
|
-
resourceId,
|
|
25404
|
-
messages: unobservedMessages,
|
|
25405
|
-
pendingTokens: statusSnapshot.pendingTokens,
|
|
25406
|
-
record: statusSnapshot.record,
|
|
25407
|
-
writer: this.turn.writer,
|
|
25408
|
-
agent: this.turn.agent,
|
|
25409
|
-
sendSignal: this.turn.sendSignal,
|
|
25410
|
-
sendStateSignal: this.turn.sendStateSignal,
|
|
25411
|
-
requestContext: this.turn.requestContext,
|
|
25412
|
-
observabilityContext: this.turn.observabilityContext
|
|
25413
|
-
}).catch((err) => {
|
|
25414
|
-
omDebug(`[OM:buffer] fire-and-forget buffer failed: ${err?.message}`);
|
|
25415
|
-
}));
|
|
25416
|
-
buffered = true;
|
|
25417
25481
|
}
|
|
25418
25482
|
const willObserveNow = statusSnapshot.shouldObserve && !hasIncompleteToolCalls;
|
|
25419
25483
|
/** In-flight message ids the step-0 cleanup must never remove from live context. */
|
|
@@ -25788,11 +25852,11 @@ var ObservationTurn = class {
|
|
|
25788
25852
|
if (asyncObservationEnabled && bufferOnIdle) {
|
|
25789
25853
|
const allMessages = getObservableMessages(this.messageList);
|
|
25790
25854
|
const record = this._record;
|
|
25791
|
-
const
|
|
25792
|
-
if (
|
|
25855
|
+
const idleMessages = selectSafeBufferPrefix(this.om.getUnobservedMessages(allMessages, record));
|
|
25856
|
+
if (idleMessages.length > 0) this.om.trackBackgroundWork(this.om.buffer({
|
|
25793
25857
|
threadId: this.threadId,
|
|
25794
25858
|
resourceId: this.resourceId,
|
|
25795
|
-
messages:
|
|
25859
|
+
messages: idleMessages,
|
|
25796
25860
|
record,
|
|
25797
25861
|
writer: this.writer,
|
|
25798
25862
|
agent: this.agent,
|
|
@@ -27520,15 +27584,18 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
27520
27584
|
this.hookExecution = config.hookExecution ?? "non-blocking";
|
|
27521
27585
|
this.mastra = config.mastra;
|
|
27522
27586
|
this.memory = config.memory;
|
|
27587
|
+
const topLevelModel = config.model;
|
|
27588
|
+
const observationConfigModel = config.observation?.model;
|
|
27589
|
+
const reflectionConfigModel = config.reflection?.model;
|
|
27523
27590
|
const resolveModel = (model, defaultModel) => model === "default" ? defaultModel : model;
|
|
27524
|
-
const observationModel = resolveModel(
|
|
27525
|
-
const reflectionModel = resolveModel(
|
|
27591
|
+
const observationModel = resolveModel(topLevelModel, OBSERVATIONAL_MEMORY_DEFAULTS.observation.model) ?? resolveModel(observationConfigModel, OBSERVATIONAL_MEMORY_DEFAULTS.observation.model) ?? resolveModel(reflectionConfigModel, OBSERVATIONAL_MEMORY_DEFAULTS.observation.model) ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.model;
|
|
27592
|
+
const reflectionModel = resolveModel(topLevelModel, OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model) ?? resolveModel(reflectionConfigModel, OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model) ?? resolveModel(observationConfigModel, OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model) ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model;
|
|
27526
27593
|
const messageTokens = config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens;
|
|
27527
27594
|
const observationTokens = config.reflection?.observationTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens;
|
|
27528
27595
|
const isSharedBudget = config.shareTokenBudget ?? false;
|
|
27529
27596
|
const isDefaultModelSelection = (model) => model === void 0 || model === "default" || model instanceof ModelByInputTokens;
|
|
27530
|
-
const observationSelectedModel =
|
|
27531
|
-
const reflectionSelectedModel =
|
|
27597
|
+
const observationSelectedModel = topLevelModel ?? observationConfigModel ?? reflectionConfigModel;
|
|
27598
|
+
const reflectionSelectedModel = topLevelModel ?? reflectionConfigModel ?? observationConfigModel;
|
|
27532
27599
|
const observationDefaultMaxOutputTokens = config.observation?.modelSettings?.maxOutputTokens ?? (isDefaultModelSelection(observationSelectedModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.observation.modelSettings.maxOutputTokens : void 0);
|
|
27533
27600
|
const reflectionDefaultMaxOutputTokens = config.reflection?.modelSettings?.maxOutputTokens ?? (isDefaultModelSelection(reflectionSelectedModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.modelSettings.maxOutputTokens : void 0);
|
|
27534
27601
|
const totalBudget = messageTokens + observationTokens;
|
|
@@ -28491,7 +28558,7 @@ ${formattedMessages}
|
|
|
28491
28558
|
if (!this.buffering.isAsyncObservationEnabled()) return false;
|
|
28492
28559
|
const lockKey = this.buffering.getLockKey(opts.threadId, opts.resourceId);
|
|
28493
28560
|
const shouldTrigger = this.buffering.shouldTriggerAsyncObservation(opts.pendingTokens, lockKey, opts.record, this.storage, opts.threshold);
|
|
28494
|
-
if (shouldTrigger) this.trackBackgroundWork(this.startAsyncBufferedObservation(opts.record, opts.threadId, opts.unobservedMessages, lockKey, opts.writer, opts.unbufferedPendingTokens, opts.requestContext));
|
|
28561
|
+
if (shouldTrigger) this.trackBackgroundWork(this.startAsyncBufferedObservation(opts.record, opts.threadId, opts.unobservedMessages, lockKey, opts.writer, opts.unbufferedPendingTokens, opts.requestContext, opts.observabilityContext));
|
|
28495
28562
|
return shouldTrigger;
|
|
28496
28563
|
}
|
|
28497
28564
|
isMessageList(value) {
|
|
@@ -30248,6 +30315,16 @@ function normalizeObservationalMemoryConfig(config) {
|
|
|
30248
30315
|
if (typeof config === "object" && config.enabled === false) return void 0;
|
|
30249
30316
|
return config;
|
|
30250
30317
|
}
|
|
30318
|
+
/**
|
|
30319
|
+
* Observer model selection (`observation.model`, else top-level `model`), read into the widened
|
|
30320
|
+
* model type first: combining values of the public type makes TS subtype-reduce the model-id
|
|
30321
|
+
* literal union, which fails with TS2590 once the provider registry is large enough.
|
|
30322
|
+
*/
|
|
30323
|
+
function selectObserverModel(omConfig) {
|
|
30324
|
+
const observationModel = omConfig.observation?.model;
|
|
30325
|
+
const topLevelModel = omConfig.model;
|
|
30326
|
+
return observationModel ?? topLevelModel;
|
|
30327
|
+
}
|
|
30251
30328
|
function hasWorkingMemoryExtractor(extractors) {
|
|
30252
30329
|
return !!extractors?.some((extractor) => extractor.slug === "working-memory");
|
|
30253
30330
|
}
|
|
@@ -30365,7 +30442,7 @@ var Memory = class Memory extends MastraMemory {
|
|
|
30365
30442
|
const extract = observation.extract ?? [];
|
|
30366
30443
|
const existingSlugs = new Set(extract.map((extractor) => extractor.slug));
|
|
30367
30444
|
let curatorMemory;
|
|
30368
|
-
const subconsciousExtractors = omConfig.experimental_subconscious.createObservationExtractors(
|
|
30445
|
+
const subconsciousExtractors = omConfig.experimental_subconscious.createObservationExtractors(selectObserverModel(omConfig), () => curatorMemory ??= new Memory({
|
|
30369
30446
|
storage: this.storage,
|
|
30370
30447
|
options: { observationalMemory: false }
|
|
30371
30448
|
})).filter((extractor) => !existingSlugs.has(extractor.slug));
|
|
@@ -31671,7 +31748,7 @@ Notes:
|
|
|
31671
31748
|
if (remind && "builtIn" in remind) tools.ask_memory = createAskMemoryTool({
|
|
31672
31749
|
memory: this,
|
|
31673
31750
|
config: remind,
|
|
31674
|
-
omModel: omConfig
|
|
31751
|
+
omModel: selectObserverModel(omConfig),
|
|
31675
31752
|
getParentAgent: (agentId) => this._mastraInstance?.getAgentById(agentId)
|
|
31676
31753
|
});
|
|
31677
31754
|
}
|
|
@@ -32350,4 +32427,4 @@ Notes:
|
|
|
32350
32427
|
//#endregion
|
|
32351
32428
|
export { formatMessagesForObserver as A, OBSERVATION_CONTINUATION_HINT as B, SUMMARIZE_THREAD_DEFAULTS as C, buildObserverPrompt as D, OBSERVER_SYSTEM_PROMPT as E, parseAnchorId as F, ModelByInputTokens as G, KnowledgeSemanticIndexCoordinator as H, stripEphemeralAnchorIds as I, publishSubconsciousActivity as J, SUBCONSCIOUS_ACTIVITY_STATE_ID as K, OBSERVATIONAL_MEMORY_DEFAULTS as L, optimizeObservationsForContext as M, parseObserverOutput as N, buildObserverSystemPrompt as O, injectAnchorIds as P, OBSERVATION_CONTEXT_INSTRUCTIONS as R, WorkingMemoryExtractor as S, TokenCounter as T, StaleKnowledgeSemanticIndexError as U, Subconscious as V, SubconsciousRemindExtractor as W, Extractor as X, renderSubconsciousActivity as Y, wrapInObservationGroup as _, extractWorkingMemoryContent as a, WorkingMemoryStateProcessor as b, getObservationsAsOf as c, combineObservationGroupRanges as d, deriveObservationGroupProvenance as f, stripObservationGroups as g, renderObservationGroupsForReflection as h, WorkingMemory as i, hasCurrentTaskSection as j, extractCurrentTask as k, ObservationalMemoryProcessor as l, reconcileObservationGroupsFromReflection as m, MessageHistory$1 as n, extractWorkingMemoryTags as o, parseObservationGroups as p, buildSubconsciousActivitySnapshot as q, SemanticRecall as r, removeWorkingMemoryTags as s, Memory as t, ObservationalMemory as u, WORKING_MEMORY_STATE_ID as v, summarizeConversation as w, deepMergeWorkingMemory as x, WORKING_MEMORY_STATE_PROCESSOR_ID as y, OBSERVATION_CONTEXT_PROMPT as z };
|
|
32352
32429
|
|
|
32353
|
-
//# sourceMappingURL=src-
|
|
32430
|
+
//# sourceMappingURL=src-Dt8oPiQN.js.map
|