# Tool calling

> Let the model call your functions with the OpenAI tools and tool_choice parameters.

Source: https://docs.serenityedge.ai/docs/tool-calling/

Tool calling lets the model ask your application to run a function and then continue the conversation with the result. Serenity Edge follows the OpenAI `tools` and `tool_choice` contract, so any client built for it works unchanged.

## How it works

1.  Describe your functions in `tools`, each with a JSON Schema for its arguments.
2.  If the model decides to call one, the response has `finish_reason: "tool_calls"` and the assistant message carries `tool_calls` with the function name and JSON-encoded arguments.
3.  Run the function, append the assistant message and a `tool` message with the result, and send the conversation again. The model then answers using the result.

## Example

### 1\. Declare the tool and send the request

```python
from openai import OpenAI
import json

client = OpenAI(base_url="https://api.serenityedge.ai/v1", api_key="YOUR_SERENITY_EDGE_API_KEY")

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

messages = [{"role": "user", "content": "What is the weather in Valencia today?"}]

response = client.chat.completions.create(model="orion-pro", messages=messages, tools=tools, tool_choice="auto")
message = response.choices[0].message
```

### 2\. Run the function and send the result back

```python
if message.tool_calls:
    messages.append(message)
    for call in message.tool_calls:
        args = json.loads(call.function.arguments)
        result = get_weather(**args)  # your own function
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

    final = client.chat.completions.create(model="orion-pro", messages=messages, tools=tools)
    print(final.choices[0].message.content)
```

The assistant message returned in step 1 looks like this:

```json
{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_3f2a9c",
      "type": "function",
      "function": {
        "name": "get_weather",
        "arguments": "{\"city\": \"Valencia\"}"
      }
    }
  ]
}
```

## Controlling tool use with `tool_choice`

| Value | Behaviour |
| --- | --- |
| `"auto"` (default when `tools` is set) | The model decides whether to call a tool. |
| `"none"` | The model never calls a tool. |
| `"required"` | The model must call at least one tool. |
| `{"type": "function", "function": {"name": "get_weather"}}` | The model must call that specific function. |

By default the model may return several tool calls in one response (`parallel_tool_calls: true`). Run them all and append one `tool` message per call, in any order, before sending the next request.

## Strict schemas

Set `"strict": true` on a function definition to guarantee that `arguments` matches your JSON Schema exactly. Strict mode requires `additionalProperties: false` on every object and every property listed in `required`. Use it when you parse arguments into typed structures; see [Structured outputs](https://docs.serenityedge.ai/docs/structured-outputs/) for the same mechanism applied to the final answer.

## Recommendations

-   Always validate `arguments` before use. Even in strict mode, treat them as untrusted input.
-   Keep function descriptions short and concrete. The model chooses tools from the description.
-   Return compact results in `tool` messages. Everything you send back counts as input tokens.
-   For long chains of calls, prefer `orion-pro`; see [Models](https://docs.serenityedge.ai/docs/models/).
