> ## Documentation Index
> Fetch the complete documentation index at: https://telluvian.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Compatibility

> Exactly which OpenAI request fields are supported, translated, ignored, or dropped.

Source: https://telluvian.ai/docs/compatibility

The API speaks two OpenAI interfaces and nothing else: **Chat Completions** and
the **[Responses API](https://telluvian.ai/docs/responses.md)**. There is no embeddings,
audio, image generation, moderation, or realtime endpoint. If your integration
only needs chat, the base-URL swap in the [quickstart](https://telluvian.ai/docs/quickstart.md) is the
whole migration.

"OpenAI-compatible" still leaves a lot unstated, and a field that is silently
ignored rather than rejected is the kind of thing that only shows up in
production. This page is the precise contract for **Chat Completions**
(`POST /v1/chat/completions`), sourced directly from the request schema the
server validates against, not from prose that can drift out of sync with it.
Every unrecognized field is accepted and ignored **except** where noted under
[Rejected, not dropped](#rejected-not-dropped).

## Supported as-is

These map straight onto the model's sampling parameters, unchanged:

`model`, `messages`, `stream`, `max_tokens`, `max_completion_tokens`
(OpenAI's o-series alias for `max_tokens`), `temperature`, `top_p`, `n`, `stop`,
`presence_penalty`, `frequency_penalty`, `seed`.

> **messages roles**
>
> Only `system`, `user`, and `assistant` are accepted. There is no `tool` role
> and no `developer` role (the o-series alias for `system`). See
> [No tool calling](#no-tool-calling) below.

## Translated

The shape differs from OpenAI's because the underlying serving engine's
parameters differ. The request is accepted in OpenAI's shape and converted:

| Field | OpenAI shape | What happens |
| --- | --- | --- |
| `logprobs` / `top_logprobs` | `logprobs: bool` + `top_logprobs: int` | Combined into a single top-k count |
| `logit_bias` | string keys (stringified token ids) | Converted to integer token ids |
| `response_format` | `{"type": "json_object"}` or `{"type": "json_schema", ...}` | `json_object` maps to guided decoding. `json_schema` is **best-effort**, and complex schemas may not be enforced exactly |

## Accepted, no effect

Present in the request schema so SDKs don't error, but nothing on the serving
path reads them:

`user`, `store`, `metadata`, `stream_options`.

> **store and stream_options do nothing here**
>
> These matter on OpenAI's own API and on Telluvian's [Responses
> endpoint](https://telluvian.ai/docs/responses.md#managing-stored-responses). But on **Chat
> Completions specifically**, they are accepted and ignored. Usage always
> arrives on the final stream chunk regardless of `stream_options`; see
> [Usage is always on the last chunk](https://telluvian.ai/docs/curl.md#streaming).

## Not in the schema, silently dropped

Anything not listed above or on the [`include_scores`
page](https://telluvian.ai/docs/include-scores.md) is **not rejected**. The request still succeeds;
the unrecognized field is dropped before the request reaches the model.
Concretely, that includes:

### No tool calling

`tools`, `tool_choice`, `functions`, `function_call`, and `parallel_tool_calls`
are all silently dropped. There is no tool/function-calling support, and no
`tool` message role to carry a result back. Sending a tool-calling request
gets you back a plain text completion as if `tools` had never been set.

### Anything else not listed above

`logit_bias` beyond the translation noted, reasoning-effort style fields,
`service_tier`, and any other field not in the tables above. Same rule:
accepted request, field ignored.

## Rejected, not dropped

One shape is a hard error rather than a silent drop:

### No vision / multimodal input

Every model is text-in, text-out. `content` must be a **plain string**. A
content array, `[{"type": "image_url", ...}]`, is **rejected with a `422`**,
not ignored like the fields above.

> **The 422 is not OpenAI-shaped**
>
> This error is raised by the model server's schema validation and passes
> through unchanged, so its body is `{"detail": [...]}` rather than the
> `{"error": {...}}` object [every other status](https://telluvian.ai/docs/errors.md) returns. Parse
> defensively if you handle it.

> **Check the response, not just the request you sent**
>
> A silently dropped field is the single easiest way to lose hours: your code
> looks correct, the request succeeds, and the behavior you expected just
> never happens. If a feature you're relying on doesn't seem to work, confirm
> it's actually in the tables above before debugging anything else. The same
> advice as [verifying `include_scores`](https://telluvian.ai/docs/include-scores.md#verifying-what-you-got).

## Telluvian extensions

Four things exist only on this API, layered on top of the OpenAI shape:

- **`include_scores`** enables verification when explicitly set to `true`; it defaults to `false`. See the
  [dedicated page](https://telluvian.ai/docs/include-scores.md).
- **`tokens` / `scores`** on the response carry the probe's output. See [Reading
  the scores](https://telluvian.ai/docs/scores.md).
- **The `-analyze` model suffix** scores text you already have instead of
  generating any. It is a suffix on `model`, so it passes through an unmodified
  OpenAI SDK untouched. See [Scoring existing text](https://telluvian.ai/docs/analyze.md).
- **The Model Select controls**: `xPerf`, `xPerfEffort`, `xLatency`, `modelZoo` and
  `sessionId`. Unlike every other extra field on this page these are read rather
  than ignored, but **only** when `model` is `telluvian/gallery-1`. They are consumed
  by the choice and stripped before the model is called. `xLatency` is accepted
  and recorded but currently ignored. Sent with any other
  model they are ordinary unrecognized fields, and ignored. See
  [Model Select](https://telluvian.ai/docs/model-select.md#the-controls).

## The Responses API

[`/v1/responses`](https://telluvian.ai/docs/responses.md) is a separate, stateful interface built on
the same underlying model. The same "no tool calling, no multimodal input"
limits apply there too. The constraint is the model and probe pipeline, not
which endpoint you call.
