Table of Contents

Hey everyone!

You can find all the C# code samples here: MicrosoftAgentFramework GitHub Repo

Many engineering teams spend significant effort building custom memory pipelines to give their AI agents long-term context. Before you start building complex database workflows from scratch, it’s worth exploring what Microsoft Foundry Memory provides out of the box (however still in preview).

In this post, we’ll do a architectural deep dive into the Microsoft Foundry Memory Store, inspect its low-level REST mechanics, and walk through a C# integration using FoundryMemoryProvider in the Microsoft Agent Framework.

Before reading this post, you may find these memory related posts interesting too:

Microsoft Foundry Memory Store Architecture

Architecture diagram of Microsoft Foundry Memory Store comparing long-term memory lifecycle and short-term memory context management for AI agents in MAF.

When designing stateful AI agents, the first distinction to understand is the difference between short-term context and long-term memory:

  • Short-Term Context: This is the active conversation thread passed directly in the LLM’s prompt window. Once a thread ends or a new session starts, this context vanishes unless explicitly persisted.
  • Long-Term Memory: This is dynamic, durable knowledge persisted across sessions, chats, and applications without relying on static system prompts or manual file uploads.

Portal Setup & Model Deployments

UI screenshot of creating a new Microsoft Foundry Memory Store, configuring chat completions and embedding models for long-term memory in MAF agents.

In the Azure AI portal (ai.azure.com), creating a Memory Store requires configuring two specific Azure OpenAI model deployments:

  1. Chat Completions Model: Used behind the scenes to extract facts and consolidate memory records.
  2. Embedding Model: Generates vector embeddings for vector similarity search during memory retrieval.

Preview Limitations: In its current preview state, memory stores carry regional constraints and quota limits (such as a maximum of 100 memory scopes per store). Additionally, model configurations defined at creation time cannot be changed later.

Supported Memory Types

Microsoft Foundry Memory Store advanced configuration UI enabling chat summary, procedural memory, user profile details, and default time-to-live settings for MAF agents.

Within a single store, you can track three distinct memory categories:

Memory TypePurposeExample
User ProfileStores persistent facts and user preferences.“User lives in Poland and prefers outdoor activities.”
Chat SummarySummarizes entire conversation threads for continuity.“Discussed itinerary options for a trip to Kraków.”
Procedural MemoryCaptures routines, preferences, and operational rules.“Do not search for flights; first calculate location boundary.”

You can also customize extraction guidelines via a User Profile Details Prompt (e.g., instructing a fitness coach agent to record dietary habits while ignoring unrelated personal facts) and configure a Time-to-Live (TTL) for temporary memories.

Connecting memory store to Foundry Agent in the Foundry portal

UI screenshot of an AI agent configured with Microsoft Foundry Memory Store preview in Microsoft Foundry playground for long-term agent memory.

When you want to connect memory to an agent defined directly in the Foundry portal (and not created using Microsoft Agent Framework) then it is as easy as linking a memory store to such an agent. Of course, you could link it programatically too. Behind the scenes it adds a tool that AI agent can call to add and search memories.

Under the Hood: Extraction, Consolidation, and Retrieval

Extraction phase pipeline in Microsoft Foundry Memory Store illustrating context lookup, LLM fact extraction, deduplication, embeddings, and entity linking for agent memory persistence.

Why does a managed memory store require both a Chat model and an Embedding model? Memory creation is not a raw log dump because it goes through a multi-stage execution pipeline.

  • Context Lookup: When an update request arrives, the store searches existing memories for relevant items.
  • Fact Extraction: The LLM processes raw user and assistant messages to extract structured facts rather than verbatim transcripts.
  • Consolidation (Deduplication): The LLM merges newly extracted facts with existing stored records to eliminate redundancy and update altered information.
  • Embedding Generation: The configured embedding model vectorizes the consolidated facts for future similarity searches.

Memory Scopes, REST APIs, and System Design Decisions

Scope Partitioning

Memory items are strictly isolated using a scope parameter. In production, this scope is typically tied to a user identifier extracted from an Entra ID JWT claim (oid), or a compound string combining user and application IDs:

// Scope pattern examples
string userScope = "usr_94a81b22";
string userAppScope = "app_sales|usr_94a81b22";

While Microsoft Foundry Memory Store currently uses a single string for scopes, libraries like Mem0 support richer key-value metadata filtering (user_id, app_id, session_id).

Asynchronous Execution & Eventual Consistency

Microsoft Foundry Memory REST API endpoints detailing supported operations including Search memories, Update memories, Delete memories by scope, and Get an update result.

The low-level REST API exposes key operations including SearchMemories and UpdateMemories. Memory processing operates asynchronously: update requests enter a queue and are processed in the background.

System Design Insight: Asynchronous memory extraction is the right trade-off. Synchronous extraction would add seconds of latency to every user interaction. Eventual consistency causes zero friction because active short-term chat history handles conversation flow during an ongoing session.

Integrating Foundry Memory with Microsoft Agent Framework in C#

