> ## Documentation Index
> Fetch the complete documentation index at: https://gomodel-feat-anthropic-response-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Anthropic

> Configure Anthropic (Claude) in GoModel and understand how reasoning effort maps to Claude's adaptive thinking and effort control.

Anthropic setup is just an API key. This page exists for one quirk: how
GoModel maps the OpenAI-style `reasoning.effort` knob onto Claude's native
thinking and effort controls, which differ by model generation.

## Configure

```bash theme={null}
ANTHROPIC_API_KEY=sk-ant-...
# ANTHROPIC_BASE_URL=https://api.anthropic.com/v1   # optional override
# ANTHROPIC_DEFAULT_MAX_TOKENS=4096                 # injected when callers omit max_tokens
```

Or in `config.yaml`:

```yaml theme={null}
providers:
  anthropic:
    type: anthropic
    api_key: "${ANTHROPIC_API_KEY}"
```

<Note>
  Anthropic's `/v1/messages` requires `max_tokens` on every request. GoModel
  injects `ANTHROPIC_DEFAULT_MAX_TOKENS` (default `4096`) when a caller omits
  it, keeping the OpenAI-compatible surface lenient.
</Note>

## Claude subscription (OAuth token)

GoModel also accepts a Claude subscription OAuth token as the Anthropic
credential. Generate one with `claude setup-token` (requires a Claude
subscription — Pro, Max, Team, or Enterprise — and the Claude Code CLI) and
set it as the provider key:

```bash theme={null}
ANTHROPIC_API_KEY=sk-ant-oat01-...
```

Tokens with the `sk-ant-oat` prefix are detected automatically: GoModel sends
them as `Authorization: Bearer` with the `oauth-2025-04-20` beta instead of
`x-api-key`. No extra configuration is needed.

<Warning>
  Anthropic authorizes subscription OAuth tokens **only for Claude Code
  traffic**. Use this to route your own Claude Code through GoModel (see the
  [Claude Code guide](/guides/claude-code)); requests from other clients are
  rejected upstream with "This credential is only authorized for use with
  Claude Code". Endpoints outside the Claude Code surface (such as model
  listing) may also be rejected — if provider model discovery fails, configure
  the `models` list for the provider explicitly.
</Warning>

## Reasoning effort mapping

GoModel accepts the OpenAI-shaped `"reasoning": {"effort": "..."}` object as
well as the Chat Completions string form `"reasoning_effort": "..."` (a
non-empty `reasoning.effort` wins when both are present; an empty object falls
back to the string form) and translates them to Claude's native controls. The
five accepted levels are `low`, `medium`, `high`, `xhigh`, and `max`; values
are matched case-insensitively and any other value is downgraded to `low` and
logged. The translation
depends on whether the model supports **adaptive thinking**.

| Model generation                                                                                                                                                                                                                        | Thinking config                                 | Effort destination                      |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | --------------------------------------- |
| Adaptive — `claude-fable-5`, `claude-fable-5-1`, `claude-mythos-5`, `claude-mythos-5-1`, `claude-opus-5`, `claude-sonnet-5`, `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-sonnet-4-6` (and dated snapshots of each) | `thinking: {type: "adaptive"}`                  | `output_config.effort` (passed through) |
| Legacy (everything else, e.g. `claude-opus-4-5`, `claude-3-5-sonnet`)                                                                                                                                                                   | `thinking: {type: "enabled", budget_tokens: N}` | mapped to a token budget                |

<Note>
  Adaptive routing is an explicit allowlist, not a version comparison. New
  model IDs are treated as legacy until added to the list. For pre-4.7 models
  the legacy fallback keeps working via `budget_tokens`; models from Opus 4.7
  onward reject `budget_tokens` outright, so a new adaptive-only model ID
  fails with an upstream 400 until it is added to the allowlist.
</Note>

For legacy models the effort string maps to a thinking budget; `max_tokens` is
bumped above the budget when needed. `xhigh` and `max` are adaptive-only levels,
so on legacy models they are capped at the `high` budget rather than inflating
`max_tokens` past what those models can emit:

