Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 4, 2025

FunctionInvokingChatClient Enhancement

This PR updates FunctionInvokingChatClient to check for existing FunctionResultContent before invoking functions, enabling proper handling of server-side function calls and supporting multiple FunctionInvokingChatClient instances in a pipeline.

Changes completed:

  • Fix formatting issues (lines 1332, 1359, 1368)
  • Encapsulate FunctionResultContent collection into CopyFunctionCalls method
  • Add retroactive removal of FCCs when FRCs are seen in later streaming updates
  • Add extensive testing covering all scenarios:
    • FunctionResultInSeparateUpdate - FCC and FRC in separate streaming updates
    • FunctionResultInSeparateMessageFromInnerClient - FCC and FRC in separate messages from inner client
    • MultipleFunctionsPartialResults - Some functions with server results, others needing invocation
    • LayeredClientsWithSameFunctionInvokeOnlyOnce - Two layered clients with same function
    • ThreeLayeredClientsWithSameFunctionInvokeOnlyOnce - Three layered clients
    • StreamingMultipleUpdatesWithMixedContent - Complex streaming scenario

Implementation details:

Core changes to FunctionInvokingChatClient.cs:

  1. Created new overload of CopyFunctionCalls for streaming that both collects FRCs and filters FCCs
  2. Added two-pass approach: first collect all FRCs, then copy FCCs that don't have results
  3. Added retroactive removal of FCCs from functionCallContents when FRCs are seen in later updates
  4. Properly handles both streaming and non-streaming scenarios

Test coverage (49 total tests, all passing):

  • Existing 39 tests continue to pass
  • Added 10 new comprehensive tests covering:
    • FCC and FRC in same/separate messages/updates
    • Multiple functions with partial results
    • Layered FunctionInvokingChatClient instances (2 and 3 layers)
    • Complex streaming scenarios with mixed content

All 365 tests in Microsoft.Extensions.AI.Tests pass on both net8.0 and net9.0.

Original prompt

Currently FunctionInvokingChatClient looks for any FunctionCallContent coming back from the inner chat client and handles any it finds. It doesn't pay attention to whether there's already a corresponding FunctionResultContent with the same CallId in the response (or response stream for streaming updates), but it should. Please update FunctionInvokingChatClient so that it also pays attention to any FunctionResultContents coming from the inner client, and it then ignores FunctionCallContent for any it already has a FunctionResultContent. Please also add extensive testing for this. This should enable a pipeline of IChatClients to contain multiple FunctionInvokingChatClient instances, such that a given FunctionCallContent is only handled once. It should also enable a leaf IChatClient to produce FunctionCallContent and FunctionResultContent to represent a server-side function call, and not worry about a FunctionInvokingChatClient trying to invoke a function for the FCC.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Microsoft Reviewers: Open in CodeFlow

@github-actions github-actions bot added the area-ai Microsoft.Extensions.AI libraries label Nov 4, 2025
Copilot AI changed the title [WIP] Update FunctionInvokingChatClient to track FunctionResultContent Skip function invocation when FunctionResultContent already exists Nov 4, 2025
Copilot AI requested a review from stephentoub November 4, 2025 16:31
Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot, please address the diagnostics:

Build FAILED.

D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1332,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net8.0]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1359,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net8.0]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1368,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net8.0]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1332,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net462]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1359,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net462]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1368,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net462]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1332,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net9.0]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1359,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net9.0]
D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\ChatCompletion\FunctionInvokingChatClientTests.cs(1368,1): error IDE0055: Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055) [D:\a\_work\1\s\test\Libraries\Microsoft.Extensions.AI.Tests\Microsoft.Extensions.AI.Tests.csproj::TargetFramework=net9.0]
    0 Warning(s)
    9 Error(s)

This also needs much more extensive testing, cover both streaming and non-streaming, FunctionResultContent coming back in the same or separate messages or updates from the corresponding FunctionCallContent, multiple FunctionCallContents some of which have FunctionResultContent and some of which don't, etc. I would also like to see a test that has multiple FunctionInvokingChatClients layered in and validating that functions are only ever invoked once and not once per FunctionInvokingChatClient.

@stephentoub stephentoub marked this pull request as ready for review November 4, 2025 17:27
@stephentoub stephentoub requested a review from a team as a code owner November 4, 2025 17:27
Copilot AI review requested due to automatic review settings November 4, 2025 17:27
@stephentoub
Copy link
Member

stephentoub commented Nov 4, 2025

cc: @westey-m, @javiercn

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds functionality to prevent redundant function invocation when server-side function calling results are already present in the response. The FunctionInvokingChatClient now checks for existing FunctionResultContent with matching CallIds and skips invoking those functions client-side.

Key Changes:

  • Modified CopyFunctionCalls methods to filter out function calls that already have corresponding results
  • Added tracking of FunctionResultContent CallIds in both streaming and non-streaming code paths
  • Comprehensive test coverage for various scenarios involving pre-existing function results

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
FunctionInvokingChatClient.cs Added logic to collect FunctionResultContent CallIds and filter out FunctionCallContent with matching CallIds to prevent redundant function invocations
FunctionInvokingChatClientTests.cs Added four comprehensive test cases covering partial results, all results present, server-side execution, and mixed scenarios across streaming and non-streaming paths
Comments suppressed due to low confidence (1)

test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientTests.cs:1557

  • The YieldAsync method accepts params IEnumerable<T> items but iterates over it as a single collection. This appears to be a bug - if multiple IEnumerable arguments are passed, only items from the first enumerable will be yielded. The params keyword creates an array of IEnumerable, so the outer foreach iterates over enumerables, not their items. Either remove params or use nested foreach loops: foreach (var enumerable in items) foreach (var item in enumerable).
    private static async IAsyncEnumerable<T> YieldAsync<T>(params IEnumerable<T> items)

Copy link
Contributor Author

Copilot AI commented Nov 4, 2025

@copilot, please address the diagnostics:

Build FAILED.

...

Fixed the formatting issues and added extensive testing. Commit 83f3393 includes:

Formatting fixes: Added blank lines at lines 1332, 1359, and 1368 as required.

Extensive testing: Added 10 new comprehensive tests covering:

  • FunctionResultInSeparateUpdate - FCC and FRC in separate streaming updates
  • FunctionResultInSeparateMessageFromInnerClient - FCC and FRC from inner client in same response
  • MultipleFunctionsPartialResults - Some functions with server results, others requiring invocation
  • LayeredClientsWithSameFunctionInvokeOnlyOnce - Two layered FunctionInvokingChatClients with same function
  • ThreeLayeredClientsWithSameFunctionInvokeOnlyOnce - Three layered clients
  • StreamingMultipleUpdatesWithMixedContent - Complex streaming with mixed FCC/FRC patterns

All tests validate that functions are invoked exactly once even with multiple layered FunctionInvokingChatClients. All 49 FunctionInvokingChatClient tests and all 365 total AI tests pass on both net8.0 and net9.0.

@stephentoub
Copy link
Member

This needs more thought. Closing for now.

@stephentoub stephentoub closed this Nov 7, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Dec 8, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-ai Microsoft.Extensions.AI libraries

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants