How to Migrate JSON Tool Calling After the OpenAI DevDay 2026 API Update
Change the write-back before you change the model id. If the target is gpt-6-astra or gpt-6.1-sol, tool calling leaves Chat Completions and uses the Responses API. A hop that only classifies or routes can move to the Decisions API, public beta since 6 October. The lookup stays lookup_order. The model only fills JSON. The host runs it.
Before you read
| Object | Official fact | What changes in the migration |
|---|---|---|
| Endpoint | Astra and GPT-6.1 Sol tool calls use Responses. Sol and Luna can call functions on Chat Completions only when reasoning_effort is none | Move to POST /v1/responses, or keep none on purpose |
| Tool object | On Responses, name sits beside type. Omitting strict tries strict mode, then falls back and marks strict: false | Set strict explicitly. The host still validates |
| Write-back | function_call and function_call_output share a call_id. async: true does not make the model run the tool | Replace role:tool with function_call_output |
| Routing | Decisions went public beta on 2026-10-06. Only gpt-6-luna. A choice does not run a tool | Move only the hop that picks an enum |
Facts from the official docs as of 2026-10-08: Using GPT-6, Migrate to the Responses API, Decisions, Async tool calling. Order A-1042 is fictional. Probabilities in the Decisions sample are illustrative.
Change the write-back shape, then the model id
After DevDay, the migration is a field change. It is not another essay on what an agent is. The official notes come down to four lines. First, if the target model is gpt-6-astra or gpt-6.1-sol, tool calling moves to Responses. Those two can still send Chat Completions requests that do not use tools. gpt-6-sol and gpt-6-luna can call functions on Chat Completions only when reasoning_effort is none. Reasoning plus tools uses Responses. Second, the tool name moves out of a nested function object and sits beside type. Third, the write-back id moves from tool_calls[].id to call_id. Fourth, a hop that only classifies or routes can move to Decisions. Decisions does not run a tool.
- Astra / GPT-6.1 Sol: tool calling leaves
/v1/chat/completions. On Responses the effort field isreasoning.effort. - Flatten the definition and set strict. Chat Completions is non-strict by default. Responses tries strict mode when
strictis omitted. - Split routing from the lookup. A
choicereturns an enum. The lookup stayslookup_order.
What shipped on 29 September: what DevDay 2026 shipped. How Responses and the Agents API differ as entry points: how the Agents API and Responses differ. This piece does not rewrite those two. It only maps the fields in an existing JSON tool-calling loop.
Name the call your code reads today
On a Chat Completions reply, one call looks like this. The id is outside. The name is inside function. arguments is a string. Fictional order — no real secrets:
{
"id": "call_3c91",
"type": "function",
"function": {
"name": "lookup_order",
"arguments": "{\"order_id\":\"A-1042\"}"
}
}
A Responses tool puts name beside type. Do not omit strict. If you do, Responses tries strict mode. An incompatible schema falls back, and the returned tool shows strict: false. To keep non-strict behavior, set false. The host still validates arguments before it runs:
{
"type": "function",
"name": "lookup_order",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
},
"required": ["order_id"],
"additionalProperties": false
}
}
The write-back keys off call_id
The model emits a function_call item, not a tool_calls array. Point the parser at these four fields:
{
"type": "function_call",
"call_id": "call_3c91",
"name": "lookup_order",
"arguments": "{\"order_id\":\"A-1042\"}"
}
The host parses arguments, checks Schema, runs lookup_order, and writes back on the same call_id. A failure is an object inside the string too. If you replay history by hand, send the previous reasoning items and the function_call with the result. Do not send the result alone. previous_response_id is the shorter path:
{
"type": "function_call_output",
"call_id": "call_3c91",
"output": "{\"order_id\":\"A-1042\",\"status\":\"paid\"}"
}
A slow tool can set async: true on the definition. The docs: the model may keep reasoning, or answer parts that do not depend on that result; the call item echoes async: true; you later submit function_call_output with the original call_id. The host still runs the tool. Built-in tools and programmatic tool calling cannot use async. In multi-agent mode, do not combine async tools with parallel tool calls. The docs name GPT-6 Astra and later models.
Five loops. Do not merge them into one upgrade
Migrate by the write-back you already have. Different object names need different parsers:
| Loop you have | Where it goes |
|---|---|
| Chat Completions + tools, target Astra or GPT-6.1 Sol | Move to POST /v1/responses. Map tool_calls[].id to call_id. Lift name out of function. |
| Chat Completions + tools, staying on gpt-6-sol or gpt-6-luna | You can stay only while reasoning_effort is none. Reasoning plus tools moves to Responses. |
| Already a Responses function_call | Keep the loop. Swap the model id. Astra and GPT-6.1 Sol do not support none; use low. When effort is not none, drop temperature, top_p, and top_logprobs. |
| A tool that only returns lookup / hold / escalate | Move that hop to POST /v1/decisions on gpt-6-luna. The lookup stays a function_call. |
| An Agents API session | Stay on Agents if you want the managed harness. The write-back stays turn_id, not function_call_output. |
The routing hop uses a Decisions choice. The request follows the 6 October public-beta shape. The order is fictional. Do not POST the homemade answer contract from the 30 September piece to /v1/decisions:
{
"model": "gpt-6-luna",
"input": "Order A-1042 is paid. What should the host do next?",
"questions": [{
"type": "choice",
"name": "next_step",
"instructions": "Pick the next host action. Do not invent a tool name.",
"choices": [
{ "value": "lookup", "description": "Read the order. No refund." },
{ "value": "hold", "description": "Stop and wait." },
{ "value": "escalate", "description": "Hand the case to a person." }
]
}]
}
The sample reply uses the official choice field names. The probabilities are fictional. The host calls lookup_order only after choice is lookup. hold stops. escalate goes to a person. A refusal does not call the tool. You pick the threshold. Images must be inline base64 data URLs. HTTPS image URLs and file_id are not accepted on this endpoint:
{
"answers": [{
"type": "choice",
"name": "next_step",
"choice": "lookup",
"probabilities": [
{ "value": "lookup", "probability": 0.91 },
{ "value": "hold", "probability": 0.05 },
{ "value": "escalate", "probability": 0.04 }
],
"confidence": 0.88
}]
}
Ultrafast is service_tier set to ultrafast on gpt-6-astra. It supports US data residency and global processing only, not EU or other regional endpoints, and it does not change tool JSON. GPT-6.1 Sol Ultrafast was still described as coming in the 29 September recap. This piece does not call it shipped. On 29 September the Agents API added Computer Use in an OpenAI-hosted browser. Your application still handles site approvals and sign-in. That is not a reason to replace Responses function_call_output. Misalignment monitoring can alert or stop a conversation. When a turn stops, do not blindly replay the same tool call.
Six steps, then flip traffic
Do not start from turning on Ultrafast. Write the write-back:
- Name the current write-back. It is
role: toolplustool_call_id, orfunction_call_output, or an Agentsturn_id. Do not share one parser across the three. - Pick the endpoint. Astra and GPT-6.1 Sol tool calls move to
POST /v1/responses. Sol and Luna can stay on Chat Completions only withreasoning_effortset tonone. - Flatten the tool and set strict. If the schema uses a form strict mode rejects, set
strict: falseand keep the host check. A lookup accepts onlyorder_id. - Align call_id and drop sampling params.
argumentsstays a string. On Astra and GPT-6.1 Sol, replacenonewithlow. When effort is not none, removetemperature,top_p, andtop_logprobs. On Chat Completions also removelogprobs. On Responses, removemessage.output_text.logprobsfrominclude. Coming from GPT-5.5 or earlier, replaceprompt_cache_retentionwithprompt_cache_options.ttlset to30m. To change effort mid-conversation, send aconfiguration_updateitem and leave request-levelreasoning.effortunchanged. - Move only the enum hop to Decisions. The model is
gpt-6-luna. The host mapslookuptolookup_order. Addasync: trueonly for a slow tool, and write back on the originalcall_id. - Diff the two JSON payloads, then flip traffic. Schema-check
argumentsandanswers[].choice. If they do not match, do not swap the model id.
How Schema is a gate: Agents API + JSON Schema. Why that gate cannot live only in the prompt: why AI needs JSON Schema. The Agents write-back shape: Agents API tool JSON.
Before you flip traffic, spread three JSON objects
Most failures are a mismatched id, a name still nested under function, or a choice treated as an order that was already looked up.
- format the old tool call beside the new function_call, then Schema validate whether
argumentsandanswers[0].choicepass the gate. - Use JSONPath extract for
$.call_id,$.name, and$.answers[0].choice. - JSON Diff the payload before and after the move. Fix
call_idbefore you rewrite the prompt. - Check that
call_3c91is the same id on the call and onfunction_call_output. - Do not paste orders, tokens, or repo paths into a public formatter. JSONSort runs in the browser.
If those three objects rebuild against Schema, the migration is done. Ultrafast does not replace that check.
Common traps
- Treating Decisions as the new tool-calling API. It returns a
choice, aprobability, or ascore. Tool arguments still use Responses function calling. An object that follows your own schema uses Structured Outputs on Responses. - Leaving the nested function object. Responses does not read the old
function.name. The name sits beside type. - Omitting strict and expecting non-strict. Responses tries strict mode, then falls back and marks
strict: falsewhen the schema cannot comply. Write the behavior you want. Keep the host check. - Leaving none or temperature on Astra or GPT-6.1 Sol. Those models do not support
none. GPT-6.1 Sol also does not supportminimal. Uselow. When effort is not none, drop the sampling params. - Moving a Responses loop into the Agents API for Computer Use. The 29 September add-on is a hosted browser. Approvals stay in your app. The Agents write-back is
turn_id. - Reading async: true as the model running the tool. The host still runs it and tracks pending work. Write back later on the original
call_id.
FAQ
Do I have to leave Chat Completions?
If the request uses tools and the model is gpt-6-astra or gpt-6.1-sol, move those calls to Responses. Chat Completions can still carry requests without tools on those models. gpt-6-sol and gpt-6-luna can call functions on Chat Completions only with reasoning_effort set to none. Reasoning plus tools uses Responses.
Can Decisions emit a function_call?
No. It returns a typed answer: a predicate probability, a choice, or a score. The host maps the choice onto a function you already have. The public-beta endpoint is POST /v1/decisions, and the only model today is gpt-6-luna. OpenAI describes it as about 10× faster than Responses. That is classification speed, not an order lookup.
What happens if I omit strict?
Chat Completions is non-strict by default. On Responses, omitting strict tries strict mode. If the schema cannot be made compatible, the API falls back and the returned tool shows strict: false. Set false explicitly to keep non-strict behavior. The host still validates arguments either way.
Should I change the write-back on an Agents session?
No. The Agents API is still in public beta. Keep turn_id. Computer Use is a separate permission on a hosted browser. Your app handles site approvals and sign-in. If you want to own every hop, stay on Responses and function_call_output.
Does Ultrafast change the tool JSON?
No. It is service_tier: ultrafast on gpt-6-astra, with US data residency and global processing only. The tool definition, call_id, and Schema stay. Do not write GPT-6.1 Sol Ultrafast as already available.
Conclusion
Migrating JSON tool calling after DevDay 2026 means changing the write-back. Astra and GPT-6.1 Sol tool calls use Responses. The name sits beside type. Results return on call_id. The hop that only picks an enum can move to Decisions. The host still runs the lookup.
Write down whether A-1042 goes into lookup_order arguments or into a Decisions input. Point at call_3c91 and answers[0].choice before you flip traffic.
Further reading
- What OpenAI shipped at DevDay 2026 The 29 September list, not these migration steps
- Agents API vs Responses API The two entry points write back differently
- OpenAI Agents API and JSON tool calling The public-beta objects; this piece does not rewrite them
- Agents API + JSON Schema Stable, checkable, executable
- Why AI needs JSON Schema Schema is a gate
- JSONSort local toolbox Format, validate, Diff, Schema
- All posts More notes on JSON and AI development
Changelog: First published