cheapinference.dev
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 / typeSupported behavior
Chat: functionDefinitions under tools[].function; results use role=tool and tool_call_id
Responses: function / customClient executes; use complete call/result items
Responses: namespaceClient tools grouped under a namespace; nested hosted tools are rejected
Responses: local_shell / apply_patchModel proposes work for the client; nothing executes on this service
Responses: shellOnly when environment.type is explicitly local
Hosted search / file search / interpreter / MCP / containersNot 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.