LLM GatewayChat

Chat completions (streaming + non-streaming, with reasoning)

OpenAI-compatible chat completions over an upstream provider chosen by `model`. Set `"stream": true` for SSE; otherwise the response is a single JSON body. ### Reasoning Opt into model thinking with top-level `reasoning_effort` (`minimal | low | medium | high | xhigh | max`). Allowed values are per-model — query `/v1/models` for `reasoning_levels`. Reasoning is **streaming-only**: non-streaming responses drop it entirely. Streaming reasoning surfaces two channels per `delta`: - `reasoning_content` — display text for live UI (DeepSeek-style extension; concatenate across chunks like `content`). - `reasoning_meta` — structured snapshot at block close, carrying the `signature` (Anthropic) or `encrypted_content` (OpenAI) clients need to replay reasoning on subsequent turns. ### Multi-turn replay Persist `reasoning_meta` between turns and send it back as a `{"type": "reasoning", ...}` block on the assistant message — before text and tool calls (Anthropic enforces this order). Required on Anthropic for tool-using turns (the API 400s without the matching thinking block); recommended on OpenAI so the model doesn't re-derive its plan and re-bill reasoning tokens. OpenAI's Responses API requires `id` on every replayed reasoning block — the gateway 400s pre-flight if missing. Anthropic ignores `id` (signatures live per-block instead). Signatures and encrypted blobs are **model-bound**: persist `model` alongside the reasoning meta and refuse to replay across models. See `docs/llm-gateway/REASONING.md` for the full contract, JSONL persistence shape, and end-to-end curl examples.

POST/v1/chat/completions

OpenAI-compatible chat completions over an upstream provider chosen by model. Set "stream": true for SSE; otherwise the response is a single JSON body.

Reasoning

Opt into model thinking with top-level reasoning_effort (minimal | low | medium | high | xhigh | max). Allowed values are per-model — query /v1/models for reasoning_levels. Reasoning is streaming-only: non-streaming responses drop it entirely.

Streaming reasoning surfaces two channels per delta:

  • reasoning_content — display text for live UI (DeepSeek-style extension; concatenate across chunks like content).
  • reasoning_meta — structured snapshot at block close, carrying the signature (Anthropic) or encrypted_content (OpenAI) clients need to replay reasoning on subsequent turns.

Multi-turn replay

Persist reasoning_meta between turns and send it back as a {"type": "reasoning", ...} block on the assistant message — before text and tool calls (Anthropic enforces this order). Required on Anthropic for tool-using turns (the API 400s without the matching thinking block); recommended on OpenAI so the model doesn't re-derive its plan and re-bill reasoning tokens.

OpenAI's Responses API requires id on every replayed reasoning block — the gateway 400s pre-flight if missing. Anthropic ignores id (signatures live per-block instead).

Signatures and encrypted blobs are model-bound: persist model alongside the reasoning meta and refuse to replay across models.

See docs/llm-gateway/REASONING.md for the full contract, JSONL persistence shape, and end-to-end curl examples.

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

OpenAI-compatible chat completions request.

model picks the upstream provider (see /v1/models). Set "stream": true to receive text/event-stream of ChatChunk deltas instead of a single ChatResponse body. Tool-calling and reasoning are both streaming-only in v1.

Response Body

application/json

application/json

application/json

curl -X POST "https://example.com/v1/chat/completions" \  -H "Content-Type: application/json" \  -d '{    "messages": [      {        "role": "user"      }    ],    "model": "gpt-5.5",    "stop": {}  }'
{  "choices": [    {      "finish_reason": "stop",      "index": 0,      "message": {        "content": "string",        "role": "assistant"      }    }  ],  "created": 0,  "id": "string",  "model": "gpt-5.5",  "object": "chat.completion",  "usage": {    "cache_creation_input_tokens": 0,    "cache_read_input_tokens": 0,    "completion_tokens": 0,    "prompt_tokens": 0,    "total_tokens": 0  }}
{  "error": {    "message": "model not supported: foo",    "type": "invalid_request_error"  }}
{  "error": {    "message": "model not supported: foo",    "type": "invalid_request_error"  }}
{  "error": {    "message": "model not supported: foo",    "type": "invalid_request_error"  }}