Skip to main content
Chat Completions API uses the OpenAI chat tool format: define tools, receive tool_calls, and return tool results as role: tool messages. Use this when you need tool calling but want to keep an existing chat-based client or agent stack.

Request Shape

from openai import OpenAI

client = OpenAI(
    base_url="https://api.naga.ac/v1",
    api_key="YOUR_API_KEY",
)

completion = client.chat.completions.create(
    model="gpt-4.1-mini",
    messages=[
        {
            "role": "user",
            "content": "What is the weather in Prague and should I bring a coat?",
        }
    ],
    tools=[
        {
            "type": "function",
            "function": {
                "name": "lookup_weather",
                "description": "Look up current weather for a city.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "city": {"type": "string"}
                    },
                    "required": ["city"],
                },
                "strict": True,
            },
        }
    ],
    tool_choice="auto",
)

print(completion.choices[0].message.tool_calls)

Assistant Tool Call

When the model decides to call a tool, the assistant message includes tool_calls.
{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_1",
      "type": "function",
      "function": {
        "name": "lookup_weather",
        "arguments": "{\"city\":\"Prague\"}"
      }
    }
  ]
}

Return Tool Results

Send tool results back as a role: tool message with the matching tool_call_id.
{
  "model": "gpt-4.1-mini",
  "messages": [
    {
      "role": "user",
      "content": "What is the weather in Prague and should I bring a coat?"
    },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_1",
          "type": "function",
          "function": {
            "name": "lookup_weather",
            "arguments": "{\"city\":\"Prague\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_1",
      "content": "{\"temperature_c\":7,\"raining\":true}"
    }
  ]
}
If you are continuing a larger workflow, keep any earlier assistant tool call and related context in the replayed message history. Some reasoning-capable models also return reasoning_details alongside tool calls. If you want continuity across turns, return that reasoning payload unchanged with the assistant message in the follow-up request. See Chat Completions Reasoning.

Streaming Behavior

When streaming is enabled, tool arguments arrive incrementally in delta.tool_calls[].function.arguments.

Caveats

  • the chat wire shape uses tool_calls, not function_call items
  • the follow-up tool result must be a role: tool message, not a function_call_output item
  • parallel_tool_calls is a request-level flag when you need to constrain parallel tool execution behavior

Common mistakes

  • sending tool results back in Responses format instead of chat message format
  • assuming the assistant will always produce final text in the same turn as the tool call
  • not buffering streamed tool_calls arguments until they are complete