How hosted tools workLink to this section
Five rules describe every hosted tool. They exist so that a request cannot be quietly rewritten behind your back.
- Listing is not execution. Declaring
web_searchadvertises it. With the defaulttool_choice: auto, the model chooses whether to call it — the platform never searches before a model call. - The model authors the arguments. Even a forced
tool_choiceonly constrains the model’s next call; the query or URL is always model-authored, never a copy of your raw message. - One loop, one terminal. Tool activity is an item on the way to the assistant answer. The same stream continues after each tool round and ends exactly once.
- Zero results is a valid outcome. An empty search is reported as an empty search, not an error and not a reason to silently try another engine.
- Failures stay typed. A tool that cannot run under your policy fails before it is dispatched, instead of quietly running with fewer constraints.
web_searchLink to this section
The model searches the web when it judges that the question needs current information. You observe each call as a web_search_call item with its status and results.
{
"model": "openai/gpt-5.5",
"input": "Which of these providers shipped a new reasoning model this week?",
"tools": [
{ "type": "web_search" }
]
}
| Field | Type | What it does |
|---|---|---|
typerequired | "web_search" | web_search_preview is accepted as the same operation. |
engine | string | Which engine executes the search. Omit for auto. See the engine table below. |
filters.allowed_domains | string[] | Domains that may be used as sources. Up to 100 entries. |
filters.blocked_domains | string[] | Domains that must not be used. A blocked domain wins over an allowed match, including subdomains. Up to 100 entries. |
external_web_access | boolean | false requires cache/index-only retrieval: engines that would fetch the live web are not used for that request. |
user_location | object | {"type":"approximate","country":"HK"} for locality. Only country is honored; city, region, and timezone constraints are not supported and the request is refused before any search runs. |
search_context_size | "low" | "medium" | "high" | How much retrieved context to give the model. |
Engines
| engine | search | fetch | Notes |
|---|---|---|---|
auto | Yes | Yes | Default. Eligible native execution first, then managed engines that can honor your policy. |
native | Yes | Yes | Strict: only proved provider-native execution on the model actually serving the request. |
parallel | Yes | Yes | Managed search and page retrieval. |
exa | Yes | Yes | Managed search and page retrieval, including cache-only retrieval. |
firecrawl | Yes | Yes | Managed search and page retrieval, including cache-only retrieval. |
perplexity | Yes | No | Search only. Domain filters are limited to 20 domains. |
brave | Yes | No | Search only. |
tavily | Yes | Yes | Managed search and page retrieval. |
anysearch | Yes | Yes | Managed search and page retrieval. |
A named engine is strict — if it cannot execute the request under your policy, the request fails instead of silently falling back. auto may fall back only among engines that can honor the policy you set. Also accepted on the declaration: search_content_types (["text"]) and return_token_budget ("default" or "unlimited").
web_fetchLink to this section
web_fetch opens one URL that the model chose and returns page content to the model. It is a hosted extension with its own declaration; you observe it as a web_search_call with an open_page action.
{
"model": "openai/gpt-5.5",
"input": "Read https://example.com/pricing and list the plans.",
"tools": [
{ "type": "web_fetch", "engine": "firecrawl" }
]
}
web_fetchaccepts onlytypeandengine. Source filters are inherited from theweb_searchdeclaration in the same request.- Pages are bounded (1 MiB per returned page) and extracted as clean markdown before they reach the model.
- The observation is a
web_search_callwhose action is{"type":"open_page","url":…}. There is no inventedweb_fetch_callitem. - A fetch engine that cannot satisfy a requested constraint (for example cache-only retrieval) is not used for that call.
tool_searchLink to this section
tool_search lets the model load tool definitions it was not given up front. The platform can execute the discovery over the tools you declared, or your client can execute it — and the choice is explicit.
// Platform executes the discovery (default):
{ "type": "tool_search" }
// Your client executes it and returns the picked tools:
{ "type": "tool_search", "execution": "client" }
- Platform execution produces a
tool_search_calland a separatetool_search_outputcarrying the loaded definitions, then continues with those tools available. Client execution emits only the call; you return the output with the samecall_id. - Marking a customer function with
defer_loading: truedoes not by itself turn on platform discovery — listtool_searchas well if you want it. - A function literally named
tool_searchis your function, not the hosted operation. A request cannot list both.
datetimeLink to this section
datetime gives the model deterministic awareness of the current date and time with no external provider call — useful for relative dates such as “next Tuesday”.
{
"model": "openai/gpt-5.5",
"input": "When is the next release train if releases ship every other Tuesday?",
"tools": [
{ "type": "datetime", "timezone": "Asia/Hong_Kong" }
]
}
- The timezone is an optional IANA name such as
Asia/Hong_Kong; it defaults toUTC. - Execution happens inside the platform with no external API call, so it adds no tool round trip to a provider.
What you observeLink to this section
Tool activity appears on the same response and the same stream as everything else. On a streaming request, each call reports its progress before the answer continues.
event: response.web_search_call.in_progress
event: response.web_search_call.searching
event: response.web_search_call.completed
data: {"type":"response.web_search_call.completed","item":{
"type":"web_search_call","status":"completed",
"action":{"type":"search","query":"…"},"results":[…]}}
# then the assistant continuation, still the same request:
event: response.output_text.delta
event: response.completed
- Non-streaming responses carry the same items inside
output, in order. - A completed search may add URL citations to the assistant text; the sources it used can be requested with the
includefield. - Tool results are evidence for the model — they are never rewritten into instructions, and they never end the turn on their own.
SamplesLink to this section
A complete request with search and fetch declared, and a streaming client that reacts to search events.
curl -N https://api.models.sylphx.ai/v1/responses \
-H "Authorization: Bearer $SYLPHX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.5",
"input": "What changed in the latest release? Cite the pages you used.",
"tools": [
{
"type": "web_search",
"engine": "auto",
"filters": { "allowed_domains": ["example.com"] },
"search_context_size": "medium"
},
{ "type": "web_fetch", "engine": "exa" }
],
"stream": true
}'
Tool failures surface on the same typed error envelope as everything else — see errors and retries.