@mastra/memory 1.35.0 → 1.36.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26045,8 +26045,23 @@ function getOpenAIPromptCacheRetention(providerOptions) {
26045
26045
  const openaiOptions = providerOptions?.openai;
26046
26046
  return typeof openaiOptions?.promptCacheRetention === "string" ? openaiOptions.promptCacheRetention.toLowerCase() : void 0;
26047
26047
  }
26048
+ function isActivationTTLMap(activateAfterIdle) {
26049
+ return typeof activateAfterIdle === "object" && activateAfterIdle !== null;
26050
+ }
26051
+ /** The configured TTL for marker payloads. Per-provider maps are omitted; markers only carry scalar values. */
26052
+ function getMarkerActivationTTL(activateAfterIdle) {
26053
+ return isActivationTTLMap(activateAfterIdle) ? void 0 : activateAfterIdle;
26054
+ }
26055
+ /** A map entry applies when its key equals the model's provider before the first `.`, lowercased. */
26056
+ function resolveActivationTTLMapEntry(activateAfterIdle, modelContext) {
26057
+ const providerKey = normalize(modelContext?.provider).split(".")[0];
26058
+ if (providerKey && Object.hasOwn(activateAfterIdle.providers, providerKey)) return activateAfterIdle.providers[providerKey];
26059
+ return activateAfterIdle.default;
26060
+ }
26048
26061
  function resolveActivationTTL(activateAfterIdle, modelContext) {
26049
- if (activateAfterIdle !== "auto") return activateAfterIdle;
26062
+ const ttl = isActivationTTLMap(activateAfterIdle) ? resolveActivationTTLMapEntry(activateAfterIdle, modelContext) : activateAfterIdle;
26063
+ if (ttl === void 0 || ttl === false) return;
26064
+ if (ttl !== "auto") return ttl;
26050
26065
  return resolveAutoActivationTTL(modelContext);
26051
26066
  }
26052
26067
  function resolveAutoActivationTTL(modelContext) {
@@ -28856,7 +28871,7 @@ var ReflectorRunner = class {
28856
28871
  messageTokens: getMaxThreshold(this.observationConfig.messageTokens),
28857
28872
  observationTokens: getMaxThreshold(record ? this.getEffectiveReflectionTokens(record) : this.reflectionConfig.observationTokens),
28858
28873
  scope: this.scope,
28859
- activateAfterIdle: this.reflectionConfig.activateAfterIdle
28874
+ activateAfterIdle: getMarkerActivationTTL(this.reflectionConfig.activateAfterIdle)
28860
28875
  };
28861
28876
  }
28862
28877
  /**
@@ -29287,7 +29302,7 @@ var ReflectorRunner = class {
29287
29302
  currentModel: activationMetadata?.currentModel,
29288
29303
  config: {
29289
29304
  ...this.getObservationMarkerConfig(freshRecord),
29290
- activateAfterIdle: activationMetadata?.activateAfterIdle ?? this.reflectionConfig.activateAfterIdle
29305
+ activateAfterIdle: activationMetadata?.activateAfterIdle ?? getMarkerActivationTTL(this.reflectionConfig.activateAfterIdle)
29291
29306
  }
29292
29307
  });
29293
29308
  writer.custom({
@@ -29976,6 +29991,32 @@ function parseActivationTTL(value, fieldPath) {
29976
29991
  if (!Number.isFinite(amount) || amount < 0) throw new Error(`${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m".`);
29977
29992
  return amount * (unit === "ms" || unit === "msec" || unit === "msecs" || unit === "millisecond" || unit === "milliseconds" ? 1 : unit === "s" || unit === "sec" || unit === "secs" || unit === "second" || unit === "seconds" ? 1e3 : unit === "m" || unit === "min" || unit === "mins" || unit === "minute" || unit === "minutes" ? 6e4 : 36e5);
29978
29993
  }
29994
+ /**
29995
+ * Parse an `activateAfterIdle` config value: a scalar TTL, or a per-provider map
29996
+ * like `{ default: 'auto', anthropic: '1h' }`.
29997
+ */
29998
+ function parseActivationTTLConfig(value, fieldPath) {
29999
+ if (typeof value !== "object") return parseActivationTTL(value, fieldPath);
30000
+ if (value === null || Array.isArray(value)) throw new Error(`${fieldPath} must be a TTL value or an object of per-provider TTLs, e.g. { default: 'auto', anthropic: '1h' }.`);
30001
+ const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== void 0);
30002
+ if (entries.length === 0) throw new Error(`${fieldPath} must set at least one provider or "default" when using per-provider TTLs, e.g. { default: 'auto', anthropic: '1h' }.`);
30003
+ const parsed = { providers: Object.create(null) };
30004
+ const seenKeys = /* @__PURE__ */ new Set();
30005
+ for (const [rawKey, entryValue] of entries) {
30006
+ const key = rawKey.trim().toLowerCase();
30007
+ const entryPath = `${fieldPath}.${rawKey}`;
30008
+ if (!key) throw new Error(`${fieldPath} contains an empty provider key.`);
30009
+ if (key.includes(".") || key.includes("/")) throw new Error(`${entryPath} is not a valid provider key. Use the provider name before the first ".", e.g. "anthropic" instead of "anthropic.messages".`);
30010
+ if (seenKeys.has(key)) throw new Error(`${entryPath} duplicates another key in ${fieldPath}. Provider keys are case-insensitive.`);
30011
+ seenKeys.add(key);
30012
+ if (entryValue !== false && typeof entryValue !== "number" && typeof entryValue !== "string") throw new Error(`${entryPath} must be a non-negative number of milliseconds, a duration string like "5m" or "1hr", "auto", or false.`);
30013
+ const ttl = entryValue === false ? false : parseActivationTTL(entryValue, entryPath);
30014
+ if (key === "default") {
30015
+ if (ttl !== false) parsed.default = ttl;
30016
+ } else parsed.providers[key] = ttl;
30017
+ }
30018
+ return parsed;
30019
+ }
29979
30020
  let hasWarnedResourceScopeDeprecation = false;
