What an Effort Level Actually Sends to the Model
Pick an effort level and Atlarix sends one value in the request. Which value, and under which key, is decided by a resolution step you never see — until a model silently ignores what you asked for. This is that step, from the click to the request body.
The level is matched against the model, not the UI
The control you see lists the model's own levels because that's the only list it's safe to send. A model that lists low, high, max never receives medium, because it would reject it — kimi-k3 is the live example. So /effort resolves the chosen level against the model's declared values first: if the model lists it, it goes out exactly as listed; if not, it never gets invented.
The old boolean maps to a ceiling
The Deep-thinking toggle still exists underneath, mapped onto the same resolution. ON asks for the model's true maximum; OFF sits one step below it — and one step below walks the model's own list, not a global ladder. A model whose list is low, high, max gets high when the switch is off, never the medium it doesn't accept.
The camelCase trap
The effort value is set as reasoningEffort and lands on the wire as reasoning_effort — and the casing is exactly where this once failed silently. The OpenAI-compatible SDK spreads your provider options into the request body and then writes reasoning_effort from its own reasoningEffort field. Set a snake_case reasoning_effort yourself and that write clobbers it with undefined, and JSON.stringify drops the key entirely. The request looked right and sent nothing. It's fixed now, and it's asserted against the real request body in a test — the only way a casing bug stays fixed.
Resolved in main, not in the renderer
There's a reason this resolution lives in the main process. The first version called the capability lookups from the renderer, and they always missed: the models.dev reasoning registry and the Core routing map are main-process module state, so from the renderer every lookup came back empty and the toggle vanished for the whole Atlarix Core lineup. The fix wasn't a new IPC channel — it's the level resolved in main and stamped onto each model row before the renderer reads it.
How we know it's really on the wire
A control that silently sends nothing is the worst kind of bug, so the test asserts the actual request body rather than the resolver's return value. It runs a turn against a fake server and reads the requests the server captured — so if the key goes out snake_case, or a level gets invented, the test fails on the bytes the provider would have seen.
Effort looks like one control, but it's a small resolution pipeline: match against the model's declared values, map the legacy boolean to a ceiling, resolve in the process that owns the catalog, and send under the one key the SDK won't drop. Most of that machinery exists to avoid a single failure mode — asking for something and getting nothing.