diff --git a/dotnet/src/Microsoft.Agents.AI/ChatClient/MessageInjectingChatClient.cs b/dotnet/src/Microsoft.Agents.AI/ChatClient/MessageInjectingChatClient.cs
index cbf5a18626..4d9fa56880 100644
--- a/dotnet/src/Microsoft.Agents.AI/ChatClient/MessageInjectingChatClient.cs
+++ b/dotnet/src/Microsoft.Agents.AI/ChatClient/MessageInjectingChatClient.cs
@@ -263,8 +263,7 @@ private static AgentSession GetRequiredSession()
}
///
- /// Drains all pending injected messages from the queue and returns a new list combining
- /// the original messages with the drained messages. The original list is never modified.
+ /// Drains all pending injected messages from the queue and returns the combined messages.
///
private static IList DrainInjectedMessages(List queue, IList newMessages)
{
@@ -275,6 +274,14 @@ private static IList DrainInjectedMessages(List queue,
return newMessages;
}
+ if (newMessages is List mutableMessages)
+ {
+ // Keep the outer function loop's history list in sync with what was sent to the model.
+ mutableMessages.AddRange(queue);
+ queue.Clear();
+ return mutableMessages;
+ }
+
var combined = new List(newMessages);
combined.AddRange(queue);
queue.Clear();
diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/MessageInjectingChatClientTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/MessageInjectingChatClientTests.cs
index 93f6b02b03..bcff9521d5 100644
--- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/MessageInjectingChatClientTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/MessageInjectingChatClientTests.cs
@@ -407,6 +407,67 @@ public async Task RunAsync_PropagatesConversationId_AcrossInternalLoopIterations
Assert.Equal("conv-123", capturedConversationIds[1]); // Second call: propagated from first response
}
+ [Fact]
+ public async Task RunAsync_KeepsInjectedMessagesInFunctionLoopHistoryAsync()
+ {
+ // Arrange
+ int serviceCallCount = 0;
+ int toolCallCount = 0;
+ List> capturedMessageTexts = [];
+ MessageInjectingChatClient? injectorRef = null;
+ ChatClientAgentSession? sessionRef = null;
+
+ Mock mockService = new();
+ mockService.Setup(
+ s => s.GetResponseAsync(
+ It.IsAny>(),
+ It.IsAny(),
+ It.IsAny()))
+ .Returns((IEnumerable msgs, ChatOptions? _, CancellationToken _) =>
+ {
+ serviceCallCount++;
+ capturedMessageTexts.Add(msgs.Select(m => m.Text).ToList());
+
+ return Task.FromResult(serviceCallCount switch
+ {
+ 1 => new ChatResponse([new(ChatRole.Assistant,
+ [new FunctionCallContent("call1", "myTool", new Dictionary())])]),
+ 2 => new ChatResponse([new(ChatRole.Assistant,
+ [new FunctionCallContent("call2", "myTool", new Dictionary())])]),
+ _ => new ChatResponse([new(ChatRole.Assistant, "final")]),
+ });
+ });
+
+ var tool = AIFunctionFactory.Create(() =>
+ {
+ toolCallCount++;
+ if (toolCallCount == 1)
+ {
+ injectorRef!.EnqueueMessages(sessionRef!, [new ChatMessage(ChatRole.User, "injected correction")]);
+ }
+
+ return "tool result";
+ }, "myTool", "A test tool");
+
+ ChatClientAgent agent = new(mockService.Object, options: new()
+ {
+ ChatOptions = new() { Tools = [tool] },
+ EnableMessageInjection = true,
+ }, services: new ServiceCollection().BuildServiceProvider());
+
+ injectorRef = agent.ChatClient.GetService()!;
+
+ // Act
+ var session = await agent.CreateSessionAsync() as ChatClientAgentSession;
+ sessionRef = session;
+ await agent.RunAsync([new(ChatRole.User, "original")], session);
+
+ // Assert
+ Assert.Equal(3, serviceCallCount);
+ Assert.Contains(capturedMessageTexts[1], text => text == "injected correction");
+ Assert.Contains(capturedMessageTexts[2], text => text == "injected correction");
+ }
+
///
/// Verifies that a session with pending injected messages can be serialized and deserialized,
/// and that the deserialized session correctly delivers the injected messages on the next run.