Claim
From the 0.24.1 changelog, introducing /effort:
default clears the override; off is a real level that disables reasoning.
On current Anthropic models it does not. effort: "off" (and /effort off) leaves thinking fully enabled on claude-sonnet-5, claude-opus-5 and claude-fable-5, so a user who explicitly opts out still pays the latency and the reasoning tokens — silently, on the one setting whose whole purpose is opting out.
Cause
adapter.rs gives each provider a DisableWire describing how thinking is turned off. Anthropic's is None — "omit the parameter":
("anthropic", EffortWire::AnthropicBudget, DisableWire::None),
Omitting thinking was a correct disable for Claude 4.6 and earlier. It stopped being one on the current generation:
| Model |
thinking omitted |
| Sonnet 4.6 / Opus 4.6 |
no thinking — omit still works |
| Sonnet 5 |
thinks (adaptive by default) |
| Opus 5 |
thinks (adaptive by default) |
| Fable 5 |
always thinks, cannot be disabled |
So the wire shape didn't change; what omitting it means did.
The payload already exists in the codebase
Anthropic is one of only three providers left on DisableWire::None; five others carry real disable wires (ThinkingToggle, ChatTemplateKwargs, GeminiZeroBudget, OllamaThink).
Notably GLM — which mimics Anthropic's API — is on ThinkingToggle, which emits:
{"thinking": {"type": "disabled"}}
That is Anthropic's own documented shape. dirge already sends exactly the payload Anthropic needs; it just doesn't send it to Anthropic.
Why the fix is not a one-line table change
Model support is uneven, so a blanket switch to ThinkingToggle would trade this bug for 400s:
- Sonnet 5 accepts
{"type": "disabled"}.
- Opus 5 accepts it only at effort
high or below — pairing it with xhigh/max is rejected. Since off means no thinking at all, that combination shouldn't arise, but the constraint is worth encoding rather than assuming.
- Fable 5 rejects it outright — thinking is unconditional there.
off can never be honoured; warning that the level is unavailable seems more honest than silently accepting it.
- Claude 4.6 and earlier must keep the current omit-the-parameter behaviour.
So it wants to be per-model, not per-provider — which may mean DisableWire needs a model-aware variant, or the choice moves to where the model id is known.
Impact
This is what forces a non-thinking tier to be Haiku 4.5. There is currently no way to get a fast, non-thinking turn out of Opus 5 or Sonnet 5 through dirge, even though the API supports it.
Happy to put up a PR if the shape above looks right — say if you'd rather have it structured differently (e.g. keep DisableWire per-provider and gate on the model at the call site).
Claim
From the 0.24.1 changelog, introducing
/effort:On current Anthropic models it does not.
effort: "off"(and/effort off) leaves thinking fully enabled onclaude-sonnet-5,claude-opus-5andclaude-fable-5, so a user who explicitly opts out still pays the latency and the reasoning tokens — silently, on the one setting whose whole purpose is opting out.Cause
adapter.rsgives each provider aDisableWiredescribing how thinking is turned off. Anthropic's isNone— "omit the parameter":Omitting
thinkingwas a correct disable for Claude 4.6 and earlier. It stopped being one on the current generation:thinkingomittedSo the wire shape didn't change; what omitting it means did.
The payload already exists in the codebase
Anthropic is one of only three providers left on
DisableWire::None; five others carry real disable wires (ThinkingToggle,ChatTemplateKwargs,GeminiZeroBudget,OllamaThink).Notably GLM — which mimics Anthropic's API — is on
ThinkingToggle, which emits:{"thinking": {"type": "disabled"}}That is Anthropic's own documented shape. dirge already sends exactly the payload Anthropic needs; it just doesn't send it to Anthropic.
Why the fix is not a one-line table change
Model support is uneven, so a blanket switch to
ThinkingTogglewould trade this bug for 400s:{"type": "disabled"}.highor below — pairing it withxhigh/maxis rejected. Sinceoffmeans no thinking at all, that combination shouldn't arise, but the constraint is worth encoding rather than assuming.offcan never be honoured; warning that the level is unavailable seems more honest than silently accepting it.So it wants to be per-model, not per-provider — which may mean
DisableWireneeds a model-aware variant, or the choice moves to where the model id is known.Impact
This is what forces a non-thinking tier to be Haiku 4.5. There is currently no way to get a fast, non-thinking turn out of Opus 5 or Sonnet 5 through dirge, even though the API supports it.
Happy to put up a PR if the shape above looks right — say if you'd rather have it structured differently (e.g. keep
DisableWireper-provider and gate on the model at the call site).