HostedToolSearchTool with DeferredTools in the type#7471
Conversation
…r tool search support Co-authored-by: stephentoub <[email protected]>
…rredTools/NonDeferredTools - Redesign HostedToolSearchTool with DeferredTools/NonDeferredTools properties - Remove SearchableAIFunctionDeclaration (no longer needed) - Revert DelegatingAIFunctionDeclaration to internal - Update OpenAI provider: use HostedToolSearchTool enable/disable logic for defer_loading - Add ChatOptions parameter to AsOpenAIResponseTool extension method - Use AOT-safe ModelReaderWriter.Read with OpenAIContext.Default - Update API baselines and tests Co-authored-by: stephentoub <[email protected]>
…tor ToResponseTool signature - Fix O(N²) by finding HostedToolSearchTool once before the tools loop instead of scanning the list for each tool - Remove HostedToolSearchTool from json baseline (experimental types don't need entries) - Refactor ToResponseTool(AITool, ...) to take HostedToolSearchTool? directly instead of extracting from ChatOptions each time - Remove FindToolSearchTool helper method (inlined into callers) Co-authored-by: stephentoub <[email protected]>
Co-authored-by: stephentoub <[email protected]>
…SearchTool private Co-authored-by: stephentoub <[email protected]>
…ation test Co-authored-by: stephentoub <[email protected]>
…s/NonDeferredTools from HostedToolSearchTool Co-authored-by: stephentoub <[email protected]> Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/7a29d49e-c422-4fe7-81f4-366bd781b460
…ai-dotnet#1053 comment, add DeferLoadingTools to HostedMcpServerTool Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/08f652ed-169c-43c3-a247-829ebd0b3e4f Co-authored-by: jozkee <[email protected]>
…gTools from HostedMcpServerTool, add interaction tests - Remove Namespace property and namespaceName parameter from SearchableAIFunctionDeclaration - Remove DeferLoadingTools property from HostedMcpServerTool - Update OpenAIResponsesChatClient to drop namespace patching and MCP defer_loading patching - Update RemoteMCP_DeferLoadingTools integration test to use AsOpenAIResponseTool() + Patch.Set + AsAITool() - Add tool_search_call/tool_search_output assertions to integration test - Add SearchableAIFunctionDeclaration + ApprovalRequiredAIFunction interaction tests - Add FunctionInvokingChatClient test for approval detection through searchable wrapper Co-authored-by: Copilot <[email protected]>
Remove [Experimental(AIToolSearch)] attribute from DelegatingAIFunctionDeclaration, SearchableAIFunctionDeclaration, and HostedToolSearchTool. Remove the AIToolSearch diagnostic constant from DiagnosticIds. Add API baseline entries for all three types in Microsoft.Extensions.AI.Abstractions.json. Clean up unused usings. Co-authored-by: Copilot <[email protected]>
Add tests verifying that the OpenAI API returns HTTP 400 when HostedToolSearchTool is used without any deferred tools: - UseToolSearch_OnlyToolSearchNoFunctions - UseToolSearch_WithNonDeferredFunctionsOnly Co-authored-by: Copilot <[email protected]>
…arch-support # Conflicts: # src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json
…e grouping in OpenAIResponsesChatClient - Add Namespace property and namespaceName parameter to SearchableAIFunctionDeclaration - Add namespaceName parameter to CreateToolSet for bulk namespace assignment - Add namespace grouping logic in OpenAIResponsesChatClient tools loop - Add ToNamespaceResponseTool helper using ModelReaderWriter for AOT-safe JSON - Add namespace unit tests in SearchableAIFunctionDeclarationTests - Add namespace VerbatimHttpHandler tests in OpenAIResponseClientTests - Add UseToolSearch_WithNamespace integration test with tool_search assertions - Add tool_search_call/tool_search_output assertions to existing integration test - Update API baseline Co-authored-by: Copilot <[email protected]>
…rouping from OpenAI provider Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/a0e8d299-9f73-4db3-be63-674f590aa717 Co-authored-by: jozkee <[email protected]>
…espace grouping from OpenAI provider" This reverts commit 89d8df4. Co-authored-by: jozkee <[email protected]>
… and restore @namespace param name Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/1783bbad-9689-4b08-bfcc-79988248c2ff Co-authored-by: jozkee <[email protected]>
- Replace per-tool SearchableAIFunctionDeclaration with collections-based DeferredTools and Namespace properties on HostedToolSearchTool - Support multiple HostedToolSearchTool instances with different/same namespaces (same namespace merges, first-claims wins) - Patch defer_loading on both FunctionTool and McpTool when claimed by a HostedToolSearchTool - Group deferred FunctionTool and McpTool into namespace containers - Widen ToNamespaceResponseTool to accept any ResponseTool - Add AsOpenAIResponseTool ChatOptions parameter for defer context - Delete SearchableAIFunctionDeclaration and its tests - Make DelegatingAIFunctionDeclaration internal (no external consumers) - Add conversion, VerbatimHttpHandler, and integration tests Co-authored-by: Copilot <[email protected]>
There was a problem hiding this comment.
Pull request overview
Adds a revised “tool_search” implementation for OpenAI Responses that enables deferred tool loading and optional namespace grouping via a new HostedToolSearchTool abstraction, with extensive unit/integration test coverage.
Changes:
- Introduces
HostedToolSearchToolwithIList<string>? DeferredToolsand optionalNamespacefor grouping deferred tools. - Updates OpenAI Responses tool conversion to emit
tool_search, patchdefer_loading, and wrap deferred tools in{"type":"namespace"}containers when configured. - Expands unit/integration tests to validate request JSON and runtime behavior for deferred loading, namespaces, and MCP scenarios.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs | Adds VerbatimHttpHandler request-shape tests covering tool_search, deferred loading, namespaces, and MCP grouping. |
| test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs | Adds live integration coverage for tool_search behavior (including MCP + RawRepresentation assertions). |
| test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIConversionTests.cs | Adds conversion tests for tool_search emission and defer-loading patching based on ChatOptions. |
| test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Tools/HostedToolSearchToolTests.cs | Adds basic round-trip tests for HostedToolSearchTool properties. |
| src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs | Implements HostedToolSearchTool conversion + defer-loading patching + namespace tool container construction. |
| src/Libraries/Microsoft.Extensions.AI.OpenAI/MicrosoftExtensionsAIResponsesExtensions.cs | Extends AsOpenAIResponseTool(AITool) to accept optional ChatOptions for conversion context. |
| src/Libraries/Microsoft.Extensions.AI.OpenAI/Microsoft.Extensions.AI.OpenAI.json | Updates API contract for the changed extension method signature (optional ChatOptions). |
| src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedToolSearchTool.cs | Adds the new marker tool type and public surface (DeferredTools, Namespace). |
| src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json | Adds the new public API surface for HostedToolSearchTool. |
|
@copilot address the feedback |
Addressed in cc2e021: updated HostedToolSearchTool XML docs to match deferred-loading behavior (including MCP/deferred tools wording), and refactored OpenAIResponsesChatClient to precompute deferred/namespace lookups once per request instead of repeatedly scanning tools. Targeted tool-search tests are passing. |
Verify that tools like HostedCodeInterpreterTool are unaffected by DeferredTools and namespace grouping: no defer_loading is patched and the tool stays top-level in the request. Co-authored-by: Copilot <[email protected]>
The ChatOptions? parameter was added so the standalone extension method could honor HostedToolSearchTool.DeferredTools when converting an AITool outside the chat client. In practice, this introduces an O(N^2) hazard if called in a loop (each call rebuilds the ToolSearchLookup) and adds API surface for a niche escape-hatch scenario. The primary path (GetResponseAsync) shares a single lookup and is unaffected. Future per-tool deferral mechanisms (e.g. a SearchableAITool decorator or a DeferLoading bool on AITool) would obsolete this parameter entirely. Callers building ResponseTool lists manually can still set defer_loading via Patch.Set as needed. Removes 11 conversion-level unit tests whose coverage is already provided end-to-end by VerbatimHttpHandler-based tests in OpenAIResponseClientTests.cs. Co-authored-by: Copilot <[email protected]>
jeffhandley
left a comment
There was a problem hiding this comment.
LGTM. New experimental APIs, room to get feedback, and reasonable workarounds for OpenAI gaps.
* Implement HostedToolSearchTool and SearchableAIFunctionDeclaration for tool search support Co-authored-by: stephentoub <[email protected]> * Redesign: consolidate tool search into HostedToolSearchTool with DeferredTools/NonDeferredTools - Redesign HostedToolSearchTool with DeferredTools/NonDeferredTools properties - Remove SearchableAIFunctionDeclaration (no longer needed) - Revert DelegatingAIFunctionDeclaration to internal - Update OpenAI provider: use HostedToolSearchTool enable/disable logic for defer_loading - Add ChatOptions parameter to AsOpenAIResponseTool extension method - Use AOT-safe ModelReaderWriter.Read with OpenAIContext.Default - Update API baselines and tests Co-authored-by: stephentoub <[email protected]> * Address review feedback: fix O(N²), remove json baseline entry, refactor ToResponseTool signature - Fix O(N²) by finding HostedToolSearchTool once before the tools loop instead of scanning the list for each tool - Remove HostedToolSearchTool from json baseline (experimental types don't need entries) - Refactor ToResponseTool(AITool, ...) to take HostedToolSearchTool? directly instead of extracting from ChatOptions each time - Remove FindToolSearchTool helper method (inlined into callers) Co-authored-by: stephentoub <[email protected]> * Extract shared FindToolSearchTool helper to deduplicate lookup code Co-authored-by: stephentoub <[email protected]> * Simplify ToResponseTool: add ChatOptions-only overload, make FindToolSearchTool private Co-authored-by: stephentoub <[email protected]> * Add unit tests for HostedToolSearchTool JSON serialization and integration test Co-authored-by: stephentoub <[email protected]> * Revert to SearchableAIFunctionDeclaration design, remove DeferredTools/NonDeferredTools from HostedToolSearchTool Co-authored-by: stephentoub <[email protected]> Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/7a29d49e-c422-4fe7-81f4-366bd781b460 * Address review feedback: rename namespaceName to @namespace, add openai-dotnet#1053 comment, add DeferLoadingTools to HostedMcpServerTool Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/08f652ed-169c-43c3-a247-829ebd0b3e4f Co-authored-by: jozkee <[email protected]> * Update tests * revert namespace param rename * Remove Namespace from SearchableAIFunctionDeclaration and DeferLoadingTools from HostedMcpServerTool, add interaction tests - Remove Namespace property and namespaceName parameter from SearchableAIFunctionDeclaration - Remove DeferLoadingTools property from HostedMcpServerTool - Update OpenAIResponsesChatClient to drop namespace patching and MCP defer_loading patching - Update RemoteMCP_DeferLoadingTools integration test to use AsOpenAIResponseTool() + Patch.Set + AsAITool() - Add tool_search_call/tool_search_output assertions to integration test - Add SearchableAIFunctionDeclaration + ApprovalRequiredAIFunction interaction tests - Add FunctionInvokingChatClient test for approval detection through searchable wrapper Co-authored-by: Copilot <[email protected]> * Remove [Experimental] from tool search types and add API baselines Remove [Experimental(AIToolSearch)] attribute from DelegatingAIFunctionDeclaration, SearchableAIFunctionDeclaration, and HostedToolSearchTool. Remove the AIToolSearch diagnostic constant from DiagnosticIds. Add API baseline entries for all three types in Microsoft.Extensions.AI.Abstractions.json. Clean up unused usings. Co-authored-by: Copilot <[email protected]> * Add integration tests for tool search edge cases Add tests verifying that the OpenAI API returns HTTP 400 when HostedToolSearchTool is used without any deferred tools: - UseToolSearch_OnlyToolSearchNoFunctions - UseToolSearch_WithNonDeferredFunctionsOnly Co-authored-by: Copilot <[email protected]> * Add namespace support to SearchableAIFunctionDeclaration and namespace grouping in OpenAIResponsesChatClient - Add Namespace property and namespaceName parameter to SearchableAIFunctionDeclaration - Add namespaceName parameter to CreateToolSet for bulk namespace assignment - Add namespace grouping logic in OpenAIResponsesChatClient tools loop - Add ToNamespaceResponseTool helper using ModelReaderWriter for AOT-safe JSON - Add namespace unit tests in SearchableAIFunctionDeclarationTests - Add namespace VerbatimHttpHandler tests in OpenAIResponseClientTests - Add UseToolSearch_WithNamespace integration test with tool_search assertions - Add tool_search_call/tool_search_output assertions to existing integration test - Update API baseline Co-authored-by: Copilot <[email protected]> * Feedback * Remove Namespace from SearchableAIFunctionDeclaration and namespace grouping from OpenAI provider Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/a0e8d299-9f73-4db3-be63-674f590aa717 Co-authored-by: jozkee <[email protected]> * Revert "Remove Namespace from SearchableAIFunctionDeclaration and namespace grouping from OpenAI provider" This reverts commit 89d8df4. Co-authored-by: jozkee <[email protected]> * Fix CI: replace KeyValuePair deconstruction for net462/netstandard2.0 and restore @namespace param name Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/1783bbad-9689-4b08-bfcc-79988248c2ff Co-authored-by: jozkee <[email protected]> * Add DeferredTools/Namespace on HostedToolSearchTool, support MCP tools - Replace per-tool SearchableAIFunctionDeclaration with collections-based DeferredTools and Namespace properties on HostedToolSearchTool - Support multiple HostedToolSearchTool instances with different/same namespaces (same namespace merges, first-claims wins) - Patch defer_loading on both FunctionTool and McpTool when claimed by a HostedToolSearchTool - Group deferred FunctionTool and McpTool into namespace containers - Widen ToNamespaceResponseTool to accept any ResponseTool - Add AsOpenAIResponseTool ChatOptions parameter for defer context - Delete SearchableAIFunctionDeclaration and its tests - Make DelegatingAIFunctionDeclaration internal (no external consumers) - Add conversion, VerbatimHttpHandler, and integration tests Co-authored-by: Copilot <[email protected]> * Address tool-search reviewer feedback for docs and lookup performance Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/cc5b7c31-3c0f-448e-95c6-2474c2327715 Co-authored-by: jozkee <[email protected]> * Refine HostedToolSearchTool docs to use deferrable tool wording Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/8f9ae606-8c21-4af0-b43d-74a2b463ed33 Co-authored-by: jozkee <[email protected]> * Optimize tool-search lookup precomputation in OpenAI responses client Agent-Logs-Url: https://github.com/dotnet/extensions/sessions/cc5b7c31-3c0f-448e-95c6-2474c2327715 Co-authored-by: jozkee <[email protected]> * Add tests for non-deferrable tools with HostedToolSearchTool Verify that tools like HostedCodeInterpreterTool are unaffected by DeferredTools and namespace grouping: no defer_loading is patched and the tool stays top-level in the request. Co-authored-by: Copilot <[email protected]> * Bring back Experimental * Address test feedback * Drop ChatOptions parameter from AsOpenAIResponseTool(AITool) The ChatOptions? parameter was added so the standalone extension method could honor HostedToolSearchTool.DeferredTools when converting an AITool outside the chat client. In practice, this introduces an O(N^2) hazard if called in a loop (each call rebuilds the ToolSearchLookup) and adds API surface for a niche escape-hatch scenario. The primary path (GetResponseAsync) shares a single lookup and is unaffected. Future per-tool deferral mechanisms (e.g. a SearchableAITool decorator or a DeferLoading bool on AITool) would obsolete this parameter entirely. Callers building ResponseTool lists manually can still set defer_loading via Patch.Set as needed. Removes 11 conversion-level unit tests whose coverage is already provided end-to-end by VerbatimHttpHandler-based tests in OpenAIResponseClientTests.cs. Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: stephentoub <[email protected]> Co-authored-by: Copilot <[email protected]>
|
May I ask if this PR addresses this issue? |
|
@shouyuan-timesoftsg it adds the tool search tool in its hosted/remote flavor to |
@rogerbarreto
Alternative to #7377.
Propose
HostedToolSearchToolwith the tools specified in the type as anIList<string>? DeferredTools.HostedToolSearchTools. That seems like a rough edge but not terrible, I'm wondering if it would be better to wait until we have a built-in NamespaceTool.Microsoft Reviewers: Open in CodeFlow