Chat-Level Middleware
Chat-level middleware intercepts every call that travels from the agent to the underlying IChatClient (the LLM inference service). This is the lowest interception point in the pipeline - below sessions, conversation history management, and function calling logic.
Typical uses: detailed prompt logging, modifying messages before they reach the AI service, transforming responses, tracking token usage or cost.
How Chat-Level Middleware Works
| Phase | What you can do |
|---|---|
| Before the LLM call | Inspect or modify the full message list and ChatOptions. |
| After the LLM call | Inspect or transform the raw ChatResponse before it is returned to the agent. |
Defining the Middleware Function
A chat middleware function has a fixed signature. It receives the messages, the chat options, the inner IChatClient, and a cancellation token. It must call innerChatClient.GetResponseAsync() to forward the request (unless intentionally short-circuiting).
Registering the Middleware
Chat-level middleware is applied to the IChatClient using the builder pattern, before the agent is created. The resulting middleware-wrapped client is then passed to AsAIAgent().
Full Example Output
Running agent.RunAsync("Hello, how are you?") with the logging middleware active produces output similar to:
Multiple Middleware in a Chain
Multiple chat-level middleware functions can be chained by calling Use() more than once. They execute in registration order:
Each middleware must call the provided inner client (or be intentionally short-circuiting) to pass control down the chain.
Difference from Agent Run Middleware
| Agent Run Middleware | Chat-Level Middleware | |
| Intercepts | One call per RunAsync() invocation | One call per LLM inference request (may be multiple per run when function calling is active) |
| Sees | User-facing messages and full AgentResponse | The raw message list sent to the LLM including injected history and tool results |
| Registration | agent.AsBuilder().Use(...) | chatClient.AsBuilder().Use(...) before agent creation |
Summary
| Concept | API | Description |
|---|---|---|
| Middleware function signature | Task<ChatResponse>(messages, options, innerChatClient, ct) | Receives the full raw message list going to the LLM. |
| Register middleware | chatClient.AsBuilder().Use(getResponseFunc: ...).Build() | Wraps the IChatClient with middleware before agent creation. |
| Forward request | innerChatClient.GetResponseAsync(...) | Must be called to continue the chain (unless short-circuiting). |
Required Packages
| Package | Purpose |
|---|---|
Microsoft.Agents.AI | AIAgent, AgentResponse |
Microsoft.Extensions.AI | IChatClient, ChatResponse, ChatMessage, ChatClientBuilder |
Microsoft.Extensions.AI.OpenAI | AsIChatClient() and OpenAI integration |