# Capabilities

One reference table for what each surface serves. Every capability below is available on a single API key; you pick a wire format, not a feature set.

## Capability matrix

The same model backs all three surfaces, so the differences here are wire-format conventions, not feature gaps. A capability marked on one surface is reachable from the others by sending that surface's shape — for example, PDF input is native to the Anthropic surface, and any `gemini-*` or OpenAI-style id can be sent there too.

| Capability | OpenAI | Anthropic | Gemini |
| --- | --- | --- | --- |
| Text generation | ✓ `/chat/completions` | ✓ `/v1/messages` | ✓ `:generateContent` |
| Streaming (SSE) | ✓ `stream: true` | ✓ `stream: true` | ✓ `:streamGenerateContent` |
| Function tools (client-defined) | ✓ `tools` | ✓ `tools` | ✓ `functionDeclarations` |
| Forced tool / structured output | ✓ `tool_choice` | ✓ `tool_choice` | ✓ `functionCallingConfig` |
| JSON mode / response schema | ✓ `response_format` | ✓ `output_config.format` | ✓ `responseSchema` |
| Vision (image input) | ✓ `image_url` | ✓ image source | ✓ `inlineData` |
| PDF / document input | Use the Anthropic surface | ✓ document source | ✓ `inlineData (PDF)` |
| Usage on a stream | ✓ `stream_options.include_usage` | ✓ in every `message_delta` | ✓ `usageMetadata` |
| Token counting | — | ✓ `/v1/messages/count_tokens` | ✓ `:countTokens` |
| Prompt caching | ✓ `cache_control` | ✓ `cache_control` | Automatic where available |

## OpenAI Responses API

DirectInference also serves the **OpenAI Responses API** at `/v1/responses` (and `/di/v1/responses`) — point `client.responses.create(...)` at the base URL and keep your model id. It is a fourth wire surface translated to the same model, so text, streaming, client-defined function tools, forced tools, JSON / structured output (`text.format`), and vision (`input_image`) work exactly as on the Chat Completions surface.

The surface is **stateless** — it keeps no server-side conversation state. Send the full conversation in `input` each turn. These shapes are rejected at request time with a typed error that names the field:

- `previous_response_id`, `background: true`, `conversation`, and `prompt` templates (stateful — `unsupported_parameter`).
- Hosted / server-side tools — `web_search`, `file_search`, `code_interpreter`, `computer_use_preview`, `image_generation`, `mcp`. DirectInference cannot execute these; client-defined function tools are fully served.
- `store: true` is accepted but honored as `store: false` — the response is never made retrievable.

## Context window & max output

DirectInference serves every request type from the model best suited to it, so the context window and maximum output are whatever the chosen model supports for that request. The figures advertised in the catalog are the **conservative minimum guaranteed across every request type** — the floor you can always rely on, not a per-call ceiling. A long-context request is served by a long-context model regardless of this floor.

:::tip[Read the current numbers from the catalog]
The live values are in the `/di/v1/models` payload — `context_length` and `max_output_tokens` on each entry — so they never go stale in your code. There is nothing to pin: query the catalog at runtime if you need the exact floor.
:::

## Not served

A few request shapes are deliberately not served. Each is rejected at request time with a descriptive error that names the offending element — never a silent drop or a degraded answer. Keep these call sites on their original provider; client-defined function tools are fully served and are the supported way to give the model capabilities.

| Shape | Rejected identifiers |
| --- | --- |
| Provider server-side tools | Gemini `googleSearch`, `googleSearchRetrieval`, `urlContext`, `codeExecution`; Anthropic `web_search`, `code_execution`; OpenAI `web_search` tool type and `web_search_options`; Responses hosted tools `web_search`, `file_search`, `code_interpreter`, `computer_use_preview`, `image_generation`, `mcp` |
| Responses API stateful subset | `previous_response_id`, `background`, `conversation`, `prompt` templates — see [OpenAI Responses API](#openai-responses-api) (the surface itself is served, statelessly) |
| Embeddings | `/embeddings` |
| Images, audio, moderations, batches, files, fine-tuning | the corresponding endpoints |

:::note[Discoverable, not surprising]
These identifiers are stable, so an agent or migration script can check against this list instead of discovering a limit by a failed call. The rejection itself is also self-describing — see [Errors & limits](https://docs.directinference.com/errors/) for the envelope each surface returns.
:::

:::tip[Capabilities are guaranteed, not advertised per model]
Because there is one model and the request type is inferred, you never match a capability to a model id. Send the call; the right model serves it. The determinism behind that — an image always reaching a vision-capable model, a tool call never coming back unusable — is spelled out in [Request types](https://docs.directinference.com/request-types/).
:::