Skip to content

Responses API tool use

The Responses API uses OpenAI’s typed-output tool-call shape. The flow is:

  1. You send a request with tools defined.
  2. The model decides to call a tool. The response status is incomplete and output contains a function_call item.
  3. You execute the tool client-side and send the result back as a function_call_output input item, referencing the same call_id.
  4. The model continues with the result and emits a final message.

Function tools are defined in the Responses-API tool format (top-level name, description, parameters):

{
"model": "claude-sonnet-4-5-20250929",
"input": "What is the weather in San Francisco?",
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"location": { "type": "string" }
},
"required": ["location"]
}
}
],
"tool_choice": "auto"
}

This is the shape codex and openai-python’s client.responses produce.

Set store: true to persist the response server-side. The response includes conversation.id when store: true, which you can use for stateful continuation, or ignore it for a one-shot call.

Terminal window
curl -X POST https://api.kindo.ai/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $KINDO_API_KEY" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"store": true,
"input": "What is the weather in San Francisco?",
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": { "location": { "type": "string" } },
"required": ["location"]
}
}
]
}'
{
"id": "resp_abc123",
"status": "incomplete",
"incomplete_details": { "reason": "tool_use" },
"conversation": { "id": "conv_abc123" },
"output": [
{
"type": "function_call",
"call_id": "call_abc",
"name": "get_weather",
"arguments": "{\"location\":\"San Francisco, CA\"}"
}
]
}

status: "incomplete" with incomplete_details.reason: "tool_use" is the canonical signal that the model wants you to run a tool.

Kindo divergence from OpenAI spec: OpenAI’s published Responses API uses status: "completed" with a function_call output item when the model calls a tool. Kindo returns status: "incomplete" with incomplete_details.reason: "tool_use" instead. Stock OpenAI SDKs will see this divergence when consuming raw HTTP responses.

Run get_weather("San Francisco, CA") in your application. This is your code, not Kindo’s — function tools are by definition client-executed.

Terminal window
curl -X POST https://api.kindo.ai/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $KINDO_API_KEY" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"conversation": "conv_abc123",
"input": [
{ "type": "message", "role": "user", "content": "What is the weather in San Francisco?" },
{
"type": "function_call",
"call_id": "call_abc",
"name": "get_weather",
"arguments": "{\"location\":\"San Francisco, CA\"}"
},
{
"type": "function_call_output",
"call_id": "call_abc",
"output": "{\"temperature\":68,\"unit\":\"fahrenheit\"}"
}
],
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": { "location": { "type": "string" } },
"required": ["location"]
}
}
]
}'

The call_id must match the one from Step 2. Re-include the tools definition so the model sees the schema again. Re-include the prior input messages so the model has the context of the tool call. Alternatively, continue statefully — pass conversation or chain via previous_response_id (the prior turns are then loaded server-side). See Chat Actions extensions for the stateful continuation recipe.

{
"id": "resp_def456",
"status": "completed",
"output": [
{
"type": "message",
"role": "assistant",
"content": [
{ "type": "output_text", "text": "It's 68 °F in San Francisco." }
]
}
],
"output_text": "It's 68 °F in San Francisco."
}
ValueBehavior
"auto" (default)The model decides whether to call a tool.
"none"The model must produce a message; never a tool call.
"required"The model must call at least one tool.
{type: "function", name: "..."}The model must call exactly that function.
{type: "allowed_tools", mode: "auto", tools: [...]}Restricts the model to a subset of declared tools. Works for function, mcp, and kindo_* tools.

POST /v1/responses also accepts:

  • {type: "mcp", server_label: "<your-mcp-server>"} — MCP tools registered against your organization. Stateful path only: the server_label is resolved server-side against your organization’s integrations, so the request must set store: true or pass a conversation ID. A stateless request that includes an mcp tool is rejected with 400 unsupported_tool_type. Platform tools are available by default in stateful conversations that aren’t tied to an agent or a messaging app, whether or not the request names them, unless Platform was turned off in that conversation. Platform availability and your tool policy still apply. To keep them off everywhere, set them to Block in your tool approval settings.
  • {type: "kindo_<name>"} — individual Kindo-hosted tools (opt-in).
  • {type: "kindo_tools"} — sugar that expands to the full Kindo hosted-tool catalog.

Stock OpenAI built-in types (web_search, file_search, computer, shell, etc.) are forwarded verbatim and dispatched to the upstream model when supported.

See Chat Actions extensions for the full hosted-tool catalog and stateful flow patterns.