Skip to content

fix(agent): send thinking:disabled for DeepSeek V4 and retry reasoning-only responses - #688

Open
iojaffee wants to merge 1 commit into
nashsu:mainfrom
iojaffee:fix/deepseek-backend-thinking-disabled
Open

fix(agent): send thinking:disabled for DeepSeek V4 and retry reasoning-only responses#688
iojaffee wants to merge 1 commit into
nashsu:mainfrom
iojaffee:fix/deepseek-backend-thinking-disabled

Conversation

@iojaffee

Copy link
Copy Markdown

What

Fixes #685 — the backend agent path never sent thinking: { type: "disabled" } for DeepSeek V4 models, so deepseek-v4-flash/deepseek-v4-pro could spend its entire max_tokens budget on reasoning_content and return an empty content, surfacing as LLM response did not contain assistant content in the UI chat.

Root cause

Three compounding issues in src-tauri/src/agent/provider.rs:

  1. structured_task_config forced reasoning: auto, overriding the user's explicit reasoning choice from Settings. So even choosing "off" had no effect on backend agent turns.
  2. apply_openai_reasoning returned early for custom providers, so the DeepSeek preset (provider: custom, api.deepseek.com) never received the thinking field the frontend sends (src/lib/llm-providers.ts:466-481).
  3. No retry fallback: when the model produced only reasoning_content with no final content, both generate_openai_like and stream_openai_like surfaced the opaque error instead of retrying with thinking disabled (the frontend direct path already does this via isReasoningOnlyResponseError in chat-panel.tsx:1197-1208).

Changes

  • apply_openai_reasoning: mirror the frontend DeepSeek handling — thinking: {type:"disabled"} on off; thinking: {type:"enabled"} + reasoning_effort on high/max; nothing on auto.
  • structured_task_config: keep the user's explicit reasoning choice; fall back to the portable auto default only when unset.
  • generate_openai_like / stream_openai_like: retry once with thinking disabled when the response contained only reasoning and no final content (guarded to DeepSeek V4 endpoints only).

Tests

Added 9 unit tests (all passing, 30/30 in agent::provider):

  • deepseek_endpoint_detection, deepseek_v4_model_detection
  • deepseek_reasoning_off_sends_thinking_disabled
  • deepseek_reasoning_high_sends_thinking_enabled_with_effort
  • deepseek_reasoning_auto_omits_controls
  • structured_task_config_keeps_user_explicit_reasoning
  • structured_task_config_defaults_to_auto_when_unset
  • can_retry_thinking_only_for_deepseek_v4
  • reasoning_only_error_detection
  • Updated structured_task_config_raises_output_budget_and_keeps_explicit_reasoning (was: forced auto)

Verification

Reproduced against live api.deepseek.com before the fix: complex agent prompt + deepseek-v4-flash streaming → 6599 SSE chunks all reasoning_content, content stayed null, finish_reason: length. Same prompt with thinking: {type:"disabled"} → full content returned reliably. cargo check and all 30 provider tests pass.

…g-only responses

Backend agent path (structured_task_config) previously forced reasoning=auto
and never sent the DeepSeek thinking field, so deepseek-v4-flash/pro could
spend its whole max_tokens budget on reasoning_content and return an empty
content, surfacing as 'LLM response did not contain assistant content'.

- apply_openai_reasoning now mirrors the frontend (llm-providers.ts):
  DeepSeek V4 endpoints get thinking:{type:disabled} on 'off', and
  thinking:{type:enabled}+reasoning_effort on high/max.
- structured_task_config keeps an explicit user reasoning choice instead of
  overriding it to auto (falls back to auto only when unset).
- generate/stream_openai_like retry once with thinking disabled when the
  response contained only reasoning_content and no final content.

Fixes nashsu#685
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant