Skip to content

feat: reasoning effort control in Web UI (/reasoning command + settings) #461

Description

@nesquena-hermes

Summary

The Web UI has no way to control reasoning effort. The CLI offers /reasoning [none|minimal|low|medium|high|xhigh] which sets the effort level for the current session, and /reasoning [show|hide] which toggles whether the thinking block is visible in the response. Neither control exists in the Web UI — users get whatever the model defaults to and cannot change it without editing config.yaml on the server and restarting.

Current state

In the CLI, /reasoning high calls _parse_reasoning_config("high") which produces {"enabled": true, "effort": "high"} and stores it in agent.reasoning_effort in config.yaml. On the next turn the agent is re-initialized with reasoning_config set, which flows into the model API call as extra_body["reasoning"] (for OpenRouter), thinking kwargs (for Anthropic direct), or reasoning.effort (for Codex/Responses API).

In the Web UI, _run_agent_streaming() (api/streaming.py) constructs the AIAgent with no reasoning_config argument at all. The streaming endpoint POST /api/chat/start also accepts no reasoning_effort field. The Web UI does correctly stream and render reasoning SSE events (thinking blocks), but it cannot set the effort level that generates them.

Proposed solution

Two surfaces:

1. Per-session slash command/reasoning [level] and /reasoning [show|hide] in the Web UI command list (static/commands.js). These pass through to the agent as regular messages (same pattern as skill slash commands — issue #460). The agent already handles these correctly when sent as user messages. The dropdown should show the valid levels as autocomplete hints.

2. Persistent setting in the Settings panel — a "Reasoning effort" selector (none / minimal / low / medium / high / xhigh) that writes to /api/settings and is forwarded to the agent config. This lets users set a default level that persists across sessions, not just the current one.

Backend change required: _run_agent_streaming() needs to accept a reasoning_effort parameter and pass it as reasoning_config to AIAgent. The /api/chat/start POST body should accept reasoning_effort. The /api/settings POST handler should accept and persist reasoning_effort to the agent's config.yaml (not just the WebUI settings store).

Reasoning visibility — the existing thinking-block toggle in the UI already handles show/hide at render time, so /reasoning show|hide could just toggle that display setting directly.

Valid effort levels

From hermes_cli/commands.py: none, minimal, low, medium, high, xhigh

  • none{"enabled": false} — disables reasoning entirely
  • minimalxhigh{"enabled": true, "effort": "<level>"}
  • Empty / unset → model default (currently medium on OpenRouter)

Files involved

  • ~/.hermes/hermes-agent/hermes_constants.pyparse_reasoning_effort()
  • ~/hermes-webui-public/api/streaming.py_run_agent_streaming()
  • ~/hermes-webui-public/api/routes.py/api/chat/start, /api/settings
  • ~/hermes-webui-public/static/commands.js — add /reasoning to COMMANDS
  • ~/hermes-webui-public/static/panels.js — Settings panel reasoning selector

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions