diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx index adc941d582..7cb13b1f66 100644 --- a/dotnet/agent-framework-dotnet.slnx +++ b/dotnet/agent-framework-dotnet.slnx @@ -181,6 +181,7 @@ + diff --git a/dotnet/samples/GettingStarted/AgentWithMemory/README.md b/dotnet/samples/GettingStarted/AgentWithMemory/README.md index 6e36ba0511..4f35adcd09 100644 --- a/dotnet/samples/GettingStarted/AgentWithMemory/README.md +++ b/dotnet/samples/GettingStarted/AgentWithMemory/README.md @@ -8,3 +8,5 @@ These samples show how to create an agent with the Agent Framework that uses Mem |[Memory with MemoryStore](./AgentWithMemory_Step02_MemoryUsingMem0/)|This sample demonstrates how to create and run an agent that uses the Mem0 service to extract and retrieve individual memories.| |[Custom Memory Implementation](./AgentWithMemory_Step03_CustomMemory/)|This sample demonstrates how to create a custom memory component and attach it to an agent.| |[Memory with Azure AI Foundry](./AgentWithMemory_Step04_MemoryUsingFoundry/)|This sample demonstrates how to create and run an agent that uses Azure AI Foundry's managed memory service to extract and retrieve individual memories.| + +> **See also**: [Memory Search with Foundry Agents](../FoundryAgents/FoundryAgents_Step26_MemorySearch/) - demonstrates using the built-in Memory Search tool with Azure Foundry Agents. diff --git a/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/FoundryAgents_Step26_MemorySearch.csproj b/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/FoundryAgents_Step26_MemorySearch.csproj new file mode 100644 index 0000000000..a1ccdfcd3a --- /dev/null +++ b/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/FoundryAgents_Step26_MemorySearch.csproj @@ -0,0 +1,23 @@ + + + + Exe + net10.0 + + enable + enable + $(NoWarn);CA1812 + + + + + + + + + + + + + + diff --git a/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/Program.cs b/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/Program.cs new file mode 100644 index 0000000000..10bb2efe8d --- /dev/null +++ b/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/Program.cs @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft. All rights reserved. + +// This sample demonstrates how to use the Memory Search Tool with AI Agents. +// The Memory Search Tool enables agents to recall information from previous conversations, +// supporting user profile persistence and chat summaries across sessions. + +using Azure.AI.Projects; +using Azure.AI.Projects.OpenAI; +using Azure.Identity; +using Microsoft.Agents.AI; +using OpenAI.Responses; + +string endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set."); +string deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; + +// Memory store configuration +// NOTE: Memory stores must be created beforehand via Azure Portal or Python SDK. +// The .NET SDK currently only supports using existing memory stores with agents. +string memoryStoreName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_MEMORY_STORE_NAME") ?? throw new InvalidOperationException("AZURE_FOUNDRY_MEMORY_STORE_NAME is not set."); + +const string AgentInstructions = """ + You are a helpful assistant that remembers past conversations. + Use the memory search tool to recall relevant information from previous interactions. + When a user shares personal details or preferences, remember them for future conversations. + """; + +const string AgentNameMEAI = "MemorySearchAgent-MEAI"; +const string AgentNameNative = "MemorySearchAgent-NATIVE"; + +// Scope identifies the user or context for memory isolation. +// Using a unique user identifier ensures memories are private to that user. +string userScope = $"user_{Environment.MachineName}"; + +// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents. +AIProjectClient aiProjectClient = new(new Uri(endpoint), new AzureCliCredential()); + +// Create the Memory Search tool configuration +MemorySearchTool memorySearchTool = new(memoryStoreName, userScope) +{ + // Optional: Configure how quickly new memories are indexed (in seconds) + UpdateDelay = 1, + + // Optional: Configure search behavior + SearchOptions = new MemorySearchToolOptions + { + // Additional search options can be configured here if needed + } +}; + +// Create agent using Option 1 (MEAI) or Option 2 (Native SDK) +AIAgent agent = await CreateAgentWithMEAI(); +// AIAgent agent = await CreateAgentWithNativeSDK(); + +Console.WriteLine("Agent created with Memory Search tool. Starting conversation...\n"); + +// Conversation 1: Share some personal information +Console.WriteLine("User: My name is Alice and I love programming in C#."); +AgentResponse response1 = await agent.RunAsync("My name is Alice and I love programming in C#."); +Console.WriteLine($"Agent: {response1.Messages.LastOrDefault()?.Text}\n"); + +// Allow time for memory to be indexed +await Task.Delay(2000); + +// Conversation 2: Test if the agent remembers +Console.WriteLine("User: What's my name and what programming language do I prefer?"); +AgentResponse response2 = await agent.RunAsync("What's my name and what programming language do I prefer?"); +Console.WriteLine($"Agent: {response2.Messages.LastOrDefault()?.Text}\n"); + +// Inspect memory search results if available in raw response items +// Note: Memory search tool call results appear as AgentResponseItem types +foreach (var message in response2.Messages) +{ + if (message.RawRepresentation is AgentResponseItem agentResponseItem && + agentResponseItem is MemorySearchToolCallResponseItem memorySearchResult) + { + Console.WriteLine($"Memory Search Status: {memorySearchResult.Status}"); + Console.WriteLine($"Memory Search Results Count: {memorySearchResult.Results.Count}"); + + foreach (var result in memorySearchResult.Results) + { + var memoryItem = result.MemoryItem; + Console.WriteLine($" - Memory ID: {memoryItem.MemoryId}"); + Console.WriteLine($" Scope: {memoryItem.Scope}"); + Console.WriteLine($" Content: {memoryItem.Content}"); + Console.WriteLine($" Updated: {memoryItem.UpdatedAt}"); + } + } +} + +// Cleanup: Delete the agent (memory store persists and should be cleaned up separately if needed) +Console.WriteLine("\nCleaning up agent..."); +await aiProjectClient.Agents.DeleteAgentAsync(agent.Name); +Console.WriteLine("Agent deleted successfully."); + +// NOTE: Memory stores are long-lived resources and are NOT deleted with the agent. +// To delete a memory store, use the Azure Portal or Python SDK: +// await project_client.memory_stores.delete(memory_store.name) + +// --- Agent Creation Options --- +#pragma warning disable CS8321 // Local function is declared but never used + +// Option 1 - Using MemorySearchTool wrapped as MEAI AITool +async Task CreateAgentWithMEAI() +{ + return await aiProjectClient.CreateAIAgentAsync( + model: deploymentName, + name: AgentNameMEAI, + instructions: AgentInstructions, + tools: [((ResponseTool)memorySearchTool).AsAITool()]); +} + +// Option 2 - Using PromptAgentDefinition with MemorySearchTool (Native SDK) +async Task CreateAgentWithNativeSDK() +{ + return await aiProjectClient.CreateAIAgentAsync( + name: AgentNameNative, + creationOptions: new AgentVersionCreationOptions( + new PromptAgentDefinition(model: deploymentName) + { + Instructions = AgentInstructions, + Tools = { memorySearchTool } + }) + ); +} diff --git a/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/README.md b/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/README.md new file mode 100644 index 0000000000..316509d32c --- /dev/null +++ b/dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step26_MemorySearch/README.md @@ -0,0 +1,92 @@ +# Using Memory Search with AI Agents + +This sample demonstrates how to use the Memory Search tool with AI agents. The Memory Search tool enables agents to recall information from previous conversations, supporting user profile persistence and chat summaries across sessions. + +## What this sample demonstrates + +- Creating an agent with Memory Search tool capabilities +- Configuring memory scope for user isolation +- Having conversations where the agent remembers past information +- Inspecting memory search results from agent responses +- Managing agent lifecycle (creation and deletion) + +## Prerequisites + +Before you begin, ensure you have the following prerequisites: + +- .NET 10 SDK or later +- Azure Foundry service endpoint and deployment configured +- Azure CLI installed and authenticated (for Azure credential authentication) +- **A pre-created Memory Store** (see below) + +**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively). + +### Creating a Memory Store + +Memory stores must be created before running this sample. The .NET SDK currently only supports **using** existing memory stores with agents. To create a memory store, use one of these methods: + +**Option 1: Azure Portal** +1. Navigate to your Azure AI Foundry project +2. Go to the Memory section +3. Create a new memory store with your desired settings + +**Option 2: Python SDK** +```python +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import MemoryStoreDefaultDefinition, MemoryStoreDefaultOptions +from azure.identity import DefaultAzureCredential + +project_client = AIProjectClient( + endpoint="https://your-endpoint.openai.azure.com/", + credential=DefaultAzureCredential() +) + +memory_store = await project_client.memory_stores.create( + name="my-memory-store", + description="Memory store for Agent Framework conversations", + definition=MemoryStoreDefaultDefinition( + chat_model=os.environ["AZURE_AI_CHAT_MODEL_DEPLOYMENT_NAME"], + embedding_model=os.environ["AZURE_AI_EMBEDDING_MODEL_DEPLOYMENT_NAME"], + options=MemoryStoreDefaultOptions( + user_profile_enabled=True, + chat_summary_enabled=True + ) + ) +) +``` + +## Environment Variables + +Set the following environment variables: + +```powershell +$env:AZURE_FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project" +$env:AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini +$env:AZURE_AI_MEMORY_STORE_NAME="your-memory-store-name" # Required - name of pre-created memory store +``` + +## Run the sample + +Navigate to the FoundryAgents sample directory and run: + +```powershell +cd dotnet/samples/GettingStarted/FoundryAgents +dotnet run --project .\FoundryAgents_Step26_MemorySearch +``` + +## Expected behavior + +The sample will: + +1. Create an agent with Memory Search tool configured +2. Send a message with personal information ("My name is Alice and I love programming in C#") +3. Wait for memory indexing +4. Ask the agent to recall the previously shared information +5. Display memory search results if available in the response +6. Clean up by deleting the agent (note: memory store persists) + +## Important notes + +- **Memory Store Lifecycle**: Memory stores are long-lived resources and are NOT deleted when the agent is deleted. Clean them up separately via Azure Portal or Python SDK. +- **Scope**: The `scope` parameter isolates memories per user/context. Use unique identifiers for different users. +- **Update Delay**: The `UpdateDelay` parameter controls how quickly new memories are indexed. diff --git a/dotnet/samples/GettingStarted/FoundryAgents/README.md b/dotnet/samples/GettingStarted/FoundryAgents/README.md index 20e9e8683f..706c6f10d7 100644 --- a/dotnet/samples/GettingStarted/FoundryAgents/README.md +++ b/dotnet/samples/GettingStarted/FoundryAgents/README.md @@ -58,6 +58,7 @@ Before you begin, ensure you have the following prerequisites: |[Using plugins](./FoundryAgents_Step13_Plugins/)|This sample demonstrates how to use plugins with a Foundry agent| |[Code interpreter](./FoundryAgents_Step14_CodeInterpreter/)|This sample demonstrates how to use the code interpreter tool with a Foundry agent| |[Computer use](./FoundryAgents_Step15_ComputerUse/)|This sample demonstrates how to use computer use capabilities with a Foundry agent| +|[Memory search](./FoundryAgents_Step26_MemorySearch/)|This sample demonstrates how to use memory search tool with a Foundry agent| |[File search](./FoundryAgents_Step18_FileSearch/)|This sample demonstrates how to use the file search tool with a Foundry agent| |[Local MCP](./FoundryAgents_Step27_LocalMCP/)|This sample demonstrates how to use a local MCP client with a Foundry agent|