29980
30021
  /**
29981
30022
  * ObservationalMemory - A three-agent memory system for long conversations.
@@ -30190,7 +30231,7 @@ var ObservationalMemory = class ObservationalMemory {
30190
30231
  bufferTokens: asyncBufferingDisabled ? void 0 : resolveBufferTokens(config.observation?.bufferTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferTokens, config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens),
30191
30232
  bufferOnIdle: config.observation?.bufferOnIdle ?? false,
30192
30233
  bufferActivation: asyncBufferingDisabled ? void 0 : config.observation?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferActivation,
30193
- activateAfterIdle: parseActivationTTL(observationActivateAfterIdle, observationActivateAfterIdlePath),
30234
+ activateAfterIdle: parseActivationTTLConfig(observationActivateAfterIdle, observationActivateAfterIdlePath),
30194
30235
  activateOnProviderChange: config.observation?.activateOnProviderChange ?? config.activateOnProviderChange ?? false,
30195
30236
  blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(config.observation?.blockAfter ?? (config.observation?.bufferTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferTokens ? 1.2 : void 0), config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens),
30196
30237
  previousObserverTokens: config.observation?.previousObserverTokens ?? 2e3,
@@ -30215,7 +30256,7 @@ var ObservationalMemory = class ObservationalMemory {
30215
30256
  },
30216
30257
  providerOptions: config.reflection?.providerOptions ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.providerOptions,
30217
30258
  bufferActivation: asyncBufferingDisabled ? void 0 : config?.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation,
30218
- activateAfterIdle: parseActivationTTL(config.reflection?.activateAfterIdle, "reflection.activateAfterIdle"),
30259
+ activateAfterIdle: parseActivationTTLConfig(config.reflection?.activateAfterIdle, "reflection.activateAfterIdle"),
30219
30260
  activateOnProviderChange: config.reflection?.activateOnProviderChange ?? false,
30220
30261
  blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(config.reflection?.blockAfter ?? (config.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation ? 1.2 : void 0), config.reflection?.observationTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens),
30221
30262
  instruction: config.reflection?.instruction,
@@ -30541,7 +30582,7 @@ var ObservationalMemory = class ObservationalMemory {
30541
30582
  messageTokens: getMaxThreshold(this.observationConfig.messageTokens),
30542
30583
  observationTokens: getMaxThreshold(this.reflectionConfig.observationTokens),
30543
30584
  scope: this.scope,
30544
- activateAfterIdle: this.observationConfig.activateAfterIdle
30585
+ activateAfterIdle: getMarkerActivationTTL(this.observationConfig.activateAfterIdle)
30545
30586
  };
30546
30587
  }
30547
30588
  /**
@@ -31942,7 +31983,7 @@ ${formattedMessages}
31942
31983
  currentModel,
31943
31984
  config: {
31944
31985
  ...this.getObservationMarkerConfig(),
31945
- activateAfterIdle: activationActivateAfterIdle ?? this.observationConfig.activateAfterIdle
31986
+ activateAfterIdle: activationActivateAfterIdle ?? getMarkerActivationTTL(this.observationConfig.activateAfterIdle)
31946
31987
  }
31947
31988
  });
31948
31989
  opts.writer.custom({
@@ -33253,22 +33294,32 @@ var Memory = class Memory extends _mastra_core_memory.MastraMemory {
33253
33294
  if (resourceScope && !resourceId && config?.semanticRecall && vectorSearchString) throw new Error("Memory error: Resource-scoped semantic recall is enabled but no resourceId was provided. Either provide a resourceId or explicitly set semanticRecall.scope to 'thread'.");
33254
33295
  let usage;
33255
33296
  if (config?.semanticRecall && vectorSearchString && this.vector) {
33256
- const result = await this.embedMessageContent(vectorSearchString);
33257
- usage = result.usage;
33258
- const { embeddings, dimension } = result;
33259
- const { indexName } = await this.createEmbeddingIndex(dimension, config);
33260
- await Promise.all(embeddings.map(async (embedding) => {
33261
- if (typeof this.vector === `undefined`) throw new Error(`Tried to query vector index ${indexName} but this Memory instance doesn't have an attached vector db.`);
33262
- const scopeFilter = resourceScope ? { resource_id: resourceId } : { thread_id: threadId };
33263
- const userFilter = typeof config.semanticRecall === "object" ? config.semanticRecall.filter : void 0;
33264
- const combinedFilter = userFilter ? { $and: [scopeFilter, userFilter] } : scopeFilter;
33297
+ const scopeFilter = resourceScope ? { resource_id: resourceId } : { thread_id: threadId };
33298
+ const userFilter = typeof config.semanticRecall === "object" ? config.semanticRecall.filter : void 0;
33299
+ const combinedFilter = userFilter ? { $and: [scopeFilter, userFilter] } : scopeFilter;
33300
+ if (this.isSelfEmbedding) {
33301
+ const { indexName } = await this.createEmbeddingIndex(void 0, config);
33265
33302
  vectorResults.push(...await this.vector.query({
33266
33303
  indexName,
33267
- queryVector: embedding,
33304
+ queryText: vectorSearchString,
33268
33305
  topK: vectorConfig.topK,
33269
33306
  filter: combinedFilter
33270
33307
  }));
33271
- }));
33308
+ } else {
33309
+ const result = await this.embedMessageContent(vectorSearchString);
33310
+ usage = result.usage;
33311
+ const { embeddings, dimension } = result;
33312
+ const { indexName } = await this.createEmbeddingIndex(dimension, config);
33313
+ await Promise.all(embeddings.map(async (embedding) => {
33314
+ if (typeof this.vector === `undefined`) throw new Error(`Tried to query vector index ${indexName} but this Memory instance doesn't have an attached vector db.`);
33315
+ vectorResults.push(...await this.vector.query({
33316
+ indexName,
33317
+ queryVector: embedding,
33318
+ topK: vectorConfig.topK,
33319
+ filter: combinedFilter
33320
+ }));
33321
+ }));
33322
+ }
33272
33323
  }
33273
33324
  const threshold = (typeof config.semanticRecall === "object" ? config.semanticRecall : void 0)?.threshold;
33274
33325
  const filteredVectorResults = threshold !== void 0 ? vectorResults.filter((r) => r.score >= threshold) : vectorResults;
@@ -33426,11 +33477,13 @@ var Memory = class Memory extends _mastra_core_memory.MastraMemory {
33426
33477
  if (this.vector) this.trackVectorCleanup(this.deleteThreadVectors(threadId));
33427
33478
  }
33428
33479
  /**
33429
- * Prefix shared by every message index. The index for the default embedding
33430
- * dimension is named with the bare prefix; other dimensions add a suffix.
33480
+ * Prefix shared by every message index. The index for the default embedding dimension is named
33481
+ * with the bare prefix; other dimensions add a dimension suffix, and a store that embeds the
33482
+ * text itself adds its own. Built here rather than read from `getEmbeddingIndexName()`, which
33483
+ * answers for one configuration and so would not match indexes written under another.
33431
33484
  */
