Tool calling

Tool & function calling

Describe your functions, and a model that supports tools will ask you to run one. Oxyy translates the declaration into whatever each provider expects, so the same tools array works across OpenAI, Anthropic, Google, xAI and the rest.

ParameterTypeRequiredDescription
toolsarrayOptionalFunction declarations: {type: "function", function: {name, description, parameters}}, where parameters is a JSON Schema object.
tool_choicestring|objectOptionalHow freely the model may call a tool. One of:noneautorequired{type:"function",function:{name}} Default auto
parallel_tool_callsbooleanOptionalAllow more than one tool call per turn. Default true
import json, os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["OXYY_API_KEY"],
    base_url="https://api.oxyy.ai/v1"
)

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Current weather for a city.",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "Weather in Dhaka?"}]
response = client.chat.completions.create(
    model="gpt-5.5", messages=messages, tools=tools, tool_choice="auto"
)

call = response.choices[0].message.tool_calls[0]
args = json.loads(call.function.arguments)

# Run the tool yourself, then send the result back as a tool message.
messages.append(response.choices[0].message)
messages.append({
    "role": "tool",
    "tool_call_id": call.id,
    "content": json.dumps({"temp_c": 31, "sky": "humid"}),
})

final = client.chat.completions.create(model="gpt-5.5", messages=messages, tools=tools)
print(final.choices[0].message.content)
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.OXYY_API_KEY,
  baseURL: 'https://api.oxyy.ai/v1'
});

const tools = [{
  type: 'function',
  function: {
    name: 'get_weather',
    description: 'Current weather for a city.',
    parameters: {
      type: 'object',
      properties: { city: { type: 'string' } },
      required: ['city'],
    },
  },
}];

const messages = [{ role: 'user', content: 'Weather in Dhaka?' }];
const res = await client.chat.completions.create({
  model: 'gpt-5.5', messages, tools, tool_choice: 'auto',
});

const call = res.choices[0].message.tool_calls[0];
const args = JSON.parse(call.function.arguments);

messages.push(res.choices[0].message, {
  role: 'tool',
  tool_call_id: call.id,
  content: JSON.stringify({ temp_c: 31, sky: 'humid' }),
});

const final = await client.chat.completions.create({ model: 'gpt-5.5', messages, tools });
console.log(final.choices[0].message.content);

The tool-call turn

Response
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1700000000,
  "model": "gpt-5.5",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_abc123",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"Dhaka\"}"
            }
          }
        ],
        "refusal": null
      },
      "logprobs": null,
      "finish_reason": "tool_calls"
    }
  ],
  "usage": { "prompt_tokens": 61, "completion_tokens": 18, "total_tokens": 79, "cost": 0.00029 }
}
The loop. Append the assistant message as it came back, then one {role:"tool", tool_call_id, content}message per call, and send the whole conversation again. finish_reason is tool_callswhenever calls are present, even on providers that report stop. On reasoning models, send back any reasoning_details unmodified so the model's own thinking survives the round trip.
Function tools only. Oxyy runs no hosted tools of its own — there is no web search, code interpreter or file search to enable. Declare a function and run it in your application. Anthropic's server tools are the exception: they are forwarded to the provider untouched over the Anthropic SDK.