aiml docs
Guides

Tool calling

A full round trip: the model asks for a tool, you answer, it finishes.

Tool calling works as in the OpenAI Chat Completions format on every model the catalog marks tools: native; models without native tools are emulated when the capability matrix allows it, and the response carries an x-aiml-warnings: feature_degraded header.

cookbook/ts/tools.ts#L3-L25
import OpenAI from "openai";

const client = new OpenAI({ baseURL: (process.env.AIML_BASE_URL ?? "https://api.ai.ml") + "/v1", apiKey: process.env.AIML_API_KEY });
const model = process.env.AIML_MODEL ?? "openai/gpt-5-mini";
const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
  { type: "function", function: { name: "get_weather", description: "Current weather for a city", parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] } } },
];
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
  // "CALL_TOOL" makes the mock provider call a tool; real models decide themselves
  { role: "user", content: "What is the weather in Indore? CALL_TOOL" },
];

const first = await client.chat.completions.create({ model, messages, tools, tool_choice: "auto" });
const call = first.choices[0]?.message.tool_calls?.[0];
if (!call || call.type !== "function") throw new Error("expected a tool call, got " + first.choices[0]?.finish_reason);
console.log(`tool_call=${call.function.name} args=${call.function.arguments}`);

// answer the tool and ask for the final reply (tool_choice "none": no second round trip)
messages.push(first.choices[0]!.message);
messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify({ city: "Indore", temp_c: 31, sky: "clear" }) });
const second = await client.chat.completions.create({ model, messages, tools, tool_choice: "none" });
console.log(second.choices[0]?.message.content);
console.log(`final=${second.choices[0]?.finish_reason}`);

Notes:

  • The assistant message with tool_calls goes back verbatim, followed by one tool message per call. The gateway turns those into the target dialect's tool_result blocks when the provider speaks Anthropic.
  • tool_choice: "none" on the second turn asks for a final answer without another tool round. "required" and { "type": "function", "function": { "name": … } } are also supported; on providers that cannot force a tool the gateway degrades to auto and warns.
  • Streaming tool calls arrive as delta.tool_calls fragments with index; concatenate function.arguments per index.
  • CALL_TOOL in the prompt is a hint for the mock provider the cookbook runs against; real models decide on their own.