# The Responses API tool loop in Node

Verified against the function calling guide on 2026-09-26.

## The loop

1. `const response = await openai.responses.create({ model, input, tools })`
   with tools declared as `{ type: "function", name, description, parameters }`.
2. `const calls = response.output.filter((i) => i.type === "function_call")`.
3. For each call: `const args = JSON.parse(call.arguments)` in try/catch;
   `await` your implementation (never fire-and-forget inside the loop, or the
   output ordering breaks).
4. Build the follow-up input: the previous `response.output` items plus, per call,
   `{ type: "function_call_output", call_id: call.call_id, output: JSON.stringify(result) }`.
   Omitting the original function_call items from the follow-up input is the most
   common 400 in this loop; the API needs the full item history.
5. `await openai.responses.create({ model, input: nextInput, tools })` and repeat
   until no function_call items remain.

## Guards

- Cap the loop (for example 8 iterations) and surface a partial answer at the cap.
- `parallel_tool_calls: false` when functions depend on each other's results.
- Whitelist `call.name` against your tool registry before dispatch; never index
  into an object with a model-supplied name without a hasOwnProperty-style check.

## Check before you ship

- In Express, this whole loop runs inside one request handler; set a route
  timeout longer than your worst-case loop, or move the loop to a background job
  and poll.
- Assert in a test that every function_call_output's call_id matches its call.