From a76f2e215f8b0cff2349697abe232370142de3da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:56:04 +0000 Subject: [PATCH] Fix streaming path to include chat history in messages sent to chat client RunCoreStreamingAsync was passing inputMessagesForProviders (which lacks chat history) to GetStreamingResponseAsync instead of inputMessagesForChatClient (which includes chat history). This caused streaming runs to lose conversation context on subsequent calls. The non-streaming path (RunCoreAsync) already correctly used inputMessagesForChatClient. This aligns the streaming path to match. Also adds a unit test that validates chat history is included in messages sent to the chat client during streaming on subsequent calls. Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com> --- .../ChatClient/ChatClientAgent.cs | 2 +- .../ChatClient/ChatClientAgentTests.cs | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs b/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs index 5878d877b2..37e673f710 100644 --- a/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs +++ b/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs @@ -226,7 +226,7 @@ protected override async IAsyncEnumerable RunCoreStreamingA try { // Using the enumerator to ensure we consider the case where no updates are returned for notification. - responseUpdatesEnumerator = chatClient.GetStreamingResponseAsync(inputMessagesForProviders, chatOptions, cancellationToken).GetAsyncEnumerator(cancellationToken); + responseUpdatesEnumerator = chatClient.GetStreamingResponseAsync(inputMessagesForChatClient, chatOptions, cancellationToken).GetAsyncEnumerator(cancellationToken); } catch (Exception ex) { diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentTests.cs index 41fb29bfed..c23e8cffaf 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentTests.cs @@ -1320,6 +1320,45 @@ public async Task RunStreamingAsyncUsesChatHistoryProviderWhenNoConversationIdRe mockFactory.Verify(f => f(It.IsAny(), It.IsAny()), Times.Once); } + /// + /// Verify that RunStreamingAsync includes chat history in messages sent to the chat client on subsequent calls. + /// + [Fact] + public async Task RunStreamingAsyncIncludesChatHistoryInMessagesToChatClientAsync() + { + // Arrange + List> capturedMessages = []; + Mock mockService = new(); + ChatResponseUpdate[] returnUpdates = + [ + new ChatResponseUpdate(role: ChatRole.Assistant, content: "response"), + ]; + mockService.Setup( + s => s.GetStreamingResponseAsync( + It.IsAny>(), + It.IsAny(), + It.IsAny())) + .Returns(ToAsyncEnumerableAsync(returnUpdates)) + .Callback, ChatOptions?, CancellationToken>((msgs, _, _) => capturedMessages.Add(msgs.ToList())); + ChatClientAgent agent = new(mockService.Object, options: new() + { + ChatOptions = new() { Instructions = "test instructions" }, + }); + + // Act + ChatClientAgentSession? session = await agent.CreateSessionAsync() as ChatClientAgentSession; + await agent.RunStreamingAsync([new(ChatRole.User, "first")], session).ToListAsync(); + await agent.RunStreamingAsync([new(ChatRole.User, "second")], session).ToListAsync(); + + // Assert - the second call should include chat history (first user message + first response) plus the new message + Assert.Equal(2, capturedMessages.Count); + var secondCallMessages = capturedMessages[1].ToList(); + Assert.Equal(3, secondCallMessages.Count); + Assert.Equal("first", secondCallMessages[0].Text); + Assert.Equal("response", secondCallMessages[1].Text); + Assert.Equal("second", secondCallMessages[2].Text); + } + /// /// Verify that RunStreamingAsync throws when a factory is provided and the chat client returns a conversation id. ///