Function calling (type: "function") — OpenAI
Status: DOCUMENTED · LIVE_VERIFIED (2026-09-18, gpt-5.4-nano on POST /v1/responses; gpt-4.1-nano on POST /v1/chat/completions)
Sources: https://developers.openai.com/api/docs/guides/function-calling · https://developers.openai.com/api/docs/guides/async-tool-calling · https://developers.openai.com/api/reference/resources/responses/methods/create · openapi-master.yaml FunctionTool, FunctionToolCall, FunctionCallOutputItemParam, ToolChoiceParam, ParallelToolCalls
Last verified: 2026-09-18
Definition (Responses API)
| Field | Type | Req. | Notes |
|---|---|---|---|
type |
"function" |
yes | |
name |
string | yes | ^[a-zA-Z0-9_-]+$, ≤ 128 chars (NamespaceTool inner definition) |
description |
string | null | no | drives when the model calls it |
parameters |
JSON Schema object | null | yes (spec) | injected into the system message → billed as input tokens |
strict |
boolean | null | yes (spec, nullable) | Responses: omitted = best-effort strict; Chat Completions: default false |
output_schema |
JSON Schema | null | no | describes the JSON encoded in string outputs (used by programmatic tool calling) |
async |
boolean | no | GPT-6 Astra+: model keeps working while the tool runs (pair with a wait tool + task_handle) |
defer_loading |
boolean | no | load through tool_search |
allowed_callers |
["direct"|"programmatic"] |
no | who may invoke: model directly and/or a program item |
Chat Completions shape: {"type":"function","function":{"name","description","parameters","strict"}}; forced choice {"type":"function","function":{"name":…}}.
Strict mode (live)
additionalProperties:false + every property in required are mandatory; sending a strict schema without additionalProperties → HTTP 400 invalid_request_error, code: invalid_function_parameters, param: tools[0].parameters (message: "'additionalProperties' is required to be supplied and to be false"). Strict schemas are cached and not ZDR-eligible; fine-tuned models lose strict mode when several functions are called in one turn.
Items
Output item function_call:
{"id":"fc_…","type":"function_call","status":"completed","call_id":"call_…","name":"get_weather","arguments":"{\"city\":\"Paris\"}"}Optional fields: namespace (when defined inside a namespace tool — observed live), caller ({type:"direct"} | {type:"program", caller_id}), async.
Input item function_call_output: {"type":"function_call_output","call_id":"call_…","output": "<string>" | [content parts]} (optionally name, namespace, caller).
Reasoning models: pass the reasoning items back with the outputs when not using previous_response_id.
tool_choice
| Shape | Effect | Live |
|---|---|---|
"none" / "auto" (default) / "required" |
no tool / model decides / ≥ 1 tool call | required verified |
{"type":"function","name":"get_weather"} |
force this function | verified |
{"type":"allowed_tools","mode":"auto"|"required","tools":[{"type":"function","name":…}, {"type":"mcp","server_label":…}, …]} |
restrict to a subset without changing tools (keeps prompt cache) |
verified (required, 2 tools → only get_weather called) |
{"type":"custom","name":…}, {"type":"mcp","server_label", "name"}, {"type":"<hosted tool type>"}, {"type":"shell"}, {"type":"apply_patch"}, {"type":"programmatic_tool_calling"} |
other tool families | see their pages |
parallel_tool_calls (default true): set false for ≤ 1 call per turn. GPT-5+ can batch several function calls in one turn even when built-in tools are present, but built-in tools are never part of that batch.
Streaming (live sequence, forced call)
response.created → response.in_progress → response.output_item.added (item function_call, arguments: "") → response.function_call_arguments.delta × N (delta, item_id, output_index, obfuscation) → response.function_call_arguments.done (arguments) → response.output_item.done → response.completed.
Namespaces
{"type":"namespace","name":"weather","description":"…","tools":[<function|custom>…]} groups tools; resulting calls carry "namespace":"weather". Deferred loading (defer_loading) applies to the inner tools. Verified live on gpt-5.4-nano (tool_choice: "required").
Limits & guidance (docs)
- Soft target < 20 functions available at turn start; combine sequential functions; don't ask the model for values you already know.
- Definitions count against context and are billed as input tokens; consider fine-tuning to shrink them.
- GPT-6 Astra requires the Responses API for tool calling.
- Async tool calling: GPT-6 Astra and later; don't combine with parallel tool calls in multi-agent mode.
Live evidence (sanitized, tmp-live/tools/)
| Probe | Status | Result |
|---|---|---|
| forced call | 200 | function_call {"city":"Paris"}; usage 50 in / 18 out |
round trip (previous_response_id + function_call_output) |
200 | message |
| stream | 200 | 11 events, sequence above |
| strict invalid schema | 400 | invalid_function_parameters |
allowed_tools + parallel_tool_calls:false |
200 | 1 call |
| namespace | 200 | function_call.namespace = "weather" |
chat completions (gpt-4.1-nano) |
200 | choices[0].message.tool_calls[0].function, finish_reason: "stop" (forced choice) |
Examples: examples/openai/tools/function-calling/ (sh/py/ts, all LIVE_VERIFIED). Tests: tests/openai/test_tools.py. Loop patterns: tool-loop.