runaiicloud
ModelsAppsGPUsServerless GPUPricingReserveDocsConnectCompareEnterprise
Log inGet started
runaiicloud docs
status →
⌘⌘K
Get started
Quickstart
API reference
Authentication & API keysStreamingErrorsModels catalogFunction calling & tool useStructured outputs
Billing & limits
Pricing, metering & prompt cachingRate limits & tiers
Bring your own model →Blog ←Get an API key →Changelog
Authentication & API keysPricing, metering & prompt cachingQuickstartRate limits & tiersStreamingErrorsModels catalogFunction calling & tool useStructured outputs
docs/API reference/Function calling & tool use
On this page▸
Which models can call toolsDeclare a toolRunnable requestWhat comes backClose the loopStreaming tool callsResponses API (/v1/responses)What is not supported
API reference

Function calling & tool use

Declare tools on chat completions or the Responses API, read tool_calls back, and close the loop.


Which models can call tools

Tool use needs a tool-call parser in the serving recipe, and the catalog says which models have one: tools, tool_choice and parallel_tool_calls are declared in a model's supported_parameters only when its recipe parses tool calls. Check before wiring a tool loop into production:

curl https://api.runaii.cloud/v1/models

At the time of writing the live catalog declares a tool-call parser on one model only:

Model tools tool_choice parallel_tool_calls
glm-5.3 yes auto | none | required yes
deepseek-v4-flash not declared — —
qwen3.8-flash not declared — —

glm-5.3 reported is_ready: false when this page was written, and is_ready is a live flag — re-check it (and Console → Models) before sending tool traffic. On a model with no tool-call parser the engine ignores those parameters — it has nothing to parse tool calls with. Only declare tools on a model whose catalog entry declares them.

Declare a tool

Tools use the OpenAI shape on /v1/chat/completions — tools[], tool_choice and parallel_tool_calls are forwarded to the engine as sent:

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "Current weather for a city.",
    "parameters": {
      "type": "object",
      "properties": { "city": { "type": "string" } },
      "required": ["city"]
    }
  }
}
Parameter Accepted values
tools array of { "type": "function", "function": { "name", "description"?, "parameters"? } }
tool_choice "auto", "none", "required", or { "type": "function", "function": { "name": "get_weather" } }
parallel_tool_calls boolean — allow more than one tool call per turn

Runnable request

curl https://api.runaii.cloud/v1/chat/completions \
  -H "Authorization: Bearer $RUNAII_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3",
    "messages": [{"role": "user", "content": "What is the weather in Berlin?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Current weather for a city.",
        "parameters": {
          "type": "object",
          "properties": {"city": {"type": "string"}},
          "required": ["city"]
        }
      }
    }],
    "tool_choice": "auto"
  }'

What comes back

The model does not run your function — it returns the call it wants you to make. finish_reason is "tool_calls" and message.content is null for a pure tool turn:

{
  "id": "rq-...",
  "object": "chat.completion",
  "model": "glm-5.3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_...",
            "type": "function",
            "function": { "name": "get_weather", "arguments": "{\"city\":\"Berlin\"}" }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ]
}

The response also carries the standard usage object — the real token counts and the exact cost you were charged, with the same fields as any other call (see pricing). The tokens the model spends writing tool arguments are completion tokens like any other output.

Close the loop

Execute the function, then send the assistant turn back verbatim followed by one role: "tool" message per call, matched by tool_call_id:

{
  "model": "glm-5.3",
  "messages": [
    { "role": "user", "content": "What is the weather in Berlin?" },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_...",
        "type": "function",
        "function": { "name": "get_weather", "arguments": "{\"city\":\"Berlin\"}" }
      }]
    },
    { "role": "tool", "tool_call_id": "call_...", "content": "{\"temp_c\": 14, \"sky\": \"overcast\"}" }
  ]
}

role: "tool" is accepted alongside the rest of the OpenAI chat role set (system, user, assistant, developer, function). A message may carry tool_calls instead of content — that is how you feed an assistant turn back in.

Streaming tool calls

With "stream": true the call arrives as tool_calls deltas: the first chunk carries index, id, type and function.name, later chunks append function.arguments fragments, and the final chunk reports finish_reason: "tool_calls". Accumulate by index, then JSON.parse the joined arguments. The terminal usage chunk behaves exactly as in streaming — usage is only emitted when the client sets stream_options: {"include_usage": true}.

Responses API (/v1/responses)

The Responses dialect flattens the tool — name, description and parameters sit at the top level of the tool object, not nested under function:

curl https://api.runaii.cloud/v1/responses \
  -H "Authorization: Bearer $RUNAII_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3",
    "input": "What is the weather in Berlin?",
    "tools": [{
      "type": "function",
      "name": "get_weather",
      "description": "Current weather for a city.",
      "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
      }
    }],
    "tool_choice": {"type": "function", "name": "get_weather"}
  }'

tool_choice accepts "auto", "none", "required" or the named form { "type": "function", "name": "get_weather" }. The model's answer comes back as an output item, and you feed the result back as an input item — the endpoint is stateless, so resend the whole conversation:

{
  "id": "resp_...",
  "object": "response",
  "status": "completed",
  "model": "glm-5.3",
  "output": [
    {
      "id": "fc_...",
      "type": "function_call",
      "status": "completed",
      "call_id": "call_...",
      "name": "get_weather",
      "arguments": "{\"city\":\"Berlin\"}"
    }
  ]
}

Send the result back in the same input array — function_call echoes the call, function_call_output carries what your code returned:

{
  "model": "glm-5.3",
  "input": [
    { "role": "user", "content": "What is the weather in Berlin?" },
    { "type": "function_call", "call_id": "call_...", "name": "get_weather", "arguments": "{\"city\":\"Berlin\"}" },
    { "type": "function_call_output", "call_id": "call_...", "output": "{\"temp_c\": 14, \"sky\": \"overcast\"}" }
  ]
}

The usage block reports the real token counts and the exact cost, exactly like chat completions.

When the model emits only tool calls, output holds just the function_call item; a message item appears when there is visible text. Streamed, the same call arrives as response.output_item.added (with call_id and name), response.function_call_arguments.delta, response.function_call_arguments.done and response.output_item.done events.

What is not supported

  • Hosted tools. web_search, file_search, computer_use, code_interpreter and mcp are rejected with 400 unsupported_tool — use type: "function" tools, which are fully supported.
  • Tool loops are yours to run. The API never executes a tool; it returns the call and waits for you to send the result back.

On this page

Which models can call toolsDeclare a toolRunnable requestWhat comes backClose the loopStreaming tool callsResponses API (/v1/responses)What is not supported

← Previous

Models catalog

Next →

Structured outputs

runaiicloud

Serverless inference, dedicated GPUs, and training for open models. OpenAI- and Anthropic-compatible APIs.

© 2026 runaii

Platform

Model libraryAppsGPUsServerless GPUPricingToken-Max coding plansCompare providersDocs

Developers

ConnectCookbookCLIAgents / MCPUse casesTutorialsBlogFAQ

Company

EnterpriseStartupsAboutCareersTrust centerStatusSupportTermsPrivacySitemap