Tool search — load tool schemas only when the model needs them
An OpenHands agent loads a fat toolset and re-sends every schema every turn. Tool search lets the model pull rarely-used tool definitions on demand, cutting input tokens while preserving the prompt cache. This page shows how it works and why it's a clean add.
1What the feature is
Tool search lets the model dynamically search for and load tool definitions into its context as needed, instead of loading them all up front. Mark rarely-used tools defer_loading: true; the model sees only their name and description at the start, and pulls the full parameter schema (via a tool_search tool) when it decides to use them.
gpt-5.4+.2Why OpenHands cares
A typical OpenHands agent loads bash, str_replace_editor, browser, task/delegate, plus one function per MCP tool. On the Responses path all those schemas are re-sent every turn. Deferring the long tail — especially large MCP surfaces — is a direct input-token win with no loss of capability.
+ N MCP schemas
re-sent every turn
browser + MCP =
name+desc only
3What OpenAI needs in the request
tools = [
{"type": "namespace", "name":"crm", "description":"...",
"tools":[{"type":"function","name":"list_open_orders",
"defer_loading": true, "parameters":{...}}]},
{"type": "tool_search"}
]
Two modes: hosted (OpenAI searches the deferred tools you declared and returns the loaded subset in the same response) and client-executed (the model emits a tool_search_call; your app looks up and returns a tool_search_output echoing the call_id). Loaded tools become callable on later turns. OpenAI recommends grouping deferred functions into namespaces or MCP servers, each < ~10 functions.
4The greenfield gap
Unlike Programmatic Tool Calling, nothing here is subtly broken — it's simply absent:
| Needed | SDK today |
|---|---|
defer_loading flag on tools | none — to_responses_tool() always emits the full schema (tool.py:497) |
namespace grouping + tool_search injection | none (llm.py:1258) |
parse tool_search_call/tool_search_output | none (message.py:541) |
defer_loading marker + optional namespace grouping, inject the tool_search tool when any deferred tool is present (start with hosted mode — the simplest), preserve/replay the two new item types for store=false, gate on gpt-5.4+. Watch the interaction with PTC: deferred tools aren't available to a program until the model has loaded them. Tracked in #4083.4Quiz
Five questions to check you actually understood it — not trivia. Click an answer to see whether it's right and why.