From 7506046f43455151eedc8a0d5d64fc94d6808eb3 Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Tue, 7 Oct 2025 09:17:31 +0100
Subject: [PATCH] .NET: Add sample to show ChatReducer usage (#1221)
* Add sample to show ChatReducer usage
* Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
dotnet/agent-framework-dotnet.slnx | 1 +
.../Agent_Step16_ChatReduction.csproj | 21 ++++++++
.../Agent_Step16_ChatReduction/Program.cs | 51 +++++++++++++++++++
.../samples/GettingStarted/Agents/README.md | 1 +
4 files changed, 74 insertions(+)
create mode 100644 dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Agent_Step16_ChatReduction.csproj
create mode 100644 dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Program.cs
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 920da0589e..04eb1f54b9 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -52,6 +52,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Agent_Step16_ChatReduction.csproj b/dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Agent_Step16_ChatReduction.csproj
new file mode 100644
index 0000000000..8298cfe6e8
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Agent_Step16_ChatReduction.csproj
@@ -0,0 +1,21 @@
+
+
+
+ Exe
+ net9.0
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Program.cs b/dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Program.cs
new file mode 100644
index 0000000000..365bdca371
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Program.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample shows how to use a chat history reducer to keep the context within model size limits.
+// Any implementation of Microsoft.Extensions.AI.IChatReducer can be used to customize how the chat history is reduced.
+// NOTE: this feature is only supported where the chat history is stored locally, such as with OpenAI Chat Completion.
+// Where the chat history is stored server side, such as with Azure Foundry Agents, the service must manage the chat history size.
+
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+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";
+
+const string JokerName = "Joker";
+const string JokerInstructions = "You are good at telling jokes.";
+
+// Construct the agent, and provide a factory to create an in-memory chat message store with a reducer that keeps only the last 2 non-system messages.
+AIAgent agent = new AzureOpenAIClient(
+ new Uri(endpoint),
+ new AzureCliCredential())
+ .GetChatClient(deploymentName)
+ .CreateAIAgent(new ChatClientAgentOptions
+ {
+ Name = JokerName,
+ Instructions = JokerInstructions,
+ ChatMessageStoreFactory = ctx => new InMemoryChatMessageStore(new MessageCountingChatReducer(2), ctx.SerializedState, ctx.JsonSerializerOptions)
+ });
+
+AgentThread thread = agent.GetNewThread();
+
+// Invoke the agent and output the text result.
+Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
+
+// Get the chat history to see how many messages are stored.
+IList? chatHistory = thread.GetService>();
+Console.WriteLine($"\nChat history has {chatHistory?.Count} messages.\n");
+
+// Invoke the agent a few more times.
+Console.WriteLine(await agent.RunAsync("Tell me a joke about a robot.", thread));
+Console.WriteLine($"\nChat history has {chatHistory?.Count} messages.\n");
+Console.WriteLine(await agent.RunAsync("Tell me a joke about a lemur.", thread));
+Console.WriteLine($"\nChat history has {chatHistory?.Count} messages.\n");
+
+// At this point, the chat history has exceeded the limit and the original message will not exist anymore,
+// so asking a follow up question about it will not work as expected.
+Console.WriteLine(await agent.RunAsync("Tell me the joke about the pirate again, but add emojis and use the voice of a parrot.", thread));
+
+Console.WriteLine($"\nChat history has {chatHistory?.Count} messages.\n");
diff --git a/dotnet/samples/GettingStarted/Agents/README.md b/dotnet/samples/GettingStarted/Agents/README.md
index 1078dafbfd..31290f9637 100644
--- a/dotnet/samples/GettingStarted/Agents/README.md
+++ b/dotnet/samples/GettingStarted/Agents/README.md
@@ -41,6 +41,7 @@ Before you begin, ensure you have the following prerequisites:
|[Using memory with an agent](./Agent_Step13_Memory/)|This sample demonstrates how to create a simple memory component and use it with an agent|
|[Using middleware with an agent](./Agent_Step14_Middleware/)|This sample demonstrates how to use middleware with an agent|
|[Using plugins with an agent](./Agent_Step15_Plugins/)|This sample demonstrates how to use plugins with an agent|
+|[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|
## Running the samples from the console