From 36532e929eed477bb89a974ed0f68137e75437a4 Mon Sep 17 00:00:00 2001 From: westey <164392973+westey-m@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:31:29 +0000 Subject: [PATCH] .NET: Add a Mem0 usage sample (#1779) * Add a Mem0 usage sample * Change charset * Add variable types --- dotnet/agent-framework-dotnet.slnx | 1 + .../Agent_Step19_Mem0Provider.csproj | 22 +++++++ .../Agent_Step19_Mem0Provider/Program.cs | 64 +++++++++++++++++++ .../samples/GettingStarted/Agents/README.md | 1 + .../Microsoft.Agents.AI.Mem0.csproj | 4 +- 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Agent_Step19_Mem0Provider.csproj create mode 100644 dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Program.cs diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx index cf1e367293..ea8415d2b1 100644 --- a/dotnet/agent-framework-dotnet.slnx +++ b/dotnet/agent-framework-dotnet.slnx @@ -59,6 +59,7 @@ + diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Agent_Step19_Mem0Provider.csproj b/dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Agent_Step19_Mem0Provider.csproj new file mode 100644 index 0000000000..9d7aa41a99 --- /dev/null +++ b/dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Agent_Step19_Mem0Provider.csproj @@ -0,0 +1,22 @@ + + + + Exe + net9.0 + + enable + enable + + + + + + + + + + + + + + diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Program.cs b/dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Program.cs new file mode 100644 index 0000000000..21aa9d3e1d --- /dev/null +++ b/dotnet/samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Program.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft. All rights reserved. + +// This sample shows how to use the Mem0Provider to persist and recall memories for an agent. +// The sample stores conversation messages in a Mem0 service and retrieves relevant memories +// for subsequent invocations, even across new threads. + +using System.Net.Http.Headers; +using System.Text.Json; +using Azure.AI.OpenAI; +using Azure.Identity; +using Microsoft.Agents.AI; +using Microsoft.Agents.AI.Mem0; +using Microsoft.Extensions.AI; +using OpenAI; + +var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; + +var mem0ServiceUri = Environment.GetEnvironmentVariable("MEM0_ENDPOINT") ?? throw new InvalidOperationException("MEM0_ENDPOINT is not set."); +var mem0ApiKey = Environment.GetEnvironmentVariable("MEM0_APIKEY") ?? throw new InvalidOperationException("MEM0_APIKEY is not set."); + +// Create an HttpClient for Mem0 with the required base address and authentication. +using HttpClient mem0HttpClient = new(); +mem0HttpClient.BaseAddress = new Uri(mem0ServiceUri); +mem0HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", mem0ApiKey); + +AIAgent agent = new AzureOpenAIClient( + new Uri(endpoint), + new AzureCliCredential()) + .GetChatClient(deploymentName) + .CreateAIAgent(new ChatClientAgentOptions() + { + Instructions = "You are a friendly travel assistant. Use known memories about the user when responding, and do not invent details.", + AIContextProviderFactory = ctx => ctx.SerializedState.ValueKind is not JsonValueKind.Null or JsonValueKind.Undefined + // If each thread should have its own Mem0 scope, you can create a new id per thread here: + // ? new Mem0Provider(mem0HttpClient, new Mem0ProviderOptions() { ThreadId = Guid.NewGuid().ToString() }) + // In this case we are storing memories scoped by application and user instead so that memories are retained across threads. + ? new Mem0Provider(mem0HttpClient, new Mem0ProviderOptions() { ApplicationId = "getting-started-agents", UserId = "sample-user" }) + // For cases where we are restoring from serialized state: + : new Mem0Provider(mem0HttpClient, ctx.SerializedState, ctx.JsonSerializerOptions) + }); + +AgentThread thread = agent.GetNewThread(); + +// Clear any existing memories for this scope to demonstrate fresh behavior. +Mem0Provider mem0Provider = thread.GetService()!; +await mem0Provider.ClearStoredMemoriesAsync(); + +Console.WriteLine(await agent.RunAsync("Hi there! My name is Taylor and I'm planning a hiking trip to Patagonia in November.", thread)); +Console.WriteLine(await agent.RunAsync("I'm travelling with my sister and we love finding scenic viewpoints.", thread)); + +Console.WriteLine("\nWaiting briefly for Mem0 to index the new memories...\n"); +await Task.Delay(TimeSpan.FromSeconds(2)); + +Console.WriteLine(await agent.RunAsync("What do you already know about my upcoming trip?", thread)); + +Console.WriteLine("\n>> Serialize and deserialize the thread to demonstrate persisted state\n"); +JsonElement serializedThread = thread.Serialize(); +AgentThread restoredThread = agent.DeserializeThread(serializedThread); +Console.WriteLine(await agent.RunAsync("Can you recap the personal details you remember?", restoredThread)); + +Console.WriteLine("\n>> Start a new thread that shares the same Mem0 scope\n"); +AgentThread newThread = agent.GetNewThread(); +Console.WriteLine(await agent.RunAsync("Summarize what you already know about me.", newThread)); diff --git a/dotnet/samples/GettingStarted/Agents/README.md b/dotnet/samples/GettingStarted/Agents/README.md index 09ebf5e0db..2b8f7550c9 100644 --- a/dotnet/samples/GettingStarted/Agents/README.md +++ b/dotnet/samples/GettingStarted/Agents/README.md @@ -44,6 +44,7 @@ Before you begin, ensure you have the following prerequisites: |[Reducing chat history size](./Agent_Step16_ChatReduction/)|This sample demonstrates how to reduce the chat history to constrain its size, where chat history is maintained locally| |[Background responses](./Agent_Step17_BackgroundResponses/)|This sample demonstrates how to use background responses for long-running operations with polling and resumption support| |[Adding RAG with text search](./Agent_Step18_TextSearchRag/)|This sample demonstrates how to enrich agent responses with retrieval augmented generation using the text search provider| +|[Using Mem0-backed memory](./Agent_Step19_Mem0Provider/)|This sample demonstrates how to use the Mem0Provider to persist and recall memories across conversations| ## Running the samples from the console diff --git a/dotnet/src/Microsoft.Agents.AI.Mem0/Microsoft.Agents.AI.Mem0.csproj b/dotnet/src/Microsoft.Agents.AI.Mem0/Microsoft.Agents.AI.Mem0.csproj index 4e06c30a11..5b571f020c 100644 --- a/dotnet/src/Microsoft.Agents.AI.Mem0/Microsoft.Agents.AI.Mem0.csproj +++ b/dotnet/src/Microsoft.Agents.AI.Mem0/Microsoft.Agents.AI.Mem0.csproj @@ -5,7 +5,6 @@ $(ProjectsDebugTargetFrameworks) preview - false @@ -14,6 +13,9 @@ + + false +