33432
33485
  get messageIndexPrefix() {
33433
- return this.getEmbeddingIndexName();
33486
+ return `memory${this.vector?.indexSeparator ?? "_"}messages`;
33434
33487
  }
33435
33488
  /**
33436
33489
  * Prefix shared by every observation index. Each observation index adds a dimension suffix.
@@ -33715,13 +33768,24 @@ ${workingMemory}`;
33715
33768
  if (joined) textForEmbedding = joined;
33716
33769
  }
33717
33770
  if (!textForEmbedding) return;
33718
- const result = await this.embedMessageContent(textForEmbedding);
33719
- dimension = result.dimension;
33720
- if (result.usage?.tokens) totalTokens += result.usage.tokens;
33771
+ let embeddings = [];
33772
+ let documents;
33773
+ let chunks;
33774
+ if (this.isSelfEmbedding) {
33775
+ chunks = this.chunkText(textForEmbedding);
33776
+ documents = chunks;
33777
+ } else {
33778
+ const result = await this.embedMessageContent(textForEmbedding);
33779
+ dimension = result.dimension;
33780
+ if (result.usage?.tokens) totalTokens += result.usage.tokens;
33781
+ embeddings = result.embeddings;
33782
+ chunks = result.chunks;
33783
+ }
33721
33784
  const threadMetadata = message.threadId ? threadMetadataMap.get(message.threadId) || {} : {};
33722
33785
  embeddingData.push({
33723
- embeddings: result.embeddings,
33724
- metadata: result.chunks.map(() => ({
33786
+ embeddings,
33787
+ documents,
33788
+ metadata: chunks.map(() => ({
33725
33789
  ...threadMetadata,
33726
33790
  message_id: message.id,
33727
33791
  thread_id: message.threadId,
@@ -33732,16 +33796,23 @@ ${workingMemory}`;
33732
33796
  }))
33733
33797
  });
33734
33798
  }));
33735
- if (embeddingData.length > 0 && dimension !== void 0) {
33799
+ if (embeddingData.length > 0 && (this.isSelfEmbedding || dimension !== void 0)) {
33736
33800
  if (typeof this.vector === `undefined`) throw new Error(`Tried to upsert embeddings but this Memory instance doesn't have an attached vector db.`);
33737
33801
  const { indexName } = await this.createEmbeddingIndex(dimension, config);
33738
33802
  const allVectors = [];
33739
33803
  const allMetadata = [];
33804
+ const allDocuments = [];
33740
33805
  for (const data of embeddingData) {
33741
33806
  allVectors.push(...data.embeddings);
33807
+ if (data.documents) allDocuments.push(...data.documents);
33742
33808
  allMetadata.push(...data.metadata);
33743
33809
  }
33744
- await this.vector.upsert({
33810
+ if (this.isSelfEmbedding) await this.vector.upsert({
33811
+ indexName,
33812
+ documents: allDocuments,
33813
+ metadata: allMetadata
33814
+ });
33815
+ else await this.vector.upsert({
33745
33816
  indexName,
33746
33817
  vectors: allVectors,
33747
33818
  metadata: allMetadata
@@ -34526,11 +34597,22 @@ Notes:
34526
34597
  }
34527
34598
  }
34528
34599
  if (textForEmbedding) {
34529
- const result = await this.embedMessageContent(textForEmbedding);
34530
- dimension = result.dimension;
34600
+ let embeddings = [];
34601
+ let documents;
34602
+ let chunks;
34603
+ if (this.isSelfEmbedding) {
34604
+ chunks = this.chunkText(textForEmbedding);
34605
+ documents = chunks;
34606
+ } else {
34607
+ const result = await this.embedMessageContent(textForEmbedding);
34608
+ dimension = result.dimension;
34609
+ embeddings = result.embeddings;
34610
+ chunks = result.chunks;
34611
+ }
34531
34612
  embeddingData.push({
34532
- embeddings: result.embeddings,
34533
- metadata: result.chunks.map(() => ({
34613
+ embeddings,
34614
+ documents,
34615
+ metadata: chunks.map(() => ({
34534
34616
  message_id: message.id,
34535
34617
  thread_id: existingMessage.threadId,
34536
34618
  resource_id: existingMessage.resourceId,
@@ -34565,15 +34647,22 @@ Notes:
34565
34647
  } catch {
34566
34648
  this.logger.debug("Failed to clean up old vectors during message update");
34567
34649
  }
34568
- if (embeddingData.length > 0 && dimension !== void 0) {
34650
+ if (embeddingData.length > 0 && (this.isSelfEmbedding || dimension !== void 0)) {
34569
34651
  const { indexName } = await this.createEmbeddingIndex(dimension, config);
34570
34652
  const allVectors = [];
34571
34653
  const allMetadata = [];
34654
+ const allDocuments = [];
34572
34655
  for (const data of embeddingData) {
34573
34656
  allVectors.push(...data.embeddings);
34657
+ if (data.documents) allDocuments.push(...data.documents);
34574
34658
  allMetadata.push(...data.metadata);
34575
34659
  }
34576
- await this.vector.upsert({
34660
+ if (this.isSelfEmbedding) await this.vector.upsert({
34661
+ indexName,
34662
+ documents: allDocuments,
34663
+ metadata: allMetadata
34664
+ });
34665
+ else await this.vector.upsert({
34577
34666
  indexName,
34578
34667
  vectors: allVectors,
34579
34668
  metadata: allMetadata
@@ -34760,7 +34849,7 @@ Notes:
34760
34849
  await this.rollbackCopiedThread(memoryStore, result.thread, "OM clone", false, priorDestinationResourceWm);
34761
34850
  throw error;
34762
34851
  }
34763
- if (this.vector && this.embedder && config.semanticRecall) try {
34852
+ if (this.vector && (this.embedder || this.isSelfEmbedding) && config.semanticRecall) try {
34764
34853
  await this.embedCopiedMessagesInBatches(memoryStore, result, config);
34765
34854
  } catch (error) {
34766
34855
  await this.rollbackCopiedThread(memoryStore, result.thread, "embedding", true, priorDestinationResourceWm);
@@ -34829,7 +34918,7 @@ Notes:
34829
34918
  async updateThreadResourceId({ threadId, resourceId, memoryConfig }) {
34830
34919
  const memoryStore = await this.getMemoryStore();
34831
34920
  const config = this.getMergedThreadConfig(memoryConfig);
34832
- const migratesVectors = Boolean(this.vector && this.embedder && config.semanticRecall);
34921
+ const migratesVectors = Boolean(this.vector && (this.embedder || this.isSelfEmbedding) && config.semanticRecall);
34833
34922
  if (!migratesVectors) {
34834
34923
  const existing = await memoryStore.getThreadById({ threadId });
34835
34924
  if (existing && existing.resourceId === resourceId) return existing;
@@ -34935,7 +35024,7 @@ Notes:
34935
35024
  * This is similar to the embedding logic in saveMessages but operates on already-saved messages.
34936
35025
  */
