Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 26, 2026

  • Understand the problem: FunctionInvokingChatClient.CreateResponseMessages should reuse FunctionResultContent returned by the function if the CallId matches
  • Implement the change in FunctionInvokingChatClient.cs at line 1230
  • Add tests to verify the new behavior
  • Unseal FunctionCallContent and FunctionResultContent classes
  • Update API baseline to reflect unsealed classes
  • Add test validating that a derived FunctionResultContent type is propagated to the inner IChatClient
  • Validate that the FunctionResultContent is the only one in the tool message
  • Assert reference equality in tests
  • Add streaming path tests for all new tests
  • Obtain tool message from ChatResponse instead of capturing via callback
  • Run tests to validate changes
  • Code review fixes

Summary

This PR modifies FunctionInvokingChatClient.CreateResponseMessages to check if the function result is already a FunctionResultContent with a matching CallId. If so, it uses that instance directly instead of wrapping it in a new FunctionResultContent. This gives the AIFunction flexibility to create its own FunctionResultContent configured however it wants.

Additionally, this PR unseals FunctionCallContent and FunctionResultContent classes to allow derivation.

Changes:

  1. Modified FunctionInvokingChatClient.CreateFunctionResultContent method to check if the result is a FunctionResultContent with a matching CallId and return it directly
  2. Unsealed FunctionCallContent and FunctionResultContent classes to allow derivation
  3. Updated API baseline files for the unsealed classes
  4. Added tests with both non-streaming and streaming paths and reference equality assertions:
    • FunctionReturningFunctionResultContentWithMatchingCallId_UsesItDirectly: Verifies that when a function returns a FunctionResultContent with matching CallId, it is used directly (same reference)
    • FunctionReturningFunctionResultContentWithMismatchedCallId_WrapsIt: Verifies that when a function returns a FunctionResultContent with mismatched CallId, it is wrapped in a new FunctionResultContent (with the inner one reference-equal)
    • FunctionReturningDerivedFunctionResultContent_PropagatesInstanceToInnerClient: Verifies that a derived FunctionResultContent type is properly propagated to the wrapped IChatClient and is the only one in the tool message (same reference)
Original prompt

On FunctionInvokingChatClient.cs:1230-1230, Right now, FunctionInvokingChatClient.CreateResponseMessages wraps the result of the function in a new FunctionResultContent. If, however, the object returned by the function is already a FunctionResultContent, and if that FunctionResultContent's CallId matches the one it's supposed to be, the implementation should just use that returned instance rather than creating a new one. This gives the AIFunction flexibility to create its own FunctionResultContent configured however it wants.


💡 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

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix response message wrapping in CreateResponseMessages Allow FunctionResultContent pass-through when CallId matches Jan 26, 2026
Copilot AI requested a review from stephentoub January 26, 2026 04:46
@stephentoub
Copy link
Member

@copilot also unseal FunctionCallContent and FunctionResultContent and add tests validating that an AIFunction can return a FunctionResultContent-derived type and that instance is what's propagated to the IChatClient wrapped by the FunctionInvokingChatClient.

Copilot AI and others added 2 commits January 26, 2026 17:18
…e propagation test

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
…nt test

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 26, 2026

@copilot also unseal FunctionCallContent and FunctionResultContent and add tests validating that an AIFunction can return a FunctionResultContent-derived type and that instance is what's propagated to...

Done in 790f979. Unsealed both FunctionCallContent and FunctionResultContent, updated the API baseline file, and added the FunctionReturningDerivedFunctionResultContent_PropagatesInstanceToInnerClient test that verifies a derived FunctionResultContent type is properly propagated to the wrapped IChatClient.

…ount

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copy link
Member

@jozkee jozkee left a comment

Choose a reason for hiding this comment

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

Otherwise, LGTM.

@jozkee jozkee marked this pull request as ready for review January 26, 2026 21:16
@jozkee jozkee requested a review from a team as a code owner January 26, 2026 21:16
Copilot AI review requested due to automatic review settings January 26, 2026 21:16
…onResultContent tests

Co-authored-by: jozkee <16040868+jozkee@users.noreply.github.com>
Copilot AI requested a review from jozkee January 26, 2026 21:24
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 updates FunctionInvokingChatClient so that it can re-use FunctionResultContent instances returned directly from functions when the CallId matches, enabling more flexible and customized function result handling. It also unseals FunctionCallContent and FunctionResultContent to allow derivation and adds tests and API baseline updates to validate and document the new behavior.

Changes:

  • Update FunctionInvokingChatClient.CreateResponseMessages (via CreateFunctionResultContent) to short-circuit and return an existing FunctionResultContent when the function result is already a FunctionResultContent with a matching CallId.
  • Unseal FunctionCallContent and FunctionResultContent to support derived content types, and update the AI abstractions API baseline accordingly.
  • Add unit tests covering matching/mismatched CallId behavior and propagation of a derived FunctionResultContent type through the inner IChatClient, including ensuring only a single FunctionResultContent is present in the tool message.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs Adds a conditional path in CreateFunctionResultContent to re-use an existing FunctionResultContent instance when the CallId matches, otherwise preserving the existing wrapping logic.
src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/FunctionCallContent.cs Removes sealed from FunctionCallContent to allow inheritance while keeping existing behavior and API intact.
src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/FunctionResultContent.cs Removes sealed from FunctionResultContent so it can be subclassed (e.g., to add custom properties) without changing its current public API surface.
src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json Updates the API baseline to reflect that FunctionCallContent and FunctionResultContent are now unsealed classes.
test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientTests.cs Adds tests verifying pass-through of matching FunctionResultContent, wrapping on mismatched CallId, and correct propagation of a derived FunctionResultContent to the inner client with only one tool result message.

Co-authored-by: jozkee <16040868+jozkee@users.noreply.github.com>
Copilot AI requested a review from jozkee January 26, 2026 22:00
@stephentoub stephentoub enabled auto-merge (squash) January 26, 2026 22:43
@stephentoub stephentoub merged commit ec81915 into main Jan 26, 2026
6 checks passed
@stephentoub stephentoub deleted the copilot/fix-functionresultcontent-creation branch January 26, 2026 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants