How hard the model thinks
A reasoning model spends time thinking before it answers, and how much is a per-request
setting: reasoning_effort on the OpenAI wire, which OpenRouter forwards to the model. It is the
single biggest lever on how long a round takes, and until 2026-09-10 the platform could only set it
one way — by editing the model node, for everyone.
The three rungs
Resolved in AgentChatClient where the round builds its one ChatOptions, so a single decision
covers every provider call the round makes, tool-loop iterations included.
| # | Where | Who sets it | Wins over |
|---|---|---|---|
| 1 | ThreadComposer.Effort — the /effort pick |
the person chatting | everything |
| 2 | ModelDefinition.ReasoningEffort on the LanguageModel node |
an admin, for the whole deployment | the provider |
| 3 | nothing is sent | the provider decides | — |
Rung 3 is not neutral. A model whose reasoning cannot be switched off ships with it ON, usually
at its highest setting: z-ai/glm-5.3 defaults to max, and an Executive Assistant round of nine
cheap tool calls took 3 min 11 s on it — 74 s of thinking before the first call, four times over
(AI/RoundTiming is what measured that). So "we set nothing" is a choice, and usually the slow one.
A blank rung 1 is declining, not choosing. Picking Model default writes an empty string, which is a real write that hands the decision back to rung 2 — that is why it is a row in the menu with a ✓ of its own rather than the absence of a selection.
Choosing it
- In the chat —
/effort, or the ⚡ chip in the status row under the composer. The chip renders the EFFECTIVE value: your pick if you made one, else what the model declares, elseautofor the provider's default; its tooltip says which of the three it is showing. The pick lives on your composer, so it follows you across tabs and threads until you change it. - On the model, for everyone — set
reasoningEfforton theLanguageModelnode (none·low·medium·high·max;minimal/xhighand friends resolve too). This is the deployment's default for that model and is what the/modelmenu shows on each row's second line, so the trade-off is visible while you are choosing the model. - Nothing to deploy either way. Both are data: the node is a mesh edit, the pick is a composer write.
An unknown spelling costs the SETTING, never the model: ReasoningEffortParser answers "send
nothing" and the round logs one warning naming the model and the spelling. A model with no reasoning
phase ignores the field entirely, so setting it is safe across a mixed catalog.
Under the Claude Code harness
/effort belongs to the CLI there, and the portal forwards the command 1:1 — the levels are the
CLI's own and the chip shows what the CLI reports. The mesh rungs above apply to the MeshWeaver
harness, which is the one that talks to a provider itself.
Why the picker takes VALUES, not nodes
/effort is the first Pick skill whose options are not mesh nodes. SkillAction.Choices is that
shape: a fixed list of {value, label, description} on the skill's own front matter, rendered by the
same widget, with the same keyboard handling and the same row anatomy as /agent and /model, and
written to the named composer field verbatim. The alternative — seeding five ReasoningEffort nodes
into every mesh before the setting can be chosen at all — makes a word the provider already
understands into a deployment step.
Any skill can use it: declare choices: instead of query: under action:. A skill that declares
both keeps its query, so nothing existing changes meaning.
What the menu shows
One row shape for every pick (ThreadChatView.PickerRow): icon column, name, one meta line, and a ✓
on whatever is selected right now. A model's meta line is derived from its definition — how hard it
thinks, and its per-million prices — because a model node carries no description and a row that only
repeats the wire id tells the person choosing nothing they did not already type.
Models group under their provider's title by the nearest title that OWNS their namespace, not by the
namespace itself. Every model the catalog sync writes sits directly under its provider with the
vendor prefix inside the id (Provider/OpenRouter + openai/gpt-5.2); a model created by hand
splits that id at the slash and lands one level deeper (Provider/OpenRouter/z-ai + glm-5.3). Both
are the same model under the same provider, and before this the second one rendered as an untitled
row after the whole block — configured, pinned to the top of its provider by Order: -2, and
unfindable by anyone scrolling for it.