diff --git a/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs b/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs index 1133e10a8a..c43f90155f 100644 --- a/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs +++ b/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs @@ -476,7 +476,7 @@ internal async Task NotifyProvidersOfNewMessagesAsync( ChatOptions? chatOptions, CancellationToken cancellationToken) { - ChatHistoryProvider? chatHistoryProvider = this.ResolveChatHistoryProvider(chatOptions); + ChatHistoryProvider? chatHistoryProvider = this.ResolveChatHistoryProvider(session, chatOptions); if (chatHistoryProvider is not null) { @@ -508,7 +508,7 @@ internal async Task NotifyProvidersOfFailureAsync( ChatOptions? chatOptions, CancellationToken cancellationToken) { - ChatHistoryProvider? chatHistoryProvider = this.ResolveChatHistoryProvider(chatOptions); + ChatHistoryProvider? chatHistoryProvider = this.ResolveChatHistoryProvider(session, chatOptions); if (chatHistoryProvider is not null) { @@ -974,14 +974,17 @@ private void WarnOnMissingPerServiceCallChatHistoryPersistingChatClient() } } - private ChatHistoryProvider? ResolveChatHistoryProvider(ChatOptions? chatOptions) + private ChatHistoryProvider? ResolveChatHistoryProvider(ChatClientAgentSession session, ChatOptions? chatOptions) { - ChatHistoryProvider? provider = chatOptions?.ConversationId is null ? this.ChatHistoryProvider : null; + bool serviceStoresHistory = !this.RequiresPerServiceCallChatHistoryPersistence + && (!string.IsNullOrWhiteSpace(session.ConversationId) + || !string.IsNullOrWhiteSpace(chatOptions?.ConversationId)); + ChatHistoryProvider? provider = serviceStoresHistory ? null : this.ChatHistoryProvider; // If someone provided an override ChatHistoryProvider via AdditionalProperties, we should use that instead. if (chatOptions?.AdditionalProperties?.TryGetValue(out ChatHistoryProvider? overrideProvider) is true) { - if (this._agentOptions?.ThrowOnChatHistoryProviderConflict is true && string.IsNullOrWhiteSpace(chatOptions?.ConversationId) is false) + if (this._agentOptions?.ThrowOnChatHistoryProviderConflict is true && serviceStoresHistory) { throw new InvalidOperationException( $"Only {nameof(ChatClientAgentSession.ConversationId)} or {nameof(this.ChatHistoryProvider)} may be used, but not both. The current {nameof(ChatClientAgentSession)} has a {nameof(ChatClientAgentSession.ConversationId)} indicating server-side chat history management, but an override {nameof(this.ChatHistoryProvider)} was provided via {nameof(AgentRunOptions.AdditionalProperties)}."); @@ -1019,7 +1022,7 @@ internal async Task> LoadChatHistoryAsync( ChatOptions? chatOptions, CancellationToken cancellationToken) { - var chatHistoryProvider = this.ResolveChatHistoryProvider(chatOptions); + var chatHistoryProvider = this.ResolveChatHistoryProvider(session, chatOptions); if (chatHistoryProvider is null) { return messages; diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_ChatHistoryManagementTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_ChatHistoryManagementTests.cs index 410ee4edda..eff8f3d83d 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_ChatHistoryManagementTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_ChatHistoryManagementTests.cs @@ -385,11 +385,11 @@ public async Task RunAsync_Throws_WhenThrowEnabledRegardlessOfClearSettingAsync( } /// - /// Verify that RunAsync does not throw when no ChatHistoryProvider is configured on options, - /// even if the service returns a conversation id (default InMemoryChatHistoryProvider is used but not from options). + /// Verify that RunAsync does not persist to the default InMemoryChatHistoryProvider when + /// the service returns a conversation id. /// [Fact] - public async Task RunAsync_DoesNotThrow_WhenNoChatHistoryProviderInOptionsAndConversationIdReturnedAsync() + public async Task RunAsync_DoesNotUseDefaultInMemoryChatHistoryProvider_WhenConversationIdReturnedAsync() { // Arrange Mock mockService = new(); @@ -407,8 +407,10 @@ public async Task RunAsync_DoesNotThrow_WhenNoChatHistoryProviderInOptionsAndCon ChatClientAgentSession? session = await agent.CreateSessionAsync() as ChatClientAgentSession; await agent.RunAsync([new(ChatRole.User, "test")], session); - // Assert - no exception, session gets the conversation id + // Assert Assert.Equal("ConvId", session!.ConversationId); + var inMemoryProvider = Assert.IsType(agent.ChatHistoryProvider); + Assert.Empty(inMemoryProvider.GetMessages(session)); } #endregion