tools. A model that does not list tool calling refuses the request with 400 hosted_capability_not_supported.
Minimal code
What one turn actually looks like
What to tune
Common mistakes
- Dropping the assistant turn. Push the whole assistant message,
tool_callsand all, before you push any tool result. Without it the tool message has nothing to attach to. - Returning a non-string tool result. The
contenton a tool-role message must be a string. Always serialize it. - A vague
description. Write it as though the model has never seen your API: what the tool does, what each argument means, what a good input looks like. This is the single biggest lever on whether a tool gets called at all. - No turn limit. Bound the loop. Ten turns covers almost every pattern, and an unbounded loop can spend real money.
- Trusting the arguments. The model can invent a field or omit a required one. Validate with Pydantic or Zod before you execute.
Next steps
Structured output
When you want JSON back without a tool loop.
Streaming
Stream the assistant turn as it arrives.
Chat completions
The full request contract.