Repository navigation
Conversation
…anges Adding or removing a tool through ChatOptions.Tools changes the tool definitions at the start of every request and invalidates the prompt cache. Providers now accept tool changes at a position in the conversation instead. These experimental content types describe such a change, ChatOptions.Tools stays the set of invocable tools, and the OpenAI Responses client sends additions as an additional_tools item. The Chat Completions client, which has no positional form, applies the changes to the tools it sends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ERjP6o4DUJYLsnWqftSufm
There was a problem hiding this comment.
🟡 Changes recommended
Tool-mode inconsistencies and repeated enumeration can produce invalid or incomplete requests.
5 open findings
What changed in this PR
Adds experimental positional tool additions/removals to AI abstractions and maps them to OpenAI APIs.
Changes:
- Adds serializable tool-change content types.
- Implements Responses positional additions and Chat Completions fallback behavior.
- Adds API baselines and request/serialization tests.
| File | Description |
|---|---|
test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs |
Tests Responses wire mapping. |
test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs |
Tests Chat Completions fallback. |
test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Contents/ToolRemovalContentTests.cs |
Tests removal content. |
test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Contents/ToolAdditionContentTests.cs |
Tests addition content. |
src/Shared/DiagnosticIds/DiagnosticIds.cs |
Registers the experiment identifier. |
src/Libraries/Microsoft.Extensions.AI.OpenAI/ToolChanges.cs |
Implements shared tool-change processing. |
src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs |
Emits positional additional_tools items. |
src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIChatClient.cs |
Applies fallback tool changes. |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Defaults.cs |
Registers experimental JSON types. |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json |
Adds API baseline entries. |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolRemovalContent.cs |
Defines removal content. |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolAdditionContent.cs |
Defines addition content and serialization. |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/AIContent.cs |
Documents future polymorphic registration. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1630779&view=codecoverage-tab |
- Materialize the messages before scanning them for tool changes, so a sequence that can only be enumerated once isn't consumed before the request is built (Responses and Chat Completions). - Throw when ToolMode requires a function that the history removes, rather than sending a tool_choice for a function missing from the tools. - Clarify the ToolAdditionContent and ToolRemovalContent remarks. - Have the Responses test remove a tool that is actually declared, and add tests for single-pass histories, streaming, and the required-function case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AUeyFfwBuvSBBsvYtTiyRd
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1630819&view=codecoverage-tab |



Draft implementation of #7822, to make the proposal concrete. Open for discussion. The API isn't settled.
What changes
ToolAdditionContent/ToolRemovalContent(experimental,MEAI001) in Microsoft.Extensions.AI.Abstractions.ToolAdditionContent.Toolis anAIFunctionDeclaration. It serializes as name, description and JSON schemas, and deserializes to a declaration.AIJsonUtilities.DefaultOptionsthe way experimental content types were before stabilization (toolAddition,toolRemoval), with the[JsonDerivedType]lines left commented onAIContent.additional_toolsinput item (role: "developer") ahead of that message's items. The OpenAI SDK has no type for it, so the JSON is built by hand, as fornamespaceandtool_search.tools.ToolChanges, in Microsoft.Extensions.AI.OpenAI, shared by both clients. Whether it should become public for adapters in other repositories is one of the open questions in [API Proposal]: Add and remove tools mid-conversation without invalidating the prompt cache #7822.FunctionInvokingChatClientis unchanged.ChatOptions.Toolsstays the set of invocable tools.Testing
AIContent.gpt-5.4-miniandgpt-5.5. A tool introduced by a mid-conversation message withToolAdditionContent:ChatOptions.Toolsread 0.FunctionInvokingChatClient.Generated with Claude Opus 5.5 (Claude Code)
Microsoft Reviewers: Open in CodeFlow