diff --git a/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProvider.cs b/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProvider.cs index 3f5cda31d0..5a0bd981b9 100644 --- a/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProvider.cs +++ b/dotnet/src/Microsoft.Agents.AI/Functions/ContextualFunctionProvider.cs @@ -112,6 +112,12 @@ public sealed class ContextualFunctionProvider : AIContextProvider { Throw.IfNull(context); + // Don't add messages to the recent messages queue if the invocation failed + if (context.InvokeException is not null) + { + return default; + } + // Add the request and response messages to the recent messages queue foreach (var message in context.RequestMessages) { diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Functions/ContextualFunctionProviderTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Functions/ContextualFunctionProviderTests.cs index 2eaa005e87..b5e2657803 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/Functions/ContextualFunctionProviderTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/Functions/ContextualFunctionProviderTests.cs @@ -304,6 +304,46 @@ public sealed class ContextualFunctionProviderTests Assert.Equal("msg5", capturedNewMessages.ElementAt(1).Text); } + [Fact] + public async Task InvokedAsync_ShouldNotAddMessages_WhenExceptionIsPresent_Async() + { + // Arrange + var functions = new List { CreateFunction("f1") }; + var options = new ContextualFunctionProviderOptions + { + NumberOfRecentMessagesInContext = 5 + }; + + var provider = new ContextualFunctionProvider( + vectorStore: this._vectorStoreMock.Object, + vectorDimensions: 1536, + functions: functions, + maxNumberOfFunctions: 5, + options: options); + + var message1 = new ChatMessage() { Contents = [new TextContent("msg1")] }; + var message2 = new ChatMessage() { Contents = [new TextContent("msg2")] }; + var message3 = new ChatMessage() { Contents = [new TextContent("msg3")] }; + + // Add successful invocations first + await provider.InvokedAsync(new AIContextProvider.InvokedContext([message1], null) { ResponseMessages = [] }); + await provider.InvokedAsync(new AIContextProvider.InvokedContext([message2], null) { ResponseMessages = [] }); + + // Act - Add an invocation with an exception + await provider.InvokedAsync(new AIContextProvider.InvokedContext([message3], null) + { + ResponseMessages = [], + InvokeException = new InvalidOperationException("Test exception") + }); + + // Assert - The exception-causing message should not be added to recent messages + var invokingContext = new AIContextProvider.InvokingContext([new() { Contents = [new TextContent("new message")] }]); + await provider.InvokingAsync(invokingContext); + + var expected = string.Join(Environment.NewLine, ["msg1", "msg2", "new message"]); + this._collectionMock.Verify(c => c.SearchAsync(expected, It.IsAny(), null, It.IsAny()), Times.Once); + } + private static AIFunction CreateFunction(string name, string description = "") { return AIFunctionFactory.Create(() => { }, name, description);