FEATURE GUIDES
Function calling
Client-executed tools and stateless tool loops.
Define a client-executed tool
The model proposes a tool call. Your application validates it, authorizes the action, runs the tool, and sends its result back. The inference service never executes your function or generated commands.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://www.cheapinference.dev/v1",
apiKey: process.env.CHEAPINFERENCE_API_KEY,
});
const input: OpenAI.Responses.ResponseInput = [
{ role: "user", content: "Check stock for SKU-123." },
];
const result = await client.responses.create({
model: "gpt-5.4-mini", input, store: false,
tools: [{ type: "function", name: "get_stock",
description: "Read inventory for a product SKU.", strict: true,
parameters: { type: "object", properties: { sku: { type: "string" } },
required: ["sku"], additionalProperties: false } }],
tool_choice: "auto", parallel_tool_calls: false,
});Return a tool result
const outputs: OpenAI.Responses.ResponseInput = [];
for (const item of result.output) {
if (item.type !== "function_call") continue;
if (item.name !== "get_stock") throw new Error("Unknown tool");
const args = JSON.parse(item.arguments);
if (typeof args.sku !== "string") throw new Error("Invalid SKU");
// Replace this illustrative value with an authorized inventory lookup.
const stock = { sku: args.sku, available: 8 };
outputs.push({ type: "function_call_output", call_id: item.call_id,
output: JSON.stringify(stock) });
}
const followup = await client.responses.create({
model: "gpt-5.4-mini", store: false,
input: [...input, ...result.output, ...outputs],
});
console.log(followup.output_text);Preserve the original call_id. Multiple calls can appear in one response. Use a bounded tool loop, validate all arguments, and require user authorization for consequential actions. Each model request is metered separately.
Tool types and endpoint differences
| Endpoint / type | Supported behavior |
|---|---|
| Chat: function | Definitions under tools[].function; results use role=tool and tool_call_id |
| Responses: function / custom | Client executes; use complete call/result items |
| Responses: namespace | Client tools grouped under a namespace; nested hosted tools are rejected |
| Responses: local_shell / apply_patch | Model proposes work for the client; nothing executes on this service |
| Responses: shell | Only when environment.type is explicitly local |
| Hosted search / file search / interpreter / MCP / containers | Not enabled in this release |
tool_choice supports auto, none, required, or a model-supported specific-tool selector. Parallel execution is your responsibility, not a promise that side effects are safe to run concurrently. Keep full tool output history when making a stateless follow-up request.