| Effort                   | Budget tokens |
| ------------------------ | ------------- |
| `low`                    | 5000          |
| `medium`                 | 10000         |
| `high` / `xhigh` / `max` | 20000         |

<Note>
  Omit `reasoning` to leave thinking at the model's default. GoModel only sets
  `thinking: {type: "adaptive"}` when you pass `reasoning.effort` (or
  `reasoning_effort`). Without it,
  Opus 4.6 to 4.8 and Sonnet 4.6/5 do not engage extended thinking, while
  Fable 5/5.1, Mythos 5/5.1, and Opus 5 think adaptively on their own (see the
  always-on note below). Effort is a separate
  control that governs overall token spend (text and tool calls) whether or not
  thinking is engaged, and Anthropic defaults it to `high` when unset. It is a
  behavioral signal for depth and verbosity, not a hard budget — actual usage
  varies per request and is bounded by `max_tokens`.
</Note>

<Note>
  Effort levels are model-gated upstream: `xhigh` is available on Fable 5/5.1,
  Opus 5, Sonnet 5, and Opus 4.8/4.7; `max` on those plus Opus 4.6 and
  Sonnet 4.6. GoModel forwards the level you send; Anthropic rejects it with a
  400 if the target model does not support it. Manual `budget_tokens` thinking
  is rejected from Opus 4.7 onward, which is why GoModel uses adaptive thinking
  for those models.
</Note>

<Note>
  On Fable 5/5.1, Mythos 5/5.1, and Opus 5 thinking is always on, whether or
  not you send `reasoning`; `reasoning.effort` only tunes its depth. The tokens
  it spends are reported as `usage.completion_reasoning_tokens` in Chat
  Completions responses. The reasoning text itself is not returned; only the
  token count is.
</Note>

## Sampling parameters

Anthropic removed `temperature` and `top_p` from Fable 5/5.1, Mythos 5/5.1,
Opus 5, Sonnet 5, and Opus 4.8/4.7 — any value, including the OpenAI SDK
default of `temperature: 1`, is rejected upstream with a 400. GoModel drops
both fields for those models and logs the discarded values, so clients that
always send a temperature keep working. Older models still receive them as
sent, with one exception below.

Anthropic treats `temperature` and `top_p` as mutually exclusive on every
model: a request carrying both is rejected with ``400 "`temperature` and `top_p` cannot both be specified for this model"``. Since OpenAI-compatible
clients routinely fill in both defaults, GoModel forwards `temperature` and
drops `top_p` (logging the discarded value) when it sees both. Send only
`top_p` if that is the knob you want to control.

Independently of the model, when extended thinking is engaged Anthropic
requires `temperature = 1`. GoModel drops any other temperature value (and logs
it) rather than failing the request.

## Structured output

`response_format` works on Anthropic models, mapped onto Claude's native
structured outputs (`output_config.format`). The same applies to `text.format`
on `/v1/responses`, which GoModel translates into `response_format` first.

| `response_format`               | What GoModel sends                                                                 |
| ------------------------------- | ---------------------------------------------------------------------------------- |
| `{"type": "text"}` (or omitted) | Nothing — Claude's default                                                         |
| `{"type": "json_schema", ...}`  | `output_config.format` with your schema, so Anthropic constrains the output        |
| `{"type": "json_object"}`       | A system-prompt instruction — Anthropic's native format accepts only `json_schema` |

```bash theme={null}
curl http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer $GOMODEL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-haiku-4-5-20251001",
    "messages": [{"role": "user", "content": "Describe Paris."}],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "city",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {"city": {"type": "string"}, "country": {"type": "string"}},
          "required": ["city", "country"],
          "additionalProperties": false
        }
      }
    }
  }'
```

The response is an ordinary chat completion whose `message.content` is the JSON
text, with `finish_reason: "stop"` — the same shape OpenAI returns. Streaming is
unaffected: the JSON arrives as normal content deltas. Tools and
`response_format` can be sent together; Claude either calls a tool
(`finish_reason: "tool_calls"`) or answers with schema-constrained JSON.

