Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<PackageVersion Include="Google.GenAI" Version="1.6.0" />
<PackageVersion Include="Mscc.GenerativeAI.Microsoft" Version="2.9.3" />
<!-- Microsoft.Azure.* -->
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.54.0" />
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.61.0" />
<!-- Newtonsoft.Json -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<!-- System.* -->
Expand Down Expand Up @@ -104,6 +104,7 @@
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.VectorData.Abstractions" Version="10.7.0" />
<!-- Vector Stores -->
<PackageVersion Include="CommunityToolkit.VectorData.CosmosNoSql" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.InMemory" Version="1.0.0" />
<PackageVersion Include="CommunityToolkit.VectorData.Qdrant" Version="1.0.0" />
<!-- Agent SDKs -->
Expand Down
1 change: 1 addition & 0 deletions dotnet/agent-framework-dotnet.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@
<Project Path="samples/02-agents/AgentWithMemory/AgentWithMemory_Step05_BoundedChatHistory/AgentWithMemory_Step05_BoundedChatHistory.csproj" />
<Project Path="samples/02-agents/AgentWithMemory/AgentWithMemory_Step06_MemoryUsingAgentMemory/AgentWithMemory_Step06_MemoryUsingAgentMemory.csproj" />
<Project Path="samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/AgentWithMemory_Step07_FileMemoryProvider.csproj" />
<Project Path="samples/02-agents/AgentWithMemory/AgentWithMemory_Step08_MemoryUsingCosmosNoSql/AgentWithMemory_Step08_MemoryUsingCosmosNoSql.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AgentProviders/openai/">
<File Path="samples/02-agents/AgentProviders/openai/README.md" />
Expand Down
20 changes: 20 additions & 0 deletions dotnet/eng/verify-samples/AgentsSamples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,26 @@ internal static class AgentsSamples
],
},

new SampleDefinition
{
Name = "AgentWithMemory_Step08_MemoryUsingCosmosNoSql",
ProjectPath = "samples/02-agents/AgentWithMemory/AgentWithMemory_Step08_MemoryUsingCosmosNoSql",
RequiredEnvironmentVariables = ["FOUNDRY_PROJECT_ENDPOINT", "COSMOS_ENDPOINT"],
OptionalEnvironmentVariables = ["FOUNDRY_MODEL", "FOUNDRY_EMBEDDING_MODEL", "COSMOS_DATABASE_NAME"],
MustContain =
[
"First session:",
"Second session (recalling prior chat history from Cosmos DB):",
],
ExpectedOutputDescription =
[
"The output should contain two joke responses.",
"The first joke should be about a pirate (as explicitly requested).",
"The second joke should also be pirate-themed or similar to what the user likes, since chat history from the first session should be recalled from Cosmos DB.",
"The output should not contain error messages or stack traces.",
],
},

// ── AgentWithRAG ────────────────────────────────────────────────────

new SampleDefinition
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>

<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Identity" />
<PackageReference Include="CommunityToolkit.VectorData.CosmosNoSql" />
<PackageReference Include="Microsoft.Azure.Cosmos" />
</ItemGroup>
Comment thread
nos-redacted marked this conversation as resolved.

<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) Microsoft. All rights reserved.

// This sample shows how to persist chat history in Azure Cosmos DB for NoSQL using the ChatHistoryMemoryProvider.
// The agent can then use chat history from prior conversations to inform responses in new conversations.

using System.Text.Json;
using Azure.AI.Projects;
using Azure.Identity;
using CommunityToolkit.VectorData.CosmosNoSql;
using Microsoft.Agents.AI;
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.VectorData;

var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
var embeddingDeploymentName = Environment.GetEnvironmentVariable("FOUNDRY_EMBEDDING_MODEL") ?? "text-embedding-3-large";
var embeddingDimensions = 3072;
if (Environment.GetEnvironmentVariable("FOUNDRY_EMBEDDING_DIMENSIONS") is string embeddingDimensionsValue &&
(!int.TryParse(embeddingDimensionsValue, out embeddingDimensions) || embeddingDimensions <= 0))
{
throw new InvalidOperationException("FOUNDRY_EMBEDDING_DIMENSIONS must be a positive integer.");
}
var cosmosEndpoint = Environment.GetEnvironmentVariable("COSMOS_ENDPOINT") ?? throw new InvalidOperationException("COSMOS_ENDPOINT is not set.");
Comment thread
nos-redacted marked this conversation as resolved.
var cosmosDatabaseName = Environment.GetEnvironmentVariable("COSMOS_DATABASE_NAME") ?? "agent-memory";

// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
DefaultAzureCredential credential = new();
AIProjectClient aiProjectClient = new(new Uri(endpoint), credential);

using CosmosClient cosmosClient = new(
cosmosEndpoint,
credential,
new CosmosClientOptions
{
UseSystemTextJsonSerializerWithOptions = JsonSerializerOptions.Default,
});

DatabaseResponse databaseResponse = await cosmosClient.CreateDatabaseIfNotExistsAsync(cosmosDatabaseName);

VectorStore vectorStore = new CosmosNoSqlVectorStore(
databaseResponse.Database,
new CosmosNoSqlVectorStoreOptions
{
JsonSerializerOptions = JsonSerializerOptions.Default,
EmbeddingGenerator = aiProjectClient
.GetProjectOpenAIClient()
.GetEmbeddingClient(embeddingDeploymentName)
.AsIEmbeddingGenerator(),
});

