Bridge by Wekoya / Docs / Chat

Tool calling (function calling)

Updated

Let the model use your code: look up an order, check a balance, book a slot, search your database. You describe the functions you have, the model asks for one when it needs it, you run it and send the result back, and the model answers with it. Bridge uses OpenAI's format, so any OpenAI SDK works as is, on every model except the preview N-ATLAS.

  1. 1. Describe your tools Send tools: a name, what it does, and its parameters.
  2. 2. The model asks The reply has tool_calls instead of an answer.
  3. 3. You run them Your code runs each one. The model never runs anything.
  4. 4. Send the results back One tool message per call; repeat until it answers.
import json, os
from openai import OpenAI

client = OpenAI(
    base_url="https://wekoya-api.wekoya.tech/v1",
    api_key=os.environ["WEKOYA_API_KEY"],
)

# 1. Describe what your code can do.
tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Look up a customer's order by its id",
        "parameters": {
            "type": "object",
            "properties": {"order_id": {"type": "string", "description": "e.g. 4021"}},
            "required": ["order_id"],
        },
    },
}]

def get_order_status(order_id):
    # Your real lookup goes here.
    return {"order_id": order_id, "status": "shipped", "eta": "Thursday"}

functions = {"get_order_status": get_order_status}
messages = [{"role": "user", "content": "Where is order 4021?"}]

for _ in range(5):  # a cap, so a confused model can't loop forever
    reply = client.chat.completions.create(model="gpt-6-luna", messages=messages, tools=tools)
    message = reply.choices[0].message
    if not message.tool_calls:
        print(message.content)  # 4. No more tools wanted: this is the answer.
        break
    # 2. The model asked for one or more tools. Keep its request in the conversation.
    messages.append(message.model_dump(exclude_none=True))
    for call in message.tool_calls:
        try:
            args = json.loads(call.function.arguments)
            result = functions[call.function.name](**args)  # 3. Run it.
        except Exception as error:
            result = {"error": str(error)}  # the model can recover from this
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

The rules that matter

Several tools at once

A reply can ask for more than one tool, for example an order status and the weather. Run each, and answer each with its own tool message before asking again. They can run at the same time.

Choosing when tools are used

Streaming

With "stream": true, tool calls arrive in pieces. Join them by index: the first piece carries the id and name, the rest add to arguments. Parse the arguments only when the stream ends.

import json, os
from openai import OpenAI

client = OpenAI(base_url="https://wekoya-api.wekoya.tech/v1", api_key=os.environ["WEKOYA_API_KEY"])
tools = [{"type": "function", "function": {"name": "get_order_status", "description": "Look up an order", "parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}}}]

stream = client.chat.completions.create(
    model="gpt-6-luna",
    messages=[{"role": "user", "content": "Where is order 4021?"}],
    tools=tools,
    stream=True,
)

calls = {}  # tool calls arrive in pieces, matched by index
for chunk in stream:
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta
    if delta.content:
        print(delta.content, end="", flush=True)
    for piece in delta.tool_calls or []:
        call = calls.setdefault(piece.index, {"id": "", "name": "", "arguments": ""})
        call["id"] = piece.id or call["id"]
        if piece.function and piece.function.name:
            call["name"] += piece.function.name
        if piece.function and piece.function.arguments:
            call["arguments"] += piece.function.arguments

for call in calls.values():
    print(call["name"], json.loads(call["arguments"]))

Which models, limits and cost