Fix Namespace gaps in HostedToolSearchTool#7500
Conversation
Adds a NamespaceDescription property to HostedToolSearchTool and threads it through OpenAIResponsesChatClient so the namespace wrapper sent to the OpenAI Responses API includes a 'description' field when one is provided. The description is conditionally emitted only when non-null/non-empty (the live service rejects empty strings). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…stances are supplied The OpenAI Responses API rejects requests with more than one tool_search tool in tools[] (HTTP 400: 'Only one tool_search tool is allowed in tools parameter'). When callers attach multiple HostedToolSearchTool instances - typically to scope different DeferredTools to different namespaces - AsCreateResponseOptions now emits only the first tool_search ResponseTool while still letting every instance contribute its Namespace/NamespaceDescription/DeferredTools to the namespace-grouping lookup. The dedupe is scoped to the request-building loop rather than the shared ToResponseTool helper so the public AsOpenAIResponseTool extension still converts every HostedToolSearchTool independently. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the OpenAI Responses tool-search serialization to better support namespaced deferred tools, addressing service rejections due to missing namespace metadata and duplicated tool_search tool entries.
Changes:
- Added
HostedToolSearchTool.NamespaceDescription(experimental) to allow emitting a namespace description in the OpenAI payload. - Updated
OpenAIResponsesChatClientto (a) include namespace descriptions when constructing{"type":"namespace"}tools and (b) avoid sending multipletool_searchentries when multipleHostedToolSearchToolinstances are provided. - Expanded unit and integration tests to validate namespace descriptions and multi-namespace scenarios.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs | Updates expected JSON to avoid duplicate tool_search entries; adds non-streaming coverage for namespace descriptions and merge behavior. |
| test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs | Adds live round-trip tests for tool search with one/two namespaces including descriptions. |
| test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Tools/HostedToolSearchToolTests.cs | Adds tests for NamespaceDescription default and round-trip behavior. |
| src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs | Adds namespace description emission, tool_search deduplication, and namespace description merge behavior. |
| src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedToolSearchTool.cs | Introduces NamespaceDescription API with XML docs clarifying behavior. |
| src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json | Updates API surface baseline for the new experimental property. |
…ol instances When several HostedToolSearchTool instances share a namespace name and only some supply a NamespaceDescription, the wrapper now uses the first non-empty description rather than first-writer-wins. ToolSearchLookup.Namespace is now a class with a settable Description so all entries in _namespacedToolNames sharing a namespace name reference the same instance and pick up later upgrades automatically; this also keeps namespaceGroups (keyed by reference equality) collapsed to one bucket per namespace name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Updates the OpenAI Responses chat client and tool-search abstractions to correctly support OpenAI “namespace” tool wrappers by allowing a namespace description to be sent, and to avoid emitting multiple tool_search entries when multiple HostedToolSearchTool instances are provided.
Changes:
- Add
NamespaceDescriptiontoHostedToolSearchTooland include it when emitting OpenAI{"type":"namespace"}tools. - Ensure only one
tool_searchtool is sent on the wire even if multipleHostedToolSearchToolinstances are configured. - Expand unit and integration test coverage for namespace descriptions and multi-namespace tool search scenarios.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs | Emits namespace tool description (when provided) and dedupes tool_search; tracks namespaces with name+description. |
| src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedToolSearchTool.cs | Adds NamespaceDescription API surface with remarks. |
| src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json | Adds API baseline entry for NamespaceDescription (Experimental). |
| test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs | Updates expected JSON to include only one tool_search; adds tests for namespace description behaviors. |
| test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs | Adds live tests to validate namespace wrappers with descriptions round-trip with tool search enabled. |
| test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Tools/HostedToolSearchToolTests.cs | Adds unit tests for NamespaceDescription default/roundtrip. |
* Add HostedToolSearchTool.NamespaceDescription support Adds a NamespaceDescription property to HostedToolSearchTool and threads it through OpenAIResponsesChatClient so the namespace wrapper sent to the OpenAI Responses API includes a 'description' field when one is provided. The description is conditionally emitted only when non-null/non-empty (the live service rejects empty strings). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Emit a single tool_search entry when multiple HostedToolSearchTool instances are supplied The OpenAI Responses API rejects requests with more than one tool_search tool in tools[] (HTTP 400: 'Only one tool_search tool is allowed in tools parameter'). When callers attach multiple HostedToolSearchTool instances - typically to scope different DeferredTools to different namespaces - AsCreateResponseOptions now emits only the first tool_search ResponseTool while still letting every instance contribute its Namespace/NamespaceDescription/DeferredTools to the namespace-grouping lookup. The dedupe is scoped to the request-building loop rather than the shared ToResponseTool helper so the public AsOpenAIResponseTool extension still converts every HostedToolSearchTool independently. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Prefer first non-empty NamespaceDescription across HostedToolSearchTool instances When several HostedToolSearchTool instances share a namespace name and only some supply a NamespaceDescription, the wrapper now uses the first non-empty description rather than first-writer-wins. ToolSearchLookup.Namespace is now a class with a settable Description so all entries in _namespacedToolNames sharing a namespace name reference the same instance and pick up later upgrades automatically; this also keeps namespaceGroups (keyed by reference equality) collapsed to one bucket per namespace name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Microsoft Reviewers: Open in CodeFlow