Skip to main content
Tools work exactly as in the OpenAI SDK — Orbitrage just routes and traces the calls. Here’s a full ReAct loop you can run as-is.
import os, json, orbitrage
orbitrage.init(os.environ["ORBITRAGE_API_KEY"], user_id="customer_42")

from openai import OpenAI
client = OpenAI()

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

def get_weather(city):           # your real implementation
    return f"22°C and sunny in {city}"

messages = [{"role": "user", "content": "What's the weather in Tokyo?"}]

while True:
    resp = client.chat.completions.create(model="grok-4-fast", messages=messages, tools=tools)
    msg = resp.choices[0].message
    messages.append(msg)
    if not msg.tool_calls:
        print(msg.content)
        break
    for tc in msg.tool_calls:
        args = json.loads(tc.function.arguments)
        result = get_weather(**args)
        messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})

Managed tools — let Orbitrage run them

Don’t want to wire up a web-search or scrape API at all? Reference a managed tool by name and Orbitrage runs it server-side with our key, loops the result back to the model, and returns the final answer — no key, no tool loop on your side. Your own tools (like get_weather above) keep running on your side, in the same call.
resp = client.chat.completions.create(
    model="grok-4-fast",
    messages=[{"role": "user", "content": "Search the web: what's new with MCP? Cite a source."}],
    tools=["tavily_orbitrage"],     # managed — we run it. Just name it.
)
print(resp.choices[0].message.content)   # final answer, already includes the search

Mix managed + your own tools

Put both in one tools array. Orbitrage runs the managed ones server-side and hands your own tool calls back to you — in the same request.
tools = [
    "calculator_orbitrage",                          # managed — we run it
    "tavily_orbitrage",                              # managed — we run it
    {"type": "function", "function": {               # yours — you run it
        "name": "get_order_status",
        "description": "Look up an order by id.",
        "parameters": {"type": "object",
                       "properties": {"id": {"type": "string"}}, "required": ["id"]}}},
]

messages = [{"role": "user", "content": "Compute 1234*5678, then check order A-1009."}]
while True:
    resp = client.chat.completions.create(model="grok-4-fast", messages=messages, tools=tools)
    msg = resp.choices[0].message
    messages.append(msg)
    if not msg.tool_calls:               # managed calls already resolved server-side
        print(msg.content); break
    for tc in msg.tool_calls:            # only YOUR tools land here
        if tc.function.name == "get_order_status":
            messages.append({"role": "tool", "tool_call_id": tc.id, "content": "shipped"})
See Tools Gateway for the full catalog (web search, scrape, calculator, datetime, weather, …) and billing. Managed tools also work with pinned models including claude-sonnet-4-6. In the dashboard, the run shows each LLM hop, the tool definitions you sent, and which tools the model called (managed tools are badged via Orbitrage with their cost) — useful for spotting tool-selection drift.
Routing scores prompts with tools too: a request that offers many tools tends to route to a tool-strong model. Pin a model if you need a specific one.