Tool calling
Let a model ask your code to run a function, then give it the result.
You describe functions in tools. If the model decides to use one, it answers with finish_reason: "tool_calls" and a tool_calls list instead of (or beside) text. Your code runs the function, appends the result as a tool message, and calls the API again. Tool calling is supported on Z1, Z1 Code and H1; it was verified on all three.
curl https://api.tessen.ai/v1/chat/completions \ -H "Authorization: Bearer $TESSEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "z1", "max_tokens": 1024, "tool_choice": "auto", "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "Get the current weather for a city.", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"] } } }], "messages": [{"role": "user", "content": "What is the weather in Paris? Use the tool."}] }'import jsonimport osimport requests URL = "https://api.tessen.ai/v1/chat/completions"HEADERS = {"Authorization": f"Bearer {os.environ['TESSEN_API_KEY']}"}TOOLS = [{ "type": "function", "function": { "name": "get_weather", "description": "Get the current weather for a city.", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, },}] messages = [{"role": "user", "content": "What is the weather in Paris? Use the tool."}]first = requests.post(URL, headers=HEADERS, timeout=120, json={"model": "z1", "max_tokens": 1024, "tools": TOOLS, "tool_choice": "auto", "messages": messages})first.raise_for_status()message = first.json()["choices"][0]["message"] if message.get("tool_calls"): call = message["tool_calls"][0] arguments = json.loads(call["function"]["arguments"]) print("tool call:", call["function"]["name"], arguments) # Your code runs the tool. Here the result is fixed. messages.append({"role": "assistant", "content": message["content"] or "", "tool_calls": message["tool_calls"]}) messages.append({"role": "tool", "tool_call_id": call["id"], "content": json.dumps({"temperature_c": 18, "sky": "clear"})}) second = requests.post(URL, headers=HEADERS, timeout=120, json={"model": "z1", "max_tokens": 1024, "tools": TOOLS, "messages": messages}) second.raise_for_status() print(second.json()["choices"][0]["message"]["content"])else: print(message["content"])const url = "https://api.tessen.ai/v1/chat/completions";const headers = { Authorization: `Bearer ${process.env.TESSEN_API_KEY}`, "Content-Type": "application/json" };const tools = [{ type: "function", function: { name: "get_weather", description: "Get the current weather for a city.", parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] }, },}]; async function chat(body) { const response = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) }); if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`); return response.json();} const messages = [{ role: "user", content: "What is the weather in Paris? Use the tool." }];const first = await chat({ model: "z1", max_tokens: 1024, tools, tool_choice: "auto", messages });const message = first.choices[0].message; if (message.tool_calls?.length) { const call = message.tool_calls[0]; console.log("tool call:", call.function.name, JSON.parse(call.function.arguments)); // Your code runs the tool. Here the result is fixed. messages.push({ role: "assistant", content: message.content ?? "", tool_calls: message.tool_calls }); messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify({ temperature_c: 18, sky: "clear" }) }); const second = await chat({ model: "z1", max_tokens: 1024, tools, messages }); console.log(second.choices[0].message.content);} else { console.log(message.content);}- Describe the function
toolsis an array of{ type: "function", function: { name, description, parameters } }.parametersis a JSON Schema object. - Read the call
choices[0].message.tool_calls[0]hasid,function.nameandfunction.arguments— a JSON string you must parse. - Return the result
Append the assistant message (with its
tool_calls) and then a message withrole: "tool", the sametool_call_id, and the result as a string. - Ask again
The model answers using the result.
Notes
tool_choice: "auto"is verified. Other OpenAI values are accepted but not verified here.- Validate
argumentsbefore you act on them: the model produces them and can get them wrong. - The assistant message's
contentmay be empty or a short sentence when it calls a tool. - Tool definitions are sent with every request that uses them, so they add to
prompt_tokens.