Formats
The same conversation, four documents
System prompt “Answer in one sentence.”, one user question, temperature 0.2, a 256-token cap. Below is where each field lands in each specification, then the four bodies themselves — editable, and rewritten from whichever one you touch by this library, running in the page.
01 · Field map
Read a row across
One concept per row; one specification per column. Red marks a value that decides whether the request is accepted at all.
Four columns wide — scroll sideways on a narrow screen.
| Field | OpenAIPOST /v1/chat/completions | AnthropicPOST /v1/messages | GeminiPOST /v1beta/models/{model}:generateContent | OllamaPOST /api/chat |
|---|---|---|---|---|
| Model | "model": "gpt-4o-mini" |
"model": "claude-sonnet-4-20250514" |
In the URL: /models/gemini-2.0-flashno model field in the body |
"model": "qwen2.5" |
| System prompt | messages[0] with role: "system" |
top-level "system": "…"kept out of the message list |
"systemInstruction": {"parts": [{"text": …}]} |
messages[0] with role: "system" |
| Messages | "messages": [{role, content: "…"}]content is a string |
"messages": [{role, content: [{type:"text", text:"…"}]}]content is an array of blocks |
"contents": [{role:"user", parts:[{text:"…"}]}] |
"messages": [{role, content: "…"}] |
| Roles | system / user / assistant |
user / assistantno system role at all |
user / modelthe assistant is called model |
system / user / assistant |
| Temperature | "temperature": 0.2 |
"temperature": 0.2 |
generationConfig.temperature |
options.temperature |
| Output limit | "max_tokens": 256 |
"max_tokens": 256required — a request without it is rejected |
generationConfig.maxOutputTokens |
options.num_predict |
| Stop sequences | "stop": ["\n\n"] |
"stop_sequences": ["\n\n"] |
generationConfig.stopSequences |
options.stop |
| Streaming | "stream": true |
"stream": true |
a different method: :streamGenerateContent?alt=ssenot a flag in the body |
"stream": false turns it offon by default |
| Usage | usage.prompt_tokens / completion_tokens |
usage.input_tokens / output_tokens |
usageMetadata.promptTokenCount / candidatesTokenCount |
prompt_eval_count / eval_count |
| Finish reason | choices[0].finish_reasonstop / length / tool_calls |
stop_reasonend_turn / max_tokens / tool_use |
candidates[0].finishReasonSTOP / MAX_TOKENS |
done_reasonstop / length |
02 · Four bodies
Edit one, and the rest follow
Every pane is a text field. Change a value, add a message, or press ↻ to make that pane the source: the other three are read and written by the four dialects, not by this page.
The model travels with the request: convert a body and the same model name appears where the target format keeps it — for Gemini, in the URL.
03 · House rules
What breaks a second integration
Four things, in the order they usually bite. None of them is a bug in either side; each is what the specification decides.
- Anthropic requires max_tokens. Omit it and the request is rejected; there is no default. OpenAI and Ollama fill one in.
- Gemini puts the model in the path and the knobs under generationConfig. Temperature, output cap and stop sequences are renamed and relocated at the same time.
- Ollama nests generation options under options, and streams by default. Ask for one response with
"stream": false. - OpenAI has no top-level system field. The system prompt is the first message, so order carries meaning.
04 · Streams
Four shapes of the same event
The deltas are one type. What arrives on the socket is not: a JSON chunk, seven named events, a candidate array, or one object per line.
data: {"choices":[{"delta":{"content":"Be"}}]}
data: {"choices":[{"delta":{"content":"cause"}}]}
data: [DONE]
One unnamed event per chunk; the stream closes with a sentinel.
event: message_start
data: {"type":"message_start",...}
event: content_block_delta
data: {"type":"content_block_delta","index":0,
"delta":{"type":"text_delta","text":"Be"}}
Seven event names, and a block index that has to be tracked.
data: {"candidates":[{"content":{"parts":
[{"text":"Be"}],"role":"model"}}]}
The same SSE frame, with the text nested three levels down.
{"message":{"role":"assistant","content":"Be"},"done":false}
{"message":{"role":"assistant","content":"cause"},"done":false}
{"done":true,"done_reason":"stop"}
No event names, no sentinel: one object per line, ending with done.
05 · Serving
And the same four, outward
The dialects that write a request also read one, so a provider can answer in all four formats. Two formats claim /v1/models; the anthropic-version header decides which answers.
| Format | Endpoints |
|---|---|
| OpenAI | /v1/chat/completions /v1/completions /v1/responses /v1/embeddings /v1/models |
| Anthropic | /v1/messages /v1/messages/count_tokens /v1/models |
| Ollama | /api/chat /api/generate /api/embed /api/tags /api/show /api/version |
| Gemini | /v1beta/models/*:generateContent :streamGenerateContent :embedContent :batchEmbedContents |
Writing one more format adds one dialect, and the client and the gateway both have it: the direction you did not write is the one you already had.