var userId = $"sample-{Guid.NewGuid():N}";

// Create the agent and add the ChatHistoryMemoryProvider to store chat messages in Cosmos DB.
AIAgent agent = aiProjectClient
.AsAIAgent(new ChatClientAgentOptions
{
ChatOptions = new() { ModelId = deploymentName, Instructions = "You are good at telling jokes." },
Name = "Joker",
AIContextProviders = [new ChatHistoryMemoryProvider(
vectorStore,
collectionName: "chathistory",
vectorDimensions: embeddingDimensions,
// Callback to configure the initial state of the ChatHistoryMemoryProvider.
// The ChatHistoryMemoryProvider stores its state in the AgentSession and this callback
// will be called whenever the ChatHistoryMemoryProvider cannot find existing state in the session,
// typically the first time it is used with a new session.
_ => new ChatHistoryMemoryProvider.State(
// Configure the scope values under which chat messages will be stored.
// In this case, we are using a per-run user ID and a unique session ID for each new session.
storageScope: new() { UserId = userId, SessionId = Guid.NewGuid().ToString("N") },
// Configure the scope which would be used to search for relevant prior messages.
// In this case, we are searching for any messages for the user across all sessions.
searchScope: new() { UserId = userId }))]
});

// Start a new session for the agent conversation.
AgentSession session = await agent.CreateSessionAsync();

// Run the agent with the session that stores conversation history in Cosmos DB.
Console.WriteLine("First session:");
Console.WriteLine(await agent.RunAsync("I like jokes about Pirates. Tell me a joke about a pirate.", session));

// Start a second session. Since we configured the search scope to be across all sessions for the user,
// the agent should remember that the user likes pirate jokes.
AgentSession session2 = await agent.CreateSessionAsync();

// Run the agent with the second session.
Console.WriteLine("Second session (recalling prior chat history from Cosmos DB):");
Console.WriteLine(await agent.RunAsync("Tell me a joke that I might like.", session2));
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Agent with Memory Using Azure Cosmos DB for NoSQL

This sample uses `ChatHistoryMemoryProvider` with `CosmosNoSqlVectorStore` to persist chat history in Azure Cosmos DB for NoSQL and recall relevant messages in a new agent session.

## Features Demonstrated

- Authenticating to Microsoft Foundry and Azure Cosmos DB with `DefaultAzureCredential`
- Storing chat messages in an Azure Cosmos DB vector store
- Creating the configured database and chat-history container when they do not exist
- Recalling relevant chat history across agent sessions

## Prerequisites

1. [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)
2. A Microsoft Foundry project with:
- A chat model deployment (the default is `gpt-5.4-mini`)
- A `text-embedding-3-large` deployment with 3,072 dimensions
3. An Azure Cosmos DB for NoSQL account with [vector search enabled](https://learn.microsoft.com/azure/cosmos-db/nosql/vector-search)
4. An Azure identity that can create the configured database and container and read and write items
5. Azure CLI authentication (`az login`)

## Configuration

Set the following environment variables:

| Variable | Description | Default |
|---|---|---|
| `FOUNDRY_PROJECT_ENDPOINT` | Microsoft Foundry project endpoint | *(required)* |
| `COSMOS_ENDPOINT` | Azure Cosmos DB account endpoint | *(required)* |
| `FOUNDRY_MODEL` | Chat model deployment name | `gpt-5.4-mini` |
| `FOUNDRY_EMBEDDING_MODEL` | Embedding model deployment name | `text-embedding-3-large` |
| `FOUNDRY_EMBEDDING_DIMENSIONS` | Number of dimensions produced by the embedding deployment | `3072` |
| `COSMOS_DATABASE_NAME` | Database used to store agent memory | `agent-memory` |

## Run the Sample

```bash
dotnet run
```

The first session stores the user's preference for pirate jokes. The second session uses a different `AgentSession` but the same per-run user search scope, allowing the agent to retrieve that preference from Azure Cosmos DB without recalling data from earlier sample runs.
1 change: 1 addition & 0 deletions dotnet/samples/02-agents/AgentWithMemory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ These samples show how to create an agent with the Agent Framework that uses Mem
|[Bounded Chat History with Overflow](./AgentWithMemory_Step05_BoundedChatHistory/)|This sample demonstrates how to create a bounded chat history provider that overflows older messages to a vector store and recalls them as memories.|
|[Memory Using AgentMemory](./AgentWithMemory_Step06_MemoryUsingAgentMemory/)|This sample demonstrates a retail shopping assistant built with [`AgentMemory`](https://www.nuget.org/packages/AgentMemory), an unofficial .NET port of the Neo4j Labs graph-memory provider, to learn customer preferences and recommend products via graph traversal.|
|[File Based Memory](./AgentWithMemory_Step07_FileMemoryProvider/)|This sample demonstrates how to use the `FileMemoryProvider` to give an agent tools for storing and recalling memories as files, and how to configure the folder that those memory files are written to.|
|[Memory with Azure Cosmos DB for NoSQL](./AgentWithMemory_Step08_MemoryUsingCosmosNoSql/)|This sample demonstrates how to persist and retrieve chat history across sessions with Azure Cosmos DB for NoSQL.|

> **See also**: [Memory Search with Foundry Agents](../AgentProviders/foundry/Agent_Step22_MemorySearch/) - demonstrates using the built-in Memory Search tool with Microsoft Foundry agents.

Loading