You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Memory Indexer takes a Microsoft.Extensions.AI embedding generator directly.AddMemoryIndexer(...) .WithEmbeddingGenerator(queriesServiceKey) embeds with the container's IEmbeddingGenerator<string, Embedding<float>>
(OpenAI, Azure OpenAI, Ollama, LMSupply, IronHive) — no IEmbeddingService to write; it replaces any embedding service
registered before it. A keyed generator embeds recall queries (an asymmetric model's query side); without one the
documents generator does. EmbeddingGeneratorEmbeddingService is the same thing without DI. The dimension is the
generator's (EmbeddingGeneratorMetadata.DefaultModelDimensions) or the one passed; neither known, or the two
disagreeing, throws; batches are one generator call and a short result or a vector of another size throws. MemoryIndexer now references Microsoft.Extensions.AI.Abstractions (it was already in the dependency closure).
VectorStoreMemoryStore stores memories in any Microsoft.Extensions.VectorData database — Qdrant, PostgreSQL
(pgvector), Azure AI Search and the other connectors — through the connector's VectorStore, with the embedding
dimension set in VectorStoreMemoryStoreOptions.Dimensions (also CollectionName, DistanceFunction, PageSize).
Rows are MemoryRecords (enums by name, times as UTC ticks, metadata as JSON plus key=value entries); every filter runs
in the database; search scores are the cosine similarity of the stored vectors, as in the other stores. Counts, the user
list and bulk deletes walk the matching records page by page. The collection is created on first use (a read before
any write used to fail on Qdrant with «collection not found»). A memory without an embedding is stored with a
placeholder vector and MemoryRecord.HasEmbedding = false, which every search filters out — Qdrant refuses a point
without a vector, and the library stores some memories (imports, summaries, backups) before or without embedding them.
The store contract runs on a real Qdrant (CommunityToolkit.VectorData.Qdrant 1.0.1, Testcontainers).
MemoryIndexer:Storage:Type = VectorStore and WithVectorStore(collectionName) register that store on the VectorStore the application registered (collection MemoryIndexer:Storage:CollectionName, default memories;
dimension as for SQLite). Without one, resolving the store fails with a message that names it.
Dependencies
Microsoft.Extensions.VectorData.Abstractions 10.6.0 → 10.11.0 (the maintained connectors require 10.8.2 or later).
Documentation
docs/QUALITY-BENCHMARKS.md names the public benchmark for recall quality: LongMemEval, retrieval only
(session- and turn-level Recall@k / NDCG@10, by question type), and what no public benchmark isolates.
Changed
Breaking — one vector size: the built-in stores take it from the embedding service. The SQLite and
VectorData stores used MemoryIndexer:Storage:VectorDimensions (default 768, or Embedding:Dimensions when 0) while the
embedder reported its own IEmbeddingService.Dimensions — two settings for one number, and a third with a Microsoft.Extensions.AI generator; a mismatch failed at the first write. The stores now read IEmbeddingService.Dimensions, so a store cannot be resolved without an embedding service. StorageOptions.VectorDimensions
is removed, and a configuration that still sets MemoryIndexer:Storage:VectorDimensions stops the host at startup
naming where the size comes from. Embedding:Dimensions stays the size of the built-in embedders (Mock, the MCP
server's local model). Migration: delete Storage:VectorDimensions; with your own embedding service, its Dimensions
is the size.
MemoryUnit no longer carries Microsoft.Extensions.VectorData attributes ([VectorStoreKey], [VectorStoreData], [VectorStoreVector(1024)]). Nothing read them, and the vector attribute fixed a 1024 dimension in code; the schema is now MemoryRecord.CreateDefinition(dimensions, …). Code that used MemoryUnit as a VectorData record type maps through MemoryRecord.From / ToMemory instead.
Breaking — one setting per concept for the Short tier capacity and the Long → Archive gate. The Short tier's
session cache (IShortTermMemory) had its own capacity (MemoryIndexer:VCM:WorkingMemory:Capacity, default 7) next to the
tier limit the store enforces (MemoryIndexer:WorkingMemory:Capacity, default 9), and the Long → Archive promoter read
its confidence/confirmation gate from MemoryIndexer:VCM:SemanticStore while the tier manager read MemoryIndexer:ArchivePromotion — setting one left the other path on its default. Now WorkingMemory:Capacity sizes
both (the cache follows the tier: 9 by default, was 7) and ArchivePromotion is the only gate. A configuration that
still sets one of the three old keys stops the host at startup naming the new key. Migration: move those keys; MemoryIndexer.Services.WorkingMemoryOptions is now WorkingMemoryCacheOptions (no Capacity); SemanticStoreOptions loses MinConfirmationCount/MinConfidenceThreshold; ShortTermMemoryService and LongTermPromoterService take IOptions<MemoryIndexerOptions> for the values that moved.