Problem or Motivation
OpenWork supports six per-session thinking levels (off / low / medium /
high / xhigh / max), but there is no way to change the thinking level from
the chat composer. Today the only place to influence it is Settings → AI, which
sets a per-workspace default for new chats. To dial reasoning effort up for a
single hard task or down for a quick one, you have to leave the conversation, open
settings, change the default, and start a new chat.
Comparable desktop apps put this control right in the composer, next to the model
picker: Claude Code Desktop ships a dedicated effort menu (⌘⇧E) alongside its
model menu, so you can raise or lower reasoning effort per message without leaving
the prompt.
OpenWork already has the neighbor for it — the composer has a model picker
dropdown — but the thinking-level equivalent is missing even though all the
plumbing is already in place:
- The composer (
FreeFormInput) already receives thinkingLevel and
onThinkingLevelChange props — they are threaded from ChatPage /
DraftChatPage → ChatDisplay → ChatInputZone → InputContainer →
FreeFormInput, and both pages already persist the value (draft
createOptions.thinkingLevel / session options). But FreeFormInput never
renders a trigger for it — the prop is only read for an ACP command refresh.
- The level metadata already exists:
THINKING_LEVELS (id + nameKey +
descriptionKey) in packages/shared/src/agent/thinking-levels.ts, and the
thinking.* translation keys are already present in all locales.
So the value is fully wired end-to-end — the app just has no UI to set it from the
place you actually compose.
Proposed Solution
Add a thinking-level picker to the composer toolbar, immediately before the
model picker, mirroring the existing model-picker dropdown:
- A toolbar button showing the current level's name (e.g. "Medium") with a brain
icon and a chevron; tooltip "Thinking".
- Opening it lists all six levels (
THINKING_LEVELS order) with name +
description, a check on the active level, and calls the already-wired
onThinkingLevelChange(level) on select — so the choice persists exactly like a
model change does.
- Hidden in
compactMode (same rule the model picker uses).
This is a frontend-only change:
- It renders a Radix dropdown (the same
StyledDropdownMenu* primitives the model
picker uses) and calls the existing onThinkingLevelChange prop. No backend / no
qwen-code change — the value already flows to the runtime today.
- It introduces no new i18n keys: level names/descriptions reuse the existing
thinking.* keys and the trigger tooltip reuses settings.ai.thinking.
Alternatives Considered
- Settings → AI thinking default already exists, but it is a workspace
default for new chats, not a per-conversation control. You can't raise effort
for the current task without starting over.
- A keyboard-only shortcut (à la
⌘⇧E) could open a menu, but OpenWork's
established pattern for composer controls is a visible toolbar dropdown (the
model picker), so a visible picker is the more discoverable, consistent fit. A
shortcut can be layered on later.
Additional Context
Feasibility: frontend-only / doable. Verified against apps/electron — the
thinkingLevel / onThinkingLevelChange props already reach FreeFormInput and
both the draft and active chat pages already persist the value; only the UI trigger
is missing.
Acceptance criteria (CDP e2e assertion)
A new e2e/assertions/thinking-level-picker.assert.ts drives the real built app
over CDP and asserts the full path:
- The composer renders a thinking-level trigger button.
- Clicking it opens a menu listing all six thinking levels.
- The trigger reflects a known current level (the default), and the active level
is marked as selected in the menu.
- Selecting a different level closes the menu and updates the trigger
label to the newly selected level — proving the picker actually changes the
session's thinking level, not merely displays a list.
Part of the autonomous desktop-feature loop (loop-bot).
Problem or Motivation
OpenWork supports six per-session thinking levels (
off/low/medium/high/xhigh/max), but there is no way to change the thinking level fromthe chat composer. Today the only place to influence it is Settings → AI, which
sets a per-workspace default for new chats. To dial reasoning effort up for a
single hard task or down for a quick one, you have to leave the conversation, open
settings, change the default, and start a new chat.
Comparable desktop apps put this control right in the composer, next to the model
picker: Claude Code Desktop ships a dedicated effort menu (
⌘⇧E) alongside itsmodel menu, so you can raise or lower reasoning effort per message without leaving
the prompt.
OpenWork already has the neighbor for it — the composer has a model picker
dropdown — but the thinking-level equivalent is missing even though all the
plumbing is already in place:
FreeFormInput) already receivesthinkingLevelandonThinkingLevelChangeprops — they are threaded fromChatPage/DraftChatPage→ChatDisplay→ChatInputZone→InputContainer→FreeFormInput, and both pages already persist the value (draftcreateOptions.thinkingLevel/ session options). ButFreeFormInputneverrenders a trigger for it — the prop is only read for an ACP command refresh.
THINKING_LEVELS(id +nameKey+descriptionKey) inpackages/shared/src/agent/thinking-levels.ts, and thethinking.*translation keys are already present in all locales.So the value is fully wired end-to-end — the app just has no UI to set it from the
place you actually compose.
Proposed Solution
Add a thinking-level picker to the composer toolbar, immediately before the
model picker, mirroring the existing model-picker dropdown:
icon and a chevron; tooltip "Thinking".
THINKING_LEVELSorder) with name +description, a check on the active level, and calls the already-wired
onThinkingLevelChange(level)on select — so the choice persists exactly like amodel change does.
compactMode(same rule the model picker uses).This is a frontend-only change:
StyledDropdownMenu*primitives the modelpicker uses) and calls the existing
onThinkingLevelChangeprop. No backend / noqwen-code change — the value already flows to the runtime today.
thinking.*keys and the trigger tooltip reusessettings.ai.thinking.Alternatives Considered
default for new chats, not a per-conversation control. You can't raise effort
for the current task without starting over.
⌘⇧E) could open a menu, but OpenWork'sestablished pattern for composer controls is a visible toolbar dropdown (the
model picker), so a visible picker is the more discoverable, consistent fit. A
shortcut can be layered on later.
Additional Context
Feasibility: frontend-only / doable. Verified against
apps/electron— thethinkingLevel/onThinkingLevelChangeprops already reachFreeFormInputandboth the draft and active chat pages already persist the value; only the UI trigger
is missing.
Acceptance criteria (CDP e2e assertion)
A new
e2e/assertions/thinking-level-picker.assert.tsdrives the real built appover CDP and asserts the full path:
is marked as selected in the menu.
label to the newly selected level — proving the picker actually changes the
session's thinking level, not merely displays a list.
Part of the autonomous desktop-feature loop (
loop-bot).