Chat completions api
Reference for the OpenAI Chat Completions API (/v1/chat/completions) and legacy /v1/completions as the lingua-franca compatibility protocol — the official spec incl. deprecation timeline and Responses-only feature delta, how 7 local servers (vLLM, SGLang, llama.cpp, Ollama, mistral.rs, Llama Stack/OGX, Lemonade) actually implement it, gateways (LiteLLM, Bifrost), 10 cloud providers' CC-compat endpoints (Anthropic, Gemini, DeepSeek, xAI, Groq, OpenRouter, Azure...), the reasoning_content/reasoning field schism, finish_reason divergences, and client wire behavior (opencode, Vercel AI SDK). NOT for the Responses API (responses-api skill) or Anthropic Messages protocol (messages-api skill).From its SKILL.md
npx -y skills add air-gapped/skills --skill chat-completions-apiAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 2 commands, including `curl -sS http://host:port/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"<name>","max_tokens":32,"messages":[{"role":"user","content":"Say OK."}]}'` and 1 more.
SKILL.md
8.7 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Chat Completions Compatibility Reference
Chat Completions is the lingua franca of LLM serving — and because everyone
has implemented and extended it longest, it carries the MOST undocumented
divergence of the three open protocols. OpenAI keeps it fully supported but
second-choice ("we recommend trying Responses"); xAI, Groq, and Azure
likewise declare it legacy. Legacy /v1/completions loses its last
first-party OpenAI models 2026-09-28 and survives as a local/third-party
surface.
Fleet property: stateless. Full history resent every turn, like
Messages; no server-side session state to break load-balanced fleets
(contrast responses-api's previous_response_id).
Last refreshed: 2026-07-19 (source-examined at commits of 2026-07-16..18;
provenance in references/sources.md).
Critical Gotchas
- The reasoning-field schism:
reasoning_content(SGLang, llama.cpp, mistral.rs, DeepSeek, xAI) vsreasoning(vLLM, Ollama, Together, Groq, OpenRouter) vs inline<think>— and vLLM silently RENAMES incomingreasoning_content→reasoning. Servers should emit both; clients should read both. Full table:references/backend-implementations.md. - Reasoning must be passed BACK in tool loops on DeepSeek v4 (with tool
calls) and OpenRouter (exact block sequence) — clients that strip
reasoning break agentic loops.
references/cloud-compat.md. - Silent-drop vs hard-400 split: Ollama silently drops
tool_choice(forced tool calls no-op!) andmax_completion_tokens(unbounded generation); Groq and xAI-reasoning hard-400 on specific params; LiteLLM raises UnsupportedParamsError as HTTP 500. Identify the target's failure mode before debugging. - finish_reason is not a closed enum:
abort(vLLM, SGLang),repetition,canceled/generated_image(mistral.rs); llama.cpp DEFAULTS tolength; named tool_choice returnsstopon vLLM/OpenAI buttool_callson SGLang/mistral.rs. Parse tolerantly, key loops ontool_calls. seedis a lottery: honored (vLLM, llama.cpp), silent no-op unless server flag (SGLang--enable-deterministic-inference), ignored (mistral.rs) — and OpenAI has formally deprecatedseedANDsystem_fingerprint.json_object≠ json mode everywhere: SGLang and mistral.rs implement it as schema{"type":"object"}— top-level arrays forbidden.json_schema.strictis ignored by ALL local servers (always fully enforced anyway).- Tool-call streaming split: whole-blob single delta (Ollama,
mistral.rs) vs incremental argument diffs (vLLM, SGLang, llama.cpp).
First delta must carry
id+function.nameor AI-SDK clients kill the stream; loose parsers finalize args the moment they parse as JSON. - Cached-token reporting is flag-gated: vLLM
--enable-prompt-tokens-details, SGLang--enable-cache-report; llama.cpp reports always; Ollama never. OpenAI CC now has explicit caching (prompt_cache_options+ per-block breakpoints,cache_write_tokensbilled 1.25×):references/spec.md. data: [DONE]is not universal — Llama Stack/OGX never sends it; AI SDK clients ignore it, official-SDK clients expect it. Send it; don't require it.
Quick Reference
When invoked with a topic argument (spec, backends, gateways, cloud,
clients), load that reference file first and answer from it. Without an
argument, pick by question shape: official params/deprecations/what-CC-gets
→ spec; which-local-server-does-what → backends; proxy/routing behavior →
gateways; hosted-provider compat → cloud; what-clients-send / parser
tolerance → clients.
- Spec:
references/spec.md— full request/response/chunk schema highlights, explicit prompt caching, stored completions, legacy /v1/completions + shutdown timeline, deprecation archaeology, Responses-only feature delta - Backends:
references/backend-implementations.md— divergence matrix- per-server sections for the 7 local servers
- Gateways:
references/gateways.md— LiteLLM param cascade and prefix routing, Bifrost, Superagent (CC outbound only), gateway-tax table - Cloud:
references/cloud-compat.md— 10 providers' CC-compat endpoints and the cross-provider gotcha matrix - Clients:
references/clients.md— opencode's three CC paths, AI SDK parser tolerance, server tolerance checklist - Sources:
references/sources.md— dated per-URL index with commits examined and the live-verification log
Translation between protocols is homed elsewhere: CC↔Messages mapping in the messages-api skill, CC↔Responses mapping in the responses-api skill.
Procedures
Pointing an OpenAI-SDK client at a local backend
- Base URL
http://host:port/v1(SDKs append/chat/completions); authBeareranything unless the server enforces keys. - Check the backend's row in the divergence matrix FIRST — especially
Ollama (
tool_choiceandmax_completion_tokenssilently dropped) and reasoning field naming. - For agent clients (opencode etc.): use the openai-COMPATIBLE provider
path, not the openai provider — the openai path model-id-sniffs
("o3-…" gets temperature stripped), drops reasoning fields, and its
factory default is the Responses API (
references/clients.md). - Reasoning models: confirm how thinking is toggled (
reasoning_effortmapping vschat_template_kwargs.enable_thinkingvs vendorthinkingfields) and which field the CoT comes back in. - Sanity curl:
Expectcurl -sS http://host:port/v1/chat/completions -H "Content-Type: application/json" \ -d '{"model":"<name>","max_tokens":32,"messages":[{"role":"user","content":"Say OK."}]}'object:"chat.completion", non-nullchoices[0].message.content,finish_reasonofstopORlength(llama.cpp defaults tolength). An error body here → check the server's error-envelope row in the matrix before parsing (mistral.rs sends{"message"}, not{"error":{...}}).
Serving CC through LiteLLM to a fleet
- Prefix decides fidelity:
openai/<model>= full surface passthrough;hosted_vllm/<model>= tool schemas silently edited (strict + additionalProperties stripped). Pick deliberately. - Set
drop_params: true(or per-modeladditional_drop_params) — otherwise unsupported params surface as HTTP 500 UnsupportedParamsError. - Statelessness makes any replica valid — no affinity needed.
Debugging a CC streaming issue
- Capture raw SSE:
curl -sN http://host:port/v1/chat/completions -H "Content-Type: application/json" \ -d '{"model":"<name>","max_tokens":64,"stream":true,"stream_options":{"include_usage":true},"messages":[{"role":"user","content":"hi"}]}' | head -40 - Expect data-only SSE: first chunk
delta.role, content/tool deltas keyed byindex, finish chunk, optionalchoices:[]usage chunk,[DONE]. - Check the backend's streaming row in the matrix for known deviations
(always-present null keys on SGLang, vendor
timingson llama.cpp, role-on-every-chunk + whole-blob tools on Ollama, raw non-JSON error lines on mistral.rs, missing [DONE] on OGX). - If tool calls vanish client-side: check whether the first delta carried
id+function.name, and whether the client requirestool_calls[].index(references/clients.md).
What ships with it: 7 files
62.6 KB alongside SKILL.md
references/
- backend-implementations.md19.2 KB
- clients.md9.6 KB
- cloud-compat.md8.8 KB
- gateways.md8.5 KB
- improvement-backlog.md2.2 KB
- sources.md5.0 KB
- spec.md9.2 KB