Relay mode
Your function tools run in relay mode: the gateway does not execute your functions. It declares your tool definitions to the model, returns the call the model wants to make, and stops. You run the tool and send the result back on the next turn. A typical loop:- Send a request with
tools(and optionallytool_choice). - The model responds with one or more tool calls and a tool-call finish reason instead of final text.
- Run each tool yourself and append the result to the conversation.
- Send the updated conversation back; the model continues (more tool calls, or a final text answer).
Chat Completions
Request —tools[] are function definitions; tool_choice is
auto (default), none, required, or { "type": "function", "function": { "name": "..." } }.
tool_calls and finish_reason is
tool_calls. Each call’s function.arguments is a JSON-encoded string.
tool message
whose tool_call_id matches, then send the conversation again:
delta.tool_calls[] fragments. The first
fragment for a call carries id, type, and function.name; later fragments
stream function.arguments text. The index field correlates fragments of the
same call.
Responses API
Show request format
Show request format
Request — Responses flattens the function fields onto each tool. Response — the model emits a Returning the result — resend the prior input and output items, then add a Streaming — a
tool_choice
is auto / none / required / { "type": "function", "name": "..." }.function_call output item with a call_id and
a JSON-string arguments:function_call_output referencing the same call_id. Responses is stateless; sending only the result loses the conversation:response.output_item.added event opens the function_call
item, response.function_call_arguments.delta events stream the argument text,
and response.function_call_arguments.done closes it.Messages (Anthropic)
Show request format
Show request format
Request — Response — a Returning the result — send a Streaming — the
tools[] use input_schema; tool_choice is { "type": "auto" },
{ "type": "any" }, { "type": "tool", "name": "..." }, or { "type": "none" }.
(A bare claude-... model id routes to Anthropic; any provider/model id also
works here — see SDKs & integrations.)tool_use content block (with a parsed input object) and
stop_reason: "tool_use":user turn containing a tool_result block
referencing the tool_use_id:tool_use block opens with a content_block_start, its input
streams as content_block_delta events of type input_json_delta
(partial_json), and closes with content_block_stop.Across all three surfaces, arguments arrive as JSON text (a string for
OpenAI-style calls, streamed
partial_json for Anthropic). Parse them yourself
before running the tool, and tolerate empty/partial fragments while streaming.Images in tool results
A tool that returns an image can hand it straight to the model — the image reaches the model instead of being flattened to text. Each surface uses its own content part inside the tool result:user
message placed immediately after the whole tool-result group, so parallel tool
calls stay intact.
Sending an image to a model whose input_modalities explicitly exclude image
returns 400 invalid_request_error rather than silently dropping it. A model
that declares no modalities at all is unverified, not text-only, and still
accepts images.
Gemini thought signatures
Gemini 3 models attach an opaque signature to the first function call of each step and reject the tool-result turn unless it comes back verbatim. The gateway round-trips it for you: on Chat Completions the tool call carriesextra_content.google.thought_signature (Google’s OpenAI-compat mapping — in
streaming it rides a tool_calls fragment), and on the Responses API the
function_call item carries the same extra_content field. Send the tool
call back exactly as you received it — clients that echo the assistant
message unchanged preserve this context. Check that your framework does not strip unknown fields. The Gemini-native endpoint uses Google’s own Part.thoughtSignature
unchanged.
Tool calls from another model. Gemini 3 also rejects any tool call in the
history that carries no signature at all — the case when you switch an ongoing
session to Gemini, synthesise a call yourself, or use a client that strips
unknown fields. The gateway marks those calls with Google’s documented
skip-validation sentinel so the turn is accepted; a real signature you send is
always preserved byte-for-byte and never replaced.
Mistral on Azure Foundry
Mistral’s serving stack on Foundry requires tool-call ids to be exactly nine alphanumeric characters, and requires every tool to carry adescription. An
OpenAI-style call_abc123 or an Anthropic-style toolu_01ABC from an earlier
model would be refused. The gateway rewrites ids consistently across the request
(each id and the tool_call_id referring to it get the same value) and supplies
an empty description when you omit one, so a tool history built against any
other provider replays unchanged. Ids in the response are the ones the provider
minted; your own ids are never rewritten on the way back.
Provider-executed search
Search the web or X with an xAI model
Search the web or X with an xAI model
On Responses, supported xAI models can run Send this body to
web_search and x_search on the provider’s server. Unlike your function tools, these searches do not need an application round trip.POST /v1/responses. Search invocations add a $0.005 charge each on top of token usage for gateway-paid requests. usage.server_side_tool_calls reports invocations when present; one request can use more than one search.These native searches execute only on xAI routes. On other providers they are filtered out; tool_choice: "required" returns 400 if no executable tools remain. Do not assume that an answer used search just because your request included a search tool. Code execution is not supported.
