Progress.Memory (Core)

Updated on Nov 3, 2026

The Memory .NET SDK is split into three NuGet packages so you take only the dependencies you need:

PackageMain purposeWhen to use
Progress.MemoryCore client for add/recall/forget memory operations.You want direct programmatic control of memory calls.
Progress.Memory.Extensions.AIIntegration with Microsoft.Extensions.AI (IChatClient).You are building with IChatClient and want middleware or tool-based memory.
Progress.Memory.SemanticKernelIntegration with Semantic Kernel (IKernelBuilder / IChatCompletionService).You are using Semantic Kernel plugins, planners, or chat wrappers.

Before configuring the SDK, request early access and prepare the Agent Memory prerequisites.

Installation

Install the core Memory package:

bash
dotnet add package Progress.Memory

Configuration

Create a ProgressMemoryConfig record with the backend URL and SDK API key:

cs
using Progress.Memory;

var config = new ProgressMemoryConfig(
    BackendBaseUrl: "https://memory-api.observability.progress.com",
    SdkApiKey:      "pmem_d_...");

Environment Variables

If you register via IConfiguration, the SDK reads:

VariablePurpose
PROGRESS_MEMORY_BACKEND_URLBase URL of the memory-api service
PROGRESS_MEMORY_SDK_API_KEYSDK API key (for example, pmem_d_*)

Dependency Injection

With explicit config:

cs
using Progress.Memory;
using Progress.Memory.Extensions;

services.AddProgressMemory(new ProgressMemoryConfig(
    BackendBaseUrl: "https://memory-api.observability.progress.com",
    SdkApiKey:      "pmem_d_..."));

From IConfiguration / environment variables:

cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Progress.Memory;
using Progress.Memory.Extensions;

var builder = Host.CreateApplicationBuilder(args);

// Set PROGRESS_MEMORY_BACKEND_URL and PROGRESS_MEMORY_SDK_API_KEY in your environment
builder.Services.AddProgressMemory(builder.Configuration);

var host = builder.Build();
var memory = host.Services.GetRequiredService<IProgressMemoryClient>();

API Reference

IProgressMemoryClient exposes three methods.

AddMemoryAsync

Extracts atomic memories from one or more conversation messages and saves them to the knowledge base.

cs
Task<AddMemoryResult> AddMemoryAsync(AddMemoryRequest request, CancellationToken ct = default);

AddMemoryRequest

PropertyTypePurpose
MessagesList<MemoryMessage>?Ordered conversation messages for memory extraction. At least one "user" message with text is required. Preferred over Text.
TextstringSingle-text input. When Messages is not set, the SDK sends this as a single "user" message.
ConversationIdstring?Optional conversation identifier to continue an existing thread. If omitted, the backend creates one.
UserIdstringIdentifies the user whose memory this belongs to.
AgentIdstringIdentifies the agent (scopes memory per agent per user).
MetadataDictionary<string, string>?Optional key/value pairs forwarded to the backend.

MemoryMessage

PropertyTypePurpose
TextstringMessage text.
TypestringMessage role: "user" or "assistant".

AddMemoryResult

PropertyTypePurpose
OriginalTextIdstringRecord ID for the submitted text.
MemoriesCountintNumber of atomic memories extracted and stored.
ConversationIdstring?Conversation identifier returned by the backend for threading follow-up turns.
MemoriesIReadOnlyList<StoredMemory>The individual extracted memories.

StoredMemory

PropertyTypePurpose
MemoryIdstringUnique identifier for the memory. Pass to ForgetMemoryAsync to delete it.
TextstringThe extracted atomic memory text.
CategorystringCategory assigned by the extraction pipeline (for example, FACT, PREFERENCE, or MEMORY).

RecallMemoryAsync

Performs a search over stored memories for a given user/agent pair.

cs
Task<IReadOnlyList<RecallResult>> RecallMemoryAsync(RecallMemoryRequest request, CancellationToken ct = default);

RecallMemoryRequest

PropertyTypePurpose
QuerystringNatural-language query describing what to look for.
UserIdstringScope results to this user.
AgentIdstringScope results to this agent.
topKintMaximum number of results to return (default 10).
IncludeOutdatedboolOptional. Set to true to return both active and outdated memories. If omitted, defaults to false (active memories only).

RecallResult

PropertyTypePurpose
MemoryIdstringUnique identifier for the memory. Pass to ForgetMemoryAsync to delete it.
TextstringThe stored atomic memory text.
ScoredoubleSemantic similarity score (0–1). Higher is more relevant.
Categorystring?Category label assigned during extraction.
OriginalTextIdstring?ID of the original text record this memory was derived from.
Statusstring?Memory status: active or outdated.
OutdatedByIdstring?ID of the replacement memory when this memory is outdated.
MetadataDictionary<string, object>Additional metadata from the backend resource.

ForgetMemoryAsync

Deletes a specific extracted memory by its ID. The original conversation text is not affected. userId must match the owner of the memory — passing a different user ID returns a 403 error.

cs
Task ForgetMemoryAsync(string memoryId, string userId, CancellationToken ct = default);

ForgetMemoryAsync is idempotent — calling it for a memory that no longer exists returns successfully.

Standalone Usage Example

The following example creates a client, stores a conversation exchange, recalls relevant memories, and deletes a recalled memory:

cs
using Progress.Memory;
using Progress.Memory.Models;

var config = new ProgressMemoryConfig(
    BackendBaseUrl: "https://memory-api.observability.progress.com",
    SdkApiKey:      "pmem_d_...");

var memory = ProgressMemoryClient.Create(config);

// Save a conversation exchange for memory extraction
var result = await memory.AddMemoryAsync(new AddMemoryRequest
{
    UserId  = "user-123",
    AgentId = "support-bot",
    Messages =
    [
        new MemoryMessage { Type = "user",      Text = "I prefer dark mode and metric units." },
        new MemoryMessage { Type = "assistant", Text = "Noted — I'll remember your display and unit preferences." },
    ],
});

Console.WriteLine($"Extracted {result.MemoriesCount} memory(s):");
foreach (var item in result.Memories)
  Console.WriteLine($"  [{item.Category}] {item.Text}  (id: {item.MemoryId})");

// Recall relevant memories before answering the next question
var memories = await memory.RecallMemoryAsync(new RecallMemoryRequest
{
    Query   = "display preferences",
    UserId  = "user-123",
    AgentId = "support-bot",
    topK       = 5,
    IncludeOutdated = false, // Optional; omit for active-only retrieval, or set to true to include outdated memories.
});

foreach (var m in memories)
    Console.WriteLine($"[{m.Score:F2}] [{m.Category}] {m.Text}");

// Forget a specific memory
if (memories.Count > 0)
    await memory.ForgetMemoryAsync(memories[0].MemoryId, "user-123");

See Also