Let the model ask your code to do things, with OpenAI's tools API. It works with yahoobot-1 only, on the OpenAI-compatible endpoint, with and without streaming.
Tool calling is OpenAI’s tools API, on yahoobot-1 only: israelbot-1 answers 400 tools_not_supported to any request that uses it. Tools that put their instructions in the prompt (Cline and Roo Code by default) don’t need any of this and work on text alone.
1. Describe your tools and ask:
{
"model": "yahoobot-1",
"messages": [{ "role": "user", "content": "What's the weather in Haifa?" }],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
}],
"tool_choice": "auto"
}2. The model answers with a call instead of text:
{
"choices": [{
"index": 0,
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "call_9a3f",
"type": "function",
"function": { "name": "get_weather", "arguments": "{\"city\":\"Haifa\"}" }
}]
}
}]
}3. Run it, and send the result back with the assistant message exactly as it came, then one tool message for each call:
{
"model": "yahoobot-1",
"tools": [ ...the same tools... ],
"messages": [
{ "role": "user", "content": "What's the weather in Haifa?" },
{ "role": "assistant", "content": null, "tool_calls": [
{ "id": "call_9a3f", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Haifa\"}" } }
] },
{ "role": "tool", "tool_call_id": "call_9a3f", "content": "31C and sunny" }
]
}The model then answers in words (finish_reason: "stop"), or asks for another call. When streaming, a call arrives as delta.tool_calls pieces: the first has the id and function.name, and the rest add to function.arguments, which is a JSON string in fragments, as OpenAI’s does. They are passed through unchanged.
| Rule | Detail |
|---|---|
| tools | Function tools only: {"type":"function","function":{...}}. Up to 128 of them. An empty list counts as no tools. |
| Tool names | 1 to 64 letters, digits, underscores or dashes. Unique. |
| description | Up to 4,096 characters. |
| parameters | A JSON Schema object, up to 32,768 bytes each. With none, a tool takes no arguments. "strict" is ignored. |
| tool_choice | "none", "auto", "required", or {"type":"function","function":{"name":"..."}} naming one of your tools. Ignored when there are no tools. |
| parallel_tool_calls | true lets the model call several tools in one turn; false asks for one at a time. Left out, the model decides. |
| Earlier calls | Assistant messages may carry tool_calls (each with an id of up to 64 characters, a name, and arguments as a string of up to 200,000), with content null or text. |
| tool messages | Each needs the tool_call_id of a call in an earlier assistant message, or the request is refused (400 invalid_tools). The content is text (a string, or text parts). |
| functions, function_call | The older API. Refused with a 400 that points to tools and tool_choice. |
The arguments are the model’s. They are not checked against your schema: parse them, validate them, and handle bad JSON, as with any model. Tool schemas, calls and results count toward your prompt size and your daily tokens.
With "stream": true a call arrives as delta.tool_calls pieces, as OpenAI's do. The first piece has the index, id, type and function.name; the rest add to function.arguments, a JSON string in fragments that you join before parsing. The last chunk has finish_reason: "tool_calls". They are passed through as the model wrote them.
data: {"choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"index":0,"id":"call_9a3f","type":"function","function":{"name":"get_weather","arguments":""}}]},"finish_reason":null}], ...}
data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"city\":"}}]},"finish_reason":null}], ...}
data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"Haifa\"}"}}]},"finish_reason":null}], ...}
data: {"choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}], ...}
data: [DONE]tool_choice to require one, and ignore a call to a name you don’t have.tool_calls in the conversation you send back, with its tool results after it; a tool message with no matching call is refused.Errors are listed under Errors: invalid_tools for a malformed tool or call, tools_not_supported for israelbot-1.