Quick answer
How does tool calling work on LLMwithCrypto?
Send your functions in tools, in the OpenAI format. When the model wants one, LLMwithCrypto returns finish_reason: "tool_calls" with the function name and JSON arguments; your code runs it and sends the result back as a tool message. For structured replies, response_format: {"type": "json_object"} asks for valid JSON. Both work on the models that support them, as documented on 23 October 2026.
Which models support tools and JSON?
Streaming works on every model; tool calling and JSON output follow what each model itself supports.
Test your own schema on the model you plan to use before you depend on it. A model that does not support tools answers in plain text instead of calling the function; a model that does not support JSON mode returns a 400 error for response_format.
What is the loop?
Describe the functions
Each tool has a
name, adescriptionthe model reads to decide when to use it, andparametersas a JSON Schema.Send the conversation with tools
The model either answers in text, or stops with
finish_reason: "tool_calls"and one or more calls inmessage.tool_calls.Run each call
Parse
function.arguments(a JSON string), run your function, and never trust the arguments blindly: validate them like any user input.Send the results back
Append the assistant message, then one
toolmessage per call with itstool_call_idand the result as text. Call the API again; repeat until the model answers in text.
import json
import os
from openai import OpenAI
client = OpenAI(
base_url="https://llmwithcrypto.com/api/v1",
api_key=os.environ["LLMWITHCRYPTO_API_KEY"],
)
tools = [
{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Return the delivery status of an order.",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
},
}
]
def get_order_status(order_id):
return {"order_id": order_id, "status": "shipped", "eta": "2026-10-25"}
messages = [{"role": "user", "content": "Where is my order A-1042?"}]
while True:
resp = client.chat.completions.create(model="gpt-oss-120b", messages=messages, tools=tools, max_tokens=300)
msg = resp.choices[0].message
if not msg.tool_calls:
print(msg.content)
break
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_order_status(**args)
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})
What does a tool call look like in the response?
The assistant message has no text, a tool_calls array, and the choice ends with finish_reason: "tool_calls". The arguments come as a JSON string, not an object. The ids and counts below are illustrative.
{
"id": "chatcmpl-3c9d27e1",
"object": "chat.completion",
"created": 1792742400,
"model": "gpt-oss-120b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_7f31",
"type": "function",
"function": {
"name": "get_order_status",
"arguments": "{\"order_id\": \"A-1042\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 118,
"completion_tokens": 22,
"total_tokens": 140
}
}
How do I control when tools are used?
"tool_choice": "auto"(the default whentoolsis set): the model decides."tool_choice": "none": the model answers in text even though tools are listed."tool_choice": "required": the model must call at least one tool.{"type": "function", "function": {"name": "get_order_status"}}: the model must call that one.
Every tool definition is sent as input on each call, so long descriptions and many tools raise the input tokens. Keep descriptions short and send only the tools a step needs.
How do I get valid JSON back?
Set response_format to {"type": "json_object"} and describe the expected keys in the system message: JSON mode guarantees that the reply parses, not that it has the keys you want. Keep temperature low for stable output and check the parsed object in your code before using it.
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://llmwithcrypto.com/api/v1',
apiKey: process.env.LLMWITHCRYPTO_API_KEY,
});
const resp = await client.chat.completions.create({
model: 'gpt-oss-120b',
messages: [
{ role: 'system', content: 'Reply with a JSON object {"sentiment": "positive" | "negative" | "neutral", "reason": string}.' },
{ role: 'user', content: 'The delivery was late but support fixed it in an hour.' },
],
response_format: { type: 'json_object' },
temperature: 0.2,
max_tokens: 150,
});
const result = JSON.parse(resp.choices[0].message.content);
console.log(result.sentiment, '-', result.reason);
Tools and JSON: common questions
Do tool calls cost extra?
No fee of their own. The tool definitions, the call and the results you send back are all tokens, billed like any other. You pay per token from your balance: input and output tokens are counted by the model’s own tokenizer and charged at that model’s price per 1M tokens. A call that ends in an error costs nothing.
Can the model call several tools at once?
Some models return more than one call in tool_calls. Run them all and send one tool message per call before the next request.
Does the API run my functions?
No. The model only says which function to call and with which arguments; your code runs it. Nothing is executed on our side, and nothing of the exchange is stored: We do not store your prompts or the model’s answers: once a response is sent, its text is gone. Each call leaves one log line with the time, the account, the model and the token counts, deleted after 30 days.