DEV Community

Aftab Bashir
Aftab Bashir

Posted on

Why AI assistants forget everything , and how I fixed it in .NET

I was building an AI chat assistant in Blazor. It worked fine. But every new conversation started from scratch. The user would say "I'm a software engineer who loves C#" and the assistant would respond warmly , then forget it completely the next time they opened the app.

That's not a memory problem. That's just a chat window.

I wanted something better. Something that actually remembers the user across sessions, extracts facts from conversations, and uses them to give better responses over time. I looked around for a .NET library that did this. Nothing existed. So I built it.

What I built

BlazorMemory is an open-source AI memory layer for .NET. It sits between your chat logic and your LLM and does three things:

  1. Extracts facts from conversations using an LLM
  2. Stores them as vector embeddings
  3. Injects relevant memories into future prompts

The flow looks like this:

User message → extract facts → embed → store
                                          ↓
Next message → embed query → vector search → inject memories → LLM
Enter fullscreen mode Exit fullscreen mode

It works in Blazor WASM with zero backend , everything stays in the browser using IndexedDB. It also works server-side with EF Core if you need SQL storage.

The hard part wasn't storage

Storing memories is easy. The hard part is making them useful.

Early versions just stored everything. After a few conversations, the memory panel was full of duplicates. "User likes C#." "User works with C#." "User is a C# developer." Three separate entries saying the same thing.

I solved this with a two-step pipeline:

Step 1 , Extract: The LLM reads the conversation and pulls out discrete facts. One sentence per fact, starting with "User". If the conversation already produced "User is a C# engineer", it won't also extract "User loves C#" , the preference is already implied.

Step 2 , Consolidate: For each new fact, the system finds similar existing memories using vector search. Then it asks the LLM: should I ADD this, UPDATE an existing memory, DELETE a contradiction, or do NOTHING?

The consolidation prompt has a clear priority order: NONE > UPDATE > DELETE > ADD. It prefers doing less. That keeps the memory clean.

Getting started

dotnet add package BlazorMemory
dotnet add package BlazorMemory.Storage.IndexedDb
dotnet add package BlazorMemory.Embeddings.OpenAi
dotnet add package BlazorMemory.Extractor.OpenAi
Enter fullscreen mode Exit fullscreen mode

Wire it up in Program.cs:

builder.Services
    .AddBlazorMemory()
    .UseIndexedDbStorage()
    .UseOpenAiEmbeddings(apiKey)
    .UseOpenAiExtractor(apiKey);
Enter fullscreen mode Exit fullscreen mode

Use it in your chat service:

public class ChatService(IMemoryService memory)
{
    public async Task<string> ChatAsync(string message, string userId)
    {
        // Pull relevant memories
        var memories = await memory.QueryAsync(message, userId,
            new QueryOptions { Limit = 5, Threshold = 0.65f });

        // Build system prompt
        var context = string.Join("\n", memories.Select(m => $"- {m.Content}"));
        var prompt = $"You are a helpful assistant.\n\nWhat you know:\n{context}";

        // Call your LLM
        var reply = await CallLlm(prompt, message);

        // Extract and store new facts
        await memory.ExtractAsync($"User: {message}\nAssistant: {reply}", userId);

        return reply;
    }
}
Enter fullscreen mode Exit fullscreen mode

That's it. The assistant now remembers things.

Namespaces

v0.2.0 added namespace support. You can scope memories by topic:

// Store work memories separately from personal ones
await memory.ExtractAsync(conversation, userId, namespace: "work");

// Query only work memories
var results = await memory.QueryAsync(query, userId, new QueryOptions
{
    Namespace = "work"
});
Enter fullscreen mode Exit fullscreen mode

Useful if you're building an assistant that handles multiple contexts.

What's available

Seven NuGet packages, all at v0.2.0:

Package What it does
BlazorMemory Core library
BlazorMemory.Storage.IndexedDb Browser storage, zero backend
BlazorMemory.Storage.InMemory For testing
BlazorMemory.Storage.EfCore SQL Server, PostgreSQL, SQLite
BlazorMemory.Embeddings.OpenAi OpenAI embeddings
BlazorMemory.Extractor.OpenAi OpenAI fact extraction
BlazorMemory.Extractor.Anthropic Claude fact extraction

The repo is at github.com/aftabkh4n/BlazorMemory. Issues and PRs welcome.

If you're building AI assistants in .NET and want them to actually remember users, give it a try.

Top comments (0)