Microsoft Agent Framework Microsoft.Extensions.AI Created: 27 Feb 2026 Updated: 27 Feb 2026

IChatClient: GetStreamingResponseAsync

GetStreamingResponseAsync works exactly like GetResponseAsync but returns an IAsyncEnumerable<ChatResponseUpdate> instead of a complete ChatResponse. Each ChatResponseUpdate contains a small chunk (often one or a few tokens) as it arrives from the model, allowing your UI to display text progressively rather than waiting for the full reply.

Key Concepts

1. Simple Streaming

Iterate with await foreach and print each chunk immediately:

await foreach (ChatResponseUpdate update in
client.GetStreamingResponseAsync("Explain what a hash table is in 3 sentences."))
{
Console.Write(update.Text);
}

2. Collecting Updates for History

To continue the conversation, collect all updates into a list and call history.AddMessages(updates). This helper assembles the chunks into a proper ChatMessage and adds it to the history list:

var updates = new List<ChatResponseUpdate>();
await foreach (ChatResponseUpdate update in client.GetStreamingResponseAsync(history))
{
Console.Write(update.Text);
updates.Add(update);
}
history.AddMessages(updates); // now history is ready for the next turn

3. Streaming Multi-Turn

Combine history management with streaming for a full conversation:

var history = new List<ChatMessage>();
history.Add(new ChatMessage(ChatRole.User, "What is a linked list?"));

var updates = new List<ChatResponseUpdate>();
await foreach (var u in client.GetStreamingResponseAsync(history))
{
Console.Write(u.Text);
updates.Add(u);
}
history.AddMessages(updates);

history.Add(new ChatMessage(ChatRole.User, "How does it differ from an array?"));
// ... repeat

Full Example

using Microsoft.Extensions.AI;
using OpenAI;

namespace MicrosoftAgentFrameworkLesson.ConsoleApp.ChatClient;

/// <summary>
/// Demonstrates IChatClient.GetStreamingResponseAsync:
/// token-by-token streaming and streaming multi-turn conversation.
/// Scenario: Programming concept explainer.
/// </summary>
public static class StreamingChatDemo
{
public static async Task RunAsync()
{
var apiKey = Environment.GetEnvironmentVariable("OPEN_AI_KEY")
?? throw new InvalidOperationException("Set OPEN_AI_KEY environment variable.");

IChatClient client = new OpenAIClient(apiKey)
.GetChatClient("gpt-4o-mini")
.AsIChatClient();

Console.WriteLine("====== IChatClient — GetStreamingResponseAsync (Streaming) ======\n");

// Demo 1: Simple streaming — tokens printed as they arrive
Console.WriteLine("--- Demo 1: Simple Streaming ---");
Console.Write("A: ");
await foreach (ChatResponseUpdate update in
client.GetStreamingResponseAsync("Explain what a hash table is in 3 sentences."))
{
Console.Write(update.Text);
}
Console.WriteLine("\n");

// Demo 2: Streaming multi-turn — history updated from streamed updates
Console.WriteLine("--- Demo 2: Streaming Multi-Turn ---");
var history = new List<ChatMessage>();
string[] questions =
[
"What is a linked list?",
"How does it differ from an array?"
];

foreach (var question in questions)
{
Console.WriteLine($"Q: {question}");
history.Add(new ChatMessage(ChatRole.User, question));

Console.Write("A: ");
var updates = new List<ChatResponseUpdate>();
await foreach (ChatResponseUpdate update in
client.GetStreamingResponseAsync(history))
{
Console.Write(update.Text);
updates.Add(update);
}
Console.WriteLine("\n");
history.AddMessages(updates);
}
}
}
Share this lesson: