Tool calling
Keiro supports client-executed function tools on Responses, Chat Completions, and Messages. The model chooses a function and produces arguments; your application validates those arguments, runs the function, and sends the result back for the next model turn.
On this page 1 of 6
Keiro never executes your function code.
Define a function with Responses#
printf 'Keiro API key: '
IFS= read -rs KEIRO_BEARER
printf '\n'
curl -sS https://api.keirolabs.ai/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "eb1-preview",
"input": "What is the weather in Seoul?",
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Return the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"],
"additionalProperties": false
}
}
],
"tool_choice": "auto"
}' \
-H @- <<<"Authorization: Bearer $KEIRO_BEARER"
When the model selects the function, output contains a function_call item:
{
"type": "function_call",
"call_id": "call_...",
"name": "get_weather",
"arguments": "{\"city\":\"Seoul\"}"
}
Parse arguments as JSON, validate it against your own schema and authorization rules, execute the function, and retain call_id for the continuation.
Return the result#
Send the complete conversation state with a function_call_output item that uses the same call ID:
{
"model": "eb1-preview",
"input": [
{
"role": "user",
"content": "What is the weather in Seoul?"
},
{
"type": "function_call",
"call_id": "call_...",
"name": "get_weather",
"arguments": "{\"city\":\"Seoul\"}"
},
{
"type": "function_call_output",
"call_id": "call_...",
"output": "18 C, light rain"
}
]
}
Public eb1 clients should resend full conversation input for continuation; stateful previous_response_id continuation is not a portable eb1 contract. The next response can contain final text or another tool call. Bound the number of turns in your application and require explicit authorization for tools with side effects.
Surface shapes#
| Surface | Tool declaration | Model call | Tool result |
|---|---|---|---|
| Responses | tools[].type: function, with flat name and parameters | output[] item with type: function_call | input[] item with type: function_call_output and matching call_id |
| Chat Completions | tools[].function | choices[0].message.tool_calls[] | role: tool message with matching tool_call_id |
| Messages | tool with name and input_schema | tool_use content block | user tool_result content block with matching tool_use_id |
Keiro preserves call identity and requires function arguments to represent a JSON object on portable function-tool paths. A capability mismatch fails closed; do not silently resend the request without its tools.
Parallel calls and streaming#
Set parallel_tool_calls only when your application can execute and correlate more than one call from the same model turn. Each call keeps its own ID.
Streaming exposes the native tool-delta events for the selected surface. eb1 models can finish a tool call before streaming it, so tool arguments sometimes arrive as one assembled delta rather than many small fragments. Always assemble by call ID and wait for the surface's completed tool item before executing it.
Portability boundary#
Function tools are the documented cross-surface contract. Hosted web search is the documented hosted tool on OpenAI-format surfaces ({"type": "web_search"}, tool_choice: "auto", billed per search); see SDKs and CLI for the request shape and default behavior. Other hosted and provider-specific custom tool types can be account-, model-, or surface-specific; do not assume they are portable unless Keiro documents the exact tool type for your account.
JSON mode and JSON Schema structured output are separate features and are not currently supported by strict validation. A function's parameters schema is supported; a response-format schema is not the same contract.