Anthropic's schema compiler is stricter than OpenAI's, so GoModel adapts the
schema before sending it:

* every object schema gets the mandatory `"additionalProperties": false`, on
  each `allOf` branch too — Anthropic requires it and merges the branches itself
* validation-only keywords Anthropic does not honor (`minimum`, `maximum`,
  `multipleOf`, `maxItems`, `uniqueItems`, `minLength`, `maxLength`,
  `propertyNames`, `not`, `if`/`then`/`else`, …) are dropped
* `pattern` is kept, because Anthropic does enforce it — except for the regex
  features its engine rejects (lookarounds, backreferences, `\b`/`\B`), which
  would 400 the request; those patterns are dropped and the loss is logged
* `minItems` is kept when it is `0` or `1`, the only values Anthropic accepts,
  and dropped otherwise
* `oneOf` is relaxed to `anyOf`, and unknown string `format` values are dropped.
  A schema carrying both `oneOf` and `anyOf` at the same level cannot be
  expressed — Anthropic rejects the `allOf` that would hold the second one — so
  `oneOf` is dropped and the loss is logged
* `required` is left exactly as sent: Anthropic accepts optional properties, so
  a property you left out of `required` stays optional

Nested objects, arrays, `enum`, `const`, `anyOf`, `allOf`, and `$ref`/`$defs`
are passed through unchanged. `$ref` has limits GoModel cannot paper over, and
Anthropic returns a 400 naming each one: references must be local (`#/$defs/…`
— an external URL is refused), non-recursive (a definition that refers to
itself, directly or in a cycle, is refused), and outside `allOf` (resolve the
reference yourself before composing with `allOf`).

<Note>
  `strict` is not forwarded — Anthropic always enforces the schema it is given.
  A non-strict schema is therefore enforced too, minus the constraints listed
  above. Structured output is available on every Claude model GoModel can
  currently reach.
</Note>

### When the content is not schema-valid JSON

The schema constrains what the model generates, not how the turn ends. Check
the completion before parsing `message.content`:

* `finish_reason: "length"` — the answer hit `max_tokens` and the JSON is cut
  off mid-value. Raise `max_tokens` and retry.
* `finish_reason: "tool_calls"` — the model called a tool instead of answering,
  so `message.content` is empty.
* `finish_reason: "refusal"` — Claude declined the request; GoModel passes
  Anthropic's refusal stop reason through unchanged and there is no JSON to
  parse.

Only `finish_reason: "stop"` with non-empty content is worth handing to a JSON
parser; treat anything else as an error rather than parsing it.

## Verbosity

OpenAI's `verbosity` (and `text.verbosity` on `/v1/responses`) has no Anthropic
equivalent. GoModel logs the requested value and drops it rather than failing
the request. Ask for shorter or longer answers in the prompt instead.

## Forced tool choice on Fable 5.1

Fable 5.1 and Mythos 5.1 accept only `tool_choice: "auto"` and `"none"`;
forcing a call with `"required"` or `{"type": "function", ...}` returns a 400
from Anthropic. GoModel follows Anthropic's documented replacement: the choice
is downgraded to `auto` and an instruction is appended to the system prompt —
"You must respond by calling one of the provided tools." for `required`, or
"You must respond by calling the tool named `<name>`." for a named function.
The downgrade is logged. `parallel_tool_calls: false` is still honored. Fable 5
and every other Claude model keep forced tool use unchanged.

<Warning>
  The instruction is strong guidance, not a hard guarantee: the model can still
  answer in text. If you relied on forced tool choice to obtain JSON, use
  [structured output](#structured-output) instead.
</Warning>

## Native passthrough

To send Claude-native request fields that have no OpenAI-compatible equivalent
(for example inline mid-task `system` entries in the `messages` array), use the
passthrough route `/p/anthropic/messages`, which forwards the body verbatim.