34937
35026
  async embedClonedMessages(messages, config) {
34938
- if (!this.vector || !this.embedder) return;
35027
+ if (!this.vector || !this.embedder && !this.isSelfEmbedding) return;
34939
35028
  const embeddingData = [];
34940
35029
  let dimension;
34941
35030
  await Promise.all(messages.map(async (message) => {
@@ -34946,11 +35035,22 @@ Notes:
34946
35035
  if (joined) textForEmbedding = joined;
34947
35036
  }
34948
35037
  if (!textForEmbedding) return;
34949
- const result = await this.embedMessageContent(textForEmbedding);
34950
- dimension = result.dimension;
35038
+ let embeddings = [];
35039
+ let documents;
35040
+ let chunks;
35041
+ if (this.isSelfEmbedding) {
35042
+ chunks = this.chunkText(textForEmbedding);
35043
+ documents = chunks;
35044
+ } else {
35045
+ const result = await this.embedMessageContent(textForEmbedding);
35046
+ dimension = result.dimension;
35047
+ embeddings = result.embeddings;
35048
+ chunks = result.chunks;
35049
+ }
34951
35050
  embeddingData.push({
34952
- embeddings: result.embeddings,
34953
- metadata: result.chunks.map(() => ({
35051
+ embeddings,
35052
+ documents,
35053
+ metadata: chunks.map(() => ({
34954
35054
  message_id: message.id,
34955
35055
  thread_id: message.threadId,
34956
35056
  resource_id: message.resourceId,
@@ -34960,15 +35060,22 @@ Notes:
34960
35060
  }))
34961
35061
  });
34962
35062
  }));
34963
- if (embeddingData.length > 0 && dimension !== void 0) {
35063
+ if (embeddingData.length > 0 && (this.isSelfEmbedding || dimension !== void 0)) {
34964
35064
  const { indexName } = await this.createEmbeddingIndex(dimension, config);
34965
35065
  const allVectors = [];
34966
35066
  const allMetadata = [];
35067
+ const allDocuments = [];
34967
35068
  for (const data of embeddingData) {
34968
35069
  allVectors.push(...data.embeddings);
35070
+ if (data.documents) allDocuments.push(...data.documents);
34969
35071
  allMetadata.push(...data.metadata);
34970
35072
  }
34971
- await this.vector.upsert({
35073
+ if (this.isSelfEmbedding) await this.vector.upsert({
35074
+ indexName,
35075
+ documents: allDocuments,
35076
+ metadata: allMetadata
35077
+ });
35078
+ else await this.vector.upsert({
34972
35079
  indexName,
34973
35080
  vectors: allVectors,
34974
35081
  metadata: allMetadata
@@ -35457,4 +35564,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
35457
35564
  }
35458
35565
  });
35459
35566
 
35460
- //# sourceMappingURL=src-BlhP1hpS.cjs.map
35567
+ //# sourceMappingURL=src-Ch_8ufgu.cjs.map