Add hostedtool.ToolSearch type and map it to OpenAI Responses ToolSearchToolParam - #641
Conversation
3ef68fd to
309c093
Compare
This comment has been minimized.
This comment has been minimized.
309c093 to
6e88513
Compare
Introduce a ToolSearch hosted tool mirroring the .NET HostedToolSearchTool, and convert it in the Responses provider to the OpenAI ToolSearchToolParam (OfToolSearch) so deferred tool search can be requested from the service.
6e88513 to
1856424
Compare
This comment has been minimized.
This comment has been minimized.
# Conflicts: # tool/hostedtool/hostedtool.go
Parity Review —
|
Go (hostedtool.ToolSearch) |
.NET (Microsoft.Extensions.AI.HostedToolSearchTool) |
Notes |
|---|---|---|
Name() → "tool_search" |
Name → "tool_search" |
✅ identical wire name |
DeferredTools []string |
DeferredTools IList<string>? |
✅ same concept |
Namespace string |
Namespace string? |
✅ same concept |
NamespaceDescription string |
NamespaceDescription string? |
✅ same concept |
AdditionalProperties map[string]any |
AdditionalProperties IReadOnlyDictionary<string,object?> |
✅ same escape hatch |
var _ tool.Tool = (*ToolSearch)(nil) guard |
class HostedToolSearchTool : AITool |
✅ both implement the common tool interface |
The Go type is also structurally parallel to the other hosted-tool types already in hostedtool.go (WebSearch, FileSearch, CodeInterpreter, MCPServer), which is the right pattern for this package.
⚠️ Parity gap: Namespace and DeferredTools are silently dropped on the wire
In the .NET Microsoft.Extensions.AI.OpenAI implementation (OpenAIResponsesChatClient.cs), HostedToolSearchTool is mapped to a bare {"type": "tool_search"} object because the OpenAI .NET SDK does not yet expose a typed ToolSearchTool (openai/openai-dotnet#1053). The Namespace and DeferredTools fields drive a ToolSearchLookup mechanism that patches defer_loading: true onto other (function) tools in the list — that logic is separate from the HostedToolSearchTool → JSON conversion.
The Go PR carries Namespace and DeferredTools on the struct for future parity, and currently drops them from the wire, which is consistent with how .NET behaves today. However, .NET does apply the defer_loading patch to peer tools automatically when a HostedToolSearchTool is present. The Go provider has no equivalent, so a caller setting DeferredTools: ["read_file"] will not see defer_loading applied to that function tool on the wire.
Recommendation: Not a blocker for this PR — the wire shape (tool_search with description/execution/parameters) is correct and consistent with the OpenAI Go SDK's ToolSearchToolParam. Track the defer_loading peer-tool patching as a follow-up; this matches the open design question already noted in the PR description.
✅ Python status
No typed HostedToolSearchTool equivalent exists in python/packages/core/agent_framework/ or the foundry provider packages. Python uses a pass-through sanitization approach for hosted tools, so no Python parity issue is raised by this PR.
Verdict
The exported API shape is consistent with the upstream .NET abstraction (Microsoft.Extensions.AI.HostedToolSearchTool). The public-api-change label is correctly applied. No parity-blocking issues found; the DeferredTools/Namespace → defer_loading behavior gap is a known forward follow-up, not a regression introduced by this PR.
Generated by Go API Consistency Review Agent · sonnet46 · 72.3 AIC · ⌖ 5.95 AIC · ⊞ 5.7K · ◷
There was a problem hiding this comment.
🟡 Not ready to approve
The new ToolSearch type’s documentation/usage implies DeferredTools/Namespace participate in provider behavior, but they are currently ignored by the OpenAI mapping (and unused elsewhere), which should be clarified to avoid misleading API consumers.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR introduces a new hosted-tool marker (hostedtool.ToolSearch) and wires it into the OpenAI Responses provider so callers can serialize a tool_search tool entry in Responses API requests, aligning the Go stack with existing .NET/Python support.
Changes:
- Added
hostedtool.ToolSearchmarker type (with parity fields likeDeferredTools/Namespace). - Updated the OpenAI Responses tool-mapping switch to serialize
tool_searchviaresponses.ToolSearchToolParam. - Added a black-box serialization test ensuring
tool_searchis emitted in the outbound request payload.
File summaries
| File | Description |
|---|---|
| tool/hostedtool/hostedtool.go | Adds the new ToolSearch hosted tool marker type. |
| provider/openaiprovider/responses.go | Maps *hostedtool.ToolSearch into responses.ToolSearchToolParam and appends it to params.Tools. |
| provider/openaiprovider/responses_test.go | Adds a request-serialization test covering the new tool_search mapping. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| case *hostedtool.ToolSearch: | ||
| var variant responses.ToolSearchToolParam |
| // ToolSearch represents a hosted tool that can be specified to an AI service | ||
| // to enable it to search over a set of deferred tools, mirroring the .NET | ||
| // Microsoft.Extensions.AI.HostedToolSearchTool. The service searches the | ||
| // deferred tools on the model's behalf so that large tool sets do not all | ||
| // need to be sent to the model up front. |
What
Add a
hostedtool.ToolSearchtype and wire it through the OpenAI Responses provider so a deferred tool-search request can be sent to the service.tool/hostedtool/hostedtool.go: newToolSearchmarker tool (fieldsDeferredTools,Namespace,NamespaceDescription,AdditionalProperties;Name()returnstool_search), with the usualvar _ tool.Toolassertion.provider/openaiprovider/responses.go: newcase *hostedtool.ToolSearchthat builds aresponses.ToolSearchToolParamand appendsresponses.ToolUnionParam{OfToolSearch: &variant}, mirroring the existing WebSearch/FileSearch/CodeInterpreter/MCPServer cases.Why
Parity with the .NET/Python stacks:
Microsoft.Extensions.AI.HostedToolSearchToolexposes a hosted tool-search marker with deferred tools, but the Go port had no equivalent — the onlyToolSearchoccurrences were unwired auto-generatedinternal/azaiprojectsconstants. The OpenAI Go SDK (responses.ToolSearchToolParam/ToolUnionParam.OfToolSearch) already supports the wire shape, so nothing but the mapping was missing.How tested
provider/openaiprovider/responses_test.goaddsTestResponsesToolSearchTool_SerializesCorrectly, a black-box test that drives a*hostedtool.ToolSearchthroughRunTextagainst the existing fake-transport harness and asserts the serialized request contains atool_searchtool (withdescription/execution/parameters). It fails when the provider case is removed (the tool is silently dropped) and passes with it.go build ./...,go vet, andgo test ./provider/openaiprovider/... ./tool/hostedtool/...are green.Open design questions (draft)
ToolSearchToolParamonly exposesDescription,Execution, andParameters.NamespaceDescriptionmaps toDescription, andexecution/parametersare read fromAdditionalProperties.DeferredToolsandNamespaceare carried on the type for .NET parity but have no direct field in this SDK version — should they be folded intoParameters, or is carrying them for other providers/future SDK versions the right call?Executionbe a first-class typed field onhostedtool.ToolSearchrather than anAdditionalPropertieskey, matching how other providers might consume it?