In .NET, integration with the Microsoft Agent Framework is handled through the Microsoft.Agents.AI.Foundry package via FoundryMemoryProvider.

FoundryMemoryProvider inherits from AIContextProvider and implements two key lifecycle methods:

  • ProvideAIContextAsync: Invoked before the LLM call to retrieve relevant memories and hydrate the prompt context.
  • StoreAIContextAsync: Invoked after the LLM response to queue conversation turns for memory processing.

C# Implementation Example

namespace _09_Memory_FoundryMemory
{
    internal class FoundryMemoryProviderExample
    {
        private readonly AIAgent _mafAgent;

        public FoundryMemoryProviderExample()
        {
            // trimmed for brevity

            var foundryMemoryProvider = new FoundryMemoryProvider(
                new AIProjectClient(new Uri(Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_NAME")!), credential),
                Environment.GetEnvironmentVariable("FOUNDRY_MEMORY_STORE_NAME")!,
                stateInitializer: _ => new(new FoundryMemoryProviderScope("Michal-123")));

            _mafAgent = new ChatClientAgent(responesClient, new ChatClientAgentOptions()
            {
                Name = "Agent powered by Foundry Memory",
                ChatOptions = new ChatOptions
                {
                    Instructions = "You are a helpful assistant that always responds in English.",
                    Reasoning = new ReasoningOptions() { Effort = ReasoningEffort.Low, Output = ReasoningOutput.None }
                },
                AIContextProviders = [foundryMemoryProvider]
            });
        }

        public async Task RunAsync()
        {
            var foundryMemoryProvider = _mafAgent.GetService<FoundryMemoryProvider>();

            AgentSession firstSession = await _mafAgent.CreateSessionAsync();
            await foundryMemoryProvider!.EnsureStoredMemoriesDeletedAsync(firstSession);
            Console.WriteLine(await _mafAgent.RunAsync("I live in Poland", firstSession));

            Console.WriteLine("\n---------------\n");

            var start = Stopwatch.StartNew();

            await foundryMemoryProvider!.WhenUpdatesCompletedAsync(pollingInterval: TimeSpan.FromSeconds(1));

            start.Stop();
            Console.WriteLine($"Memory update completed in {start.Elapsed.TotalSeconds}s");

            Console.WriteLine("\n---------------\n");

            AgentSession secondSession = await _mafAgent.CreateSessionAsync();
            Console.WriteLine(await _mafAgent.RunAsync("What is the capital of the country I live in?", secondSession));
        }
    }
}

You can see that we have to pass AIProjectClient to the FoundryMemoryProvider and that is because that provider is just a wrapper around memory store related actions that AIProjectClient exposes.

This is what gets saved into Microsoft Foundry memory store and what is then retrieved by the second session, thanks to which the correct answer can be provided.

Microsoft Foundry Memory Store UI displaying a user_profile memory item filtered by scope in Microsoft Foundry.

Low-Level APIs: Controlling updateDelay, Lineage, and State Machines

When invoking AIProjectClient memory APIs directly, you gain fine-grained control over execution mechanics.

Key Parameters:

  • UpdateDelay: Instructs the background queue to wait before processing (e.g., 300 seconds). This prevents rapid, repetitive extraction calls while a user is actively typing multi-turn prompts.
  • PreviousUpdateId: Acts as a parent state pointer. Passing the previous update ID allows the backend to perform incremental diffs or supersede older pending updates.
var updateResult = await _foundryProjectClient.MemoryStores.UpdateMemoriesAsync(
    Environment.GetEnvironmentVariable("FOUNDRY_MEMORY_STORE_NAME")!,
    options: new MemoryUpdateOptions(_scope)
    {
        UpdateDelay = (int) updateDelay.TotalMilliseconds,
        PreviousUpdateId = previousUpdateId,
        Items = // user and assistant messages
    });

Processing statuses

When you run the 2nd example FoundryMemoryStoreApiExample you will see the following statuses (except for the Failed):

  • Queued: Request is submitted and waiting in the processing queue (respecting UpdateDelay).
  • InProgress: Fact extraction, deduplication, embedding generation, and entity linking are actively running.
  • Completed: Operation succeeded and the updated memory items are persisted in the store.
  • Superseded: Superseded by a newer operation (PreviousUpdateId).
  • Failed: Terminated due to an unrecoverable error (e.g., rate limits, bad payloads, or authorization failures).

Final Verdict

Microsoft Foundry Memory Store simplifies long-term context management for Azure-native workloads. While third-party options like Mem0 currently offer more granular metadata filtering and custom categories, Foundry’s managed approach, seamless C# AIContextProvider integration, and native agent service ecosystem make it a compelling out-of-the-box solution as it progresses toward General Availability.

Summary

Giving AI agents long-term memory doesn’t require building custom database pipelines and chunking logic. Microsoft Foundry Memory provides a managed, asynchronous extraction and consolidation pipeline out of the box. By integrating FoundryMemoryProvider into the Microsoft Agent Framework, your C# agents can automatically retain user profiles, chat summaries, and procedural routines across completely separate conversation sessions.

Categorized in:

Agents,