Skip to content

Commit d886334

Browse files
authored
Add ChatHistoryMemoryProvider doc (#963)
* Add ChatHistoryMemoryProvider doc * Fix link
1 parent cfcd7c7 commit d886334

5 files changed

Lines changed: 208 additions & 5 deletions

File tree

agent-framework/TOC.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ items:
180180
href: integrations/m365.md
181181
- name: Neo4j GraphRAG Provider
182182
href: integrations/neo4j-graphrag.md
183+
- name: Chat History Memory Provider
184+
href: integrations/chat-history-memory-provider.md
183185
- name: Neo4j Memory Provider
184186
href: integrations/neo4j-memory.md
185187
- name: A2A Protocol

agent-framework/agents/conversations/context-providers.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ ms.service: agent-framework
1313

1414
Context providers run around each invocation to add context before execution and process data after execution.
1515

16+
> [!NOTE]
17+
> For a list of pre-built context providers you can use with your agent, see [Integrations](../../integrations/index.md)
18+
1619
## Built-in pattern
1720

1821
:::zone pivot="programming-language-csharp"

agent-framework/agents/observability.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ var agent = new ChatClientAgent(
5353
> [!IMPORTANT]
5454
> When you enable observability for your chat clients and agents, you might see duplicated information, especially when sensitive data is enabled. The chat context (including prompts and responses) that is captured by both the chat client and the agent will be included in both spans. Depending on your needs, you might choose to enable observability only on the chat client or only on the agent to avoid duplication. See the [GenAI Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/) for more details on the attributes captured for LLM and Agents.
5555
56-
> [!NOTE]
56+
> [!WARNING]
5757
> Only enable sensitive data in development or testing environments, as it might expose user information in production logs and traces. Sensitive data includes prompts, responses, function call arguments, and results.
5858
5959
### Configuration
@@ -327,7 +327,7 @@ The following environment variables control Agent Framework observability:
327327
- `ENABLE_CONSOLE_EXPORTERS` - Default is `false`, set to `true` to enable console output for telemetry.
328328
- `VS_CODE_EXTENSION_PORT` - Port for AI Toolkit or Microsoft Foundry VS Code extension integration.
329329

330-
> [!NOTE]
330+
> [!WARNING]
331331
> Sensitive information includes prompts, responses, and more, and should only be enabled in development or test environments. It is not recommended to enable this in production as it may expose sensitive data.
332332
333333
#### Standard OpenTelemetry environment variables
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
---
2+
title: Chat History Memory Provider for Agent Framework
3+
description: Learn how to use the Chat History Memory Provider to add semantic memory capabilities to your Agent Framework agents by storing and retrieving chat history from a vector store.
4+
zone_pivot_groups: programming-languages
5+
author: westey-m
6+
ms.topic: conceptual
7+
ms.author: westey
8+
ms.date: 04/03/2026
9+
ms.service: agent-framework
10+
---
11+
12+
# Chat History Memory Provider
13+
14+
::: zone pivot="programming-language-csharp"
15+
16+
The `ChatHistoryMemoryProvider` is an AI Context Provider that stores all chat history in a vector store and retrieves related messages to augment the current conversation. This enables agents to recall relevant context from prior interactions using semantic similarity search.
17+
18+
## How it works
19+
20+
The provider operates in two phases:
21+
22+
1. **Storage**: After each agent invocation, new request and response messages are stored in the vector store with embeddings generated from their content.
23+
24+
2. **Retrieval**: Before each invocation (or on-demand via function calling), the provider searches the vector store for messages semantically similar to the current user input and injects them as context.
25+
26+
Stored messages are scoped using configurable identifiers (application, agent, user, session) allowing fine-grained control over what history is stored and searchable.
27+
28+
## Prerequisites
29+
30+
- A vector store implementation from [Microsoft.Extensions.VectorData](https://www.nuget.org/packages/Microsoft.Extensions.VectorData.Abstractions) (for example, [`InMemoryVectorStore`](https://www.nuget.org/packages/Microsoft.SemanticKernel.Connectors.InMemory), [Azure AI Search](https://www.nuget.org/packages/Microsoft.SemanticKernel.Connectors.AzureAISearch), or [other supported stores](/semantic-kernel/concepts/vector-store-connectors/out-of-the-box-connectors))
31+
- An embedding model configured on your vector store
32+
- Azure OpenAI or OpenAI deployment for the chat model
33+
- .NET 8.0 or later
34+
35+
## Usage
36+
37+
The following example demonstrates creating an agent with the `ChatHistoryMemoryProvider` using an in-memory vector store.
38+
39+
Note the usage of only userid for the search scope. This allows the agent to recall information from prior conversations with the same user to inform new responses.
40+
41+
```csharp
42+
using Azure.AI.OpenAI;
43+
using Azure.Identity;
44+
using Microsoft.Agents.AI;
45+
using Microsoft.Extensions.AI;
46+
using Microsoft.Extensions.VectorData;
47+
using Microsoft.SemanticKernel.Connectors.InMemory;
48+
49+
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
50+
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
51+
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
52+
var embeddingDeploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME")
53+
?? "text-embedding-3-large";
54+
55+
// Create a vector store with an embedding generator.
56+
// For production, replace InMemoryVectorStore with a persistent store.
57+
VectorStore vectorStore = new InMemoryVectorStore(new InMemoryVectorStoreOptions()
58+
{
59+
EmbeddingGenerator = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
60+
.GetEmbeddingClient(embeddingDeploymentName)
61+
.AsIEmbeddingGenerator()
62+
});
63+
64+
// Create the agent with ChatHistoryMemoryProvider
65+
AIAgent agent = new AzureOpenAIClient(
66+
new Uri(endpoint),
67+
new DefaultAzureCredential())
68+
.GetChatClient(deploymentName)
69+
.AsAIAgent(new ChatClientAgentOptions
70+
{
71+
ChatOptions = new() { Instructions = "You are a helpful assistant." },
72+
Name = "MemoryAgent",
73+
AIContextProviders = [new ChatHistoryMemoryProvider(
74+
vectorStore,
75+
collectionName: "chathistory",
76+
vectorDimensions: 3072,
77+
session => new ChatHistoryMemoryProvider.State(
78+
// Configure where messages are stored
79+
storageScope: new() { UserId = "user-123", SessionId = Guid.NewGuid().ToString() },
80+
// Configure where to search (can be broader than storage scope)
81+
searchScope: new() { UserId = "user-123" }))]
82+
});
83+
84+
// Start a session and interact with the agent
85+
AgentSession session = await agent.CreateSessionAsync();
86+
Console.WriteLine(await agent.RunAsync("I prefer window seats on flights.", session));
87+
88+
// Start a new session - the agent can recall the user's preference
89+
AgentSession session2 = await agent.CreateSessionAsync();
90+
Console.WriteLine(await agent.RunAsync("Book me a flight to Seattle.", session2));
91+
```
92+
93+
> [!TIP]
94+
> Use different `storageScope` and `searchScope` configurations to control memory isolation. For example, store per-session but search across all sessions for a user.
95+
96+
## Configuration options
97+
98+
The `ChatHistoryMemoryProviderOptions` class provides configuration for the provider behavior.
99+
100+
### Search behavior
101+
102+
| Option | Type | Default | Description |
103+
|--------|------|---------|-------------|
104+
| `SearchTime` | `SearchBehavior` | `BeforeAIInvoke` | Controls when memory search is executed. |
105+
106+
The `SearchBehavior` enum has two values:
107+
108+
- **`BeforeAIInvoke`**: Automatically searches for relevant memories before each AI invocation and injects them as context messages. This is the default behavior.
109+
- **`OnDemandFunctionCalling`**: Exposes a function tool that the AI model can invoke to search memories on demand. Use this when you want the model to decide when to recall memories.
110+
111+
### Search result options
112+
113+
| Option | Type | Default | Description |
114+
|--------|------|---------|-------------|
115+
| `MaxResults` | `int?` | `3` | Maximum number of chat history results to retrieve per search. |
116+
| `ContextPrompt` | `string?` | `"## Memories\nConsider the following memories..."` | The prompt text prefixed to search results before injection. |
117+
118+
### On-demand function tool options
119+
120+
These options only apply when `SearchTime` is set to `OnDemandFunctionCalling`:
121+
122+
| Option | Type | Default | Description |
123+
|--------|------|---------|-------------|
124+
| `FunctionToolName` | `string?` | `"Search"` | The name of the search function tool exposed to the model. |
125+
| `FunctionToolDescription` | `string?` | `"Allows searching for related previous chat history..."` | The description of the search function tool. |
126+
127+
### Message filtering
128+
129+
| Option | Type | Default | Description |
130+
|--------|------|---------|-------------|
131+
| `SearchInputMessageFilter` | `Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>>?` | External messages only | Filter applied to request messages when constructing search queries. |
132+
| `StorageInputRequestMessageFilter` | `Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>>?` | External messages only | Filter applied to request messages before storage. |
133+
| `StorageInputResponseMessageFilter` | `Func<IEnumerable<ChatMessage>, IEnumerable<ChatMessage>>?` | No filter | Filter applied to response messages before storage. |
134+
135+
### Logging and telemetry
136+
137+
| Option | Type | Default | Description |
138+
|--------|------|---------|-------------|
139+
| `EnableSensitiveTelemetryData` | `bool` | `false` | When `true`, sensitive data (user IDs, message content) appears in logs unchanged. |
140+
| `Redactor` | `Redactor?` | Redactor that replaces text with `"<redacted>"` | Custom redactor for sensitive values when logging. Ignored if `EnableSensitiveTelemetryData` is `true`. |
141+
142+
### State management
143+
144+
| Option | Type | Default | Description |
145+
|--------|------|---------|-------------|
146+
| `StateKey` | `string?` | Provider type name | Key used to store provider state in the `AgentSession.StateBag`. Override when using multiple `ChatHistoryMemoryProvider` instances in the same session. |
147+
148+
## Scope configuration
149+
150+
The `ChatHistoryMemoryProviderScope` class controls how messages are organized and filtered in the vector store.
151+
152+
| Property | Type | Description |
153+
|----------|------|-------------|
154+
| `ApplicationId` | `string?` | Scope messages to a specific application. If not set, spans all applications. |
155+
| `AgentId` | `string?` | Scope messages to a specific agent. If not set, spans all agents. |
156+
| `UserId` | `string?` | Scope messages to a specific user. If not set, spans all users. |
157+
| `SessionId` | `string?` | Scope messages to a specific session. |
158+
159+
### Storage vs search scope
160+
161+
The `ChatHistoryMemoryProvider.State` class accepts two scopes:
162+
163+
- **`storageScope`**: Defines how new messages are tagged when stored. All scope properties are written as metadata.
164+
- **`searchScope`**: Defines the filter criteria when searching. Set this broader than storage scope to search across multiple sessions or agents.
165+
166+
Example: Store per-session, search across all sessions for a user:
167+
168+
```csharp
169+
new ChatHistoryMemoryProvider.State(
170+
storageScope: new() { UserId = "user-123", SessionId = "session-456" },
171+
searchScope: new() { UserId = "user-123" })
172+
```
173+
174+
## Security considerations
175+
176+
> [!WARNING]
177+
> Review these security considerations before deploying the `ChatHistoryMemoryProvider` in production.
178+
179+
- **Indirect prompt injection**: Messages retrieved from the vector store are injected into the LLM context. If the vector store is compromised, adversarial content could influence LLM behavior. Data from the store is accepted as-is without validation.
180+
181+
- **PII and sensitive data**: Conversation messages (including user inputs and LLM responses) are stored as vectors. These messages may contain PII or sensitive information. Ensure your vector store has appropriate access controls and encryption at rest.
182+
183+
- **On-demand search tool**: When using `OnDemandFunctionCalling`, the AI model controls when and what to search for. The search query is AI-generated and should be treated as untrusted input by the vector store implementation.
184+
185+
- **Trace logging**: When `LogLevel.Trace` is enabled, full search queries and results may be logged. This data may contain PII. Use the `Redactor` option or disable sensitive telemetry in production.
186+
187+
::: zone-end
188+
189+
::: zone pivot="programming-language-python"
190+
191+
This provider is not yet available for Python. See the C# tab for usage examples.
192+
193+
::: zone-end
194+
195+
## Next steps
196+
197+
> [!div class="nextstepaction"]
198+
> [Context Providers overview](../agents/conversations/context-providers.md)

agent-framework/integrations/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ may be supplied. Here is a list of existing providers that can be used.
3838

3939
| Chat History Provider | Release Status |
4040
| ------------------------------------------------------------------ | --------------- |
41-
| [In-Memory Chat History Provider](https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI.Abstractions/InMemoryChatHistoryProvider.cs) | Preview |
41+
| [In-Memory Chat History Provider](https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI.Abstractions/InMemoryChatHistoryProvider.cs) | Released |
4242
| [Cosmos DB Chat History Provider](https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI.CosmosNoSql/CosmosChatHistoryProvider.cs) | Preview |
4343

4444
::: zone-end
@@ -61,7 +61,7 @@ Here is a list of existing providers that can be used.
6161

6262
| Memory AI Context Provider | Release Status |
6363
| ------------------------------------------------------------------ | --------------- |
64-
| [Chat History Memory Provider](https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI/Memory/ChatHistoryMemoryProvider.cs) | Preview |
64+
| [Chat History Memory Provider](./chat-history-memory-provider.md) | Released |
6565

6666
::: zone-end
6767

@@ -87,7 +87,7 @@ Here is a list of existing providers that can be used.
8787
| RAG AI Context Provider | Release Status |
8888
| ------------------------------------------------------------------ | --------------- |
8989
| [Neo4j GraphRAG Provider](./neo4j-graphrag.md) | Preview |
90-
| [Text Search Provider](https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI/TextSearchProvider.cs) | Preview |
90+
| [Text Search Provider](https://github.com/microsoft/agent-framework/blob/main/dotnet/src/Microsoft.Agents.AI/TextSearchProvider.cs) | Released |
9191

9292
::: zone-end
9393

0 commit comments

Comments
 (0)