You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When connecting Open WebUI (or any OpenAI-compatible frontend) to Hermes's API server with a DeepSeek V4 backend, two independent gaps prevent reasoning/thinking content from reaching the SSE stream. The reasoning_effort configured in config.yaml is also silently dropped before it hits the DeepSeek API.
Gap 1 — reasoning_effort + thinking never sent to DeepSeek API
File:agent/transports/chat_completions.py
The transport layer injects reasoning_effort as a top-level kwarg only for Kimi (line 272), TokenHub (line 287), and LM Studio (line 305). It injects extra_body.thinking only for Kimi (line 342). No DeepSeek branch exists. DeepSeek V4 requires:
Additionally, extra_body.reasoning (line 353) is gated behind params.get("supports_reasoning", False), which comes from AIAgent._supports_reasoning_extra_body() (run_agent.py:3476). That method returns False for direct DeepSeek connections because of the guard at line 3501:
The reasoning_effort value IS correctly read from config by GatewayRunner._load_reasoning_config() and passed as reasoning_config dict through to the agent. It just never reaches the wire.
Gap 2 — reasoning_content discarded in API server streaming pipeline
The agent correctly captures delta.reasoning_content from DeepSeek's streaming response (chat_completion_helpers.py). It fires agent._fire_reasoning_delta(text) which calls self.reasoning_callback(text) (run_agent.py:3038-3044).
Three missing pieces in gateway/platforms/api_server.py:
_create_agent() (lines 893-911) never passes reasoning_callback.AIAgent.__init__ accepts it (run_agent.py:382) and _fire_reasoning_delta dispatches through it — but the API server never wires it. Compare with stream_delta_callback (line 903) which IS wired.
_handle_chat_completions (lines 1218-1220) only registers three callbacks:
stream_delta_callback=_on_delta
tool_start_callback=_on_tool_start
tool_complete_callback=_on_tool_complete
No reasoning_callback is created or passed.
_write_sse_chat_completion (line 1398) has no mechanism to emit delta.reasoning_content chunks. The SSE writer only handles:
Open WebUI has supported rendering delta.reasoning_content in a collapsible "Thinking" panel since early v0.5.x (PR chore(models): refresh OpenRouter + Nous fallback lists #23001 fixed a rendering bug March 2026, but field recognition itself is older).
Suggested patches
Patch A — DeepSeek reasoning_effort + thinking injection
agent/transports/chat_completions.py, after the TokenHub block (~line 299):
Summary
When connecting Open WebUI (or any OpenAI-compatible frontend) to Hermes's API server with a DeepSeek V4 backend, two independent gaps prevent reasoning/thinking content from reaching the SSE stream. The
reasoning_effortconfigured inconfig.yamlis also silently dropped before it hits the DeepSeek API.Gap 1 —
reasoning_effort+thinkingnever sent to DeepSeek APIFile:
agent/transports/chat_completions.pyThe transport layer injects
reasoning_effortas a top-level kwarg only for Kimi (line 272), TokenHub (line 287), and LM Studio (line 305). It injectsextra_body.thinkingonly for Kimi (line 342). No DeepSeek branch exists. DeepSeek V4 requires:{ "reasoning_effort": "max", "extra_body": {"thinking": {"type": "enabled"}} }Additionally,
extra_body.reasoning(line 353) is gated behindparams.get("supports_reasoning", False), which comes fromAIAgent._supports_reasoning_extra_body()(run_agent.py:3476). That method returnsFalsefor direct DeepSeek connections because of the guard at line 3501:The
reasoning_effortvalue IS correctly read from config byGatewayRunner._load_reasoning_config()and passed asreasoning_configdict through to the agent. It just never reaches the wire.Gap 2 —
reasoning_contentdiscarded in API server streaming pipelineThe agent correctly captures
delta.reasoning_contentfrom DeepSeek's streaming response (chat_completion_helpers.py). It firesagent._fire_reasoning_delta(text)which callsself.reasoning_callback(text)(run_agent.py:3038-3044).Three missing pieces in
gateway/platforms/api_server.py:_create_agent()(lines 893-911) never passesreasoning_callback.AIAgent.__init__accepts it (run_agent.py:382) and_fire_reasoning_deltadispatches through it — but the API server never wires it. Compare withstream_delta_callback(line 903) which IS wired._handle_chat_completions(lines 1218-1220) only registers three callbacks:stream_delta_callback=_on_deltatool_start_callback=_on_tool_starttool_complete_callback=_on_tool_completeNo
reasoning_callbackis created or passed._write_sse_chat_completion(line 1398) has no mechanism to emitdelta.reasoning_contentchunks. The SSE writer only handles:("__tool_progress__", payload)→ customevent: hermes.tool.progressdelta.contentThe standard OpenAI format for reasoning content is:
{"choices": [{"index": 0, "delta": {"reasoning_content": "..."}, "finish_reason": null}]}Open WebUI has supported rendering
delta.reasoning_contentin a collapsible "Thinking" panel since early v0.5.x (PR chore(models): refresh OpenRouter + Nous fallback lists #23001 fixed a rendering bug March 2026, but field recognition itself is older).Suggested patches
Patch A — DeepSeek reasoning_effort + thinking injection
agent/transports/chat_completions.py, after the TokenHub block (~line 299):Patch B — Wire reasoning_callback in API server
File:
gateway/platforms/api_server.pyIn
_handle_chat_completions(~line 1162, after_on_delta):In the
_run_agentcall (~line 1218), add:In
_write_sse_chat_completion(~line 1398), add before theelsebranch:Verification
After both patches:
reasoning_effortandextra_body.thinkingdelta.reasoning_contentchunksFull technical audit with streaming-path diagram and verified line numbers is available if needed.