Skip to content

fix(agents): recognize params.thinking=false and "disabled"/"none" as thinking=off#74418

Merged
steipete merged 4 commits into
openclaw:mainfrom
yelog:fix/deepseek-v4-thinking-false-74374
May 31, 2026
Merged

fix(agents): recognize params.thinking=false and "disabled"/"none" as thinking=off#74418
steipete merged 4 commits into
openclaw:mainfrom
yelog:fix/deepseek-v4-thinking-false-74374

Conversation

@yelog

@yelog yelog commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #74374

resolveThinkingDefault only recognized string values like "off", "low", "high", etc. for per-model params.thinking. When a user configured params.thinking: false (boolean) or params.thinking: "disabled" — both common ways to express "no thinking" — the value fell through to the model/provider default (e.g. "high" for DeepSeek v4-pro).

This caused the DeepSeek thinking stream wrapper to inject reasoning_content into assistant messages and set thinking: { type: "enabled" }. If the user also configured extra_body: { thinking: { type: "disabled" } }, the extra_body wrapper then overwrote thinking to disabled — but reasoning_content was already in the messages. DeepSeek's API rejects this inconsistent state with:

400 "reasoning_content must be passed back"

Changes

  • resolveThinkingDefault now treats false, "disabled", and "none" as "off"
  • Added 3 tests for each alias (DeepSeek v4-pro model config)

Root Cause

src/agents/model-thinking-default.ts:42-52 only matched string values against the known thinking levels. Boolean false and aliases like "disabled" / "none" were not handled, causing them to fall through to the provider default. The DeepSeek V4 wrapper (createDeepSeekV4OpenAICompatibleThinkingWrapper) already handles "none" correctly at the stream level, but it was never reached because thinkingLevel was resolved to the wrong value upstream.

Real behavior proof

Behavior addressed: DeepSeek V4 has provider default thinking high, but model-level disabled aliases must resolve to OpenClaw thinking off before request payload shaping.
Real environment tested: local OpenClaw source checkout using fork PR head 676e44b3db5b73dbd564221a2b023e708ea419a5.
Exact steps or command run after this patch:

node --import tsx -e '<script imports resolveThinkingDefault, defines a DeepSeek V4 catalog default of high, sets agents.defaults.models["deepseek/deepseek-v4-pro"].params.thinking to false/disabled/none, and prints only resolved levels>'

Evidence after fix:

{
  "branch": "fork/fix/deepseek-v4-thinking-false-74374",
  "head": "676e44b3db5b73dbd564221a2b023e708ea419a5",
  "command": "node --import tsx resolveThinkingDefault proof",
  "providerDefault": "high",
  "cases": [
    {
      "input": false,
      "resolved": "off"
    },
    {
      "input": "disabled",
      "resolved": "off"
    },
    {
      "input": "none",
      "resolved": "off"
    }
  ]
}

Observed result after fix: all three disabled aliases resolve to off instead of falling through to the provider default high.
What was not tested: No live DeepSeek HTTP request was sent; this proof exercises the production thinking resolver locally and avoids printing prompts, credentials, or provider responses.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Apr 29, 2026
@greptile-apps

greptile-apps Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes resolveThinkingDefault to treat params.thinking: false, "disabled", and "none" as "off", preventing those values from falling through to the provider/model default and causing an inconsistent API state with DeepSeek V4-pro. Three targeted unit tests cover each new alias.

Confidence Score: 5/5

This PR is safe to merge — the change is small, well-scoped, and fully tested.

The fix is minimal (8 lines) and directly addresses the documented root cause. All three new aliases are covered by unit tests, and there are no side effects on the existing code paths. No P0/P1 issues found.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(agents): recognize boolean false and..." | Re-trigger Greptile

@clawsweeper

clawsweeper Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed May 31, 2026, 9:42 AM ET / 13:42 UTC.

Summary
The PR makes per-model params.thinking values false, disabled, and none resolve to OpenClaw thinking off in the shared agent resolver and auto-reply model-selection path, with targeted tests.

PR surface: Source +16, Tests +103. Total +119 across 4 files.

Reproducibility: yes. Current-main source inspection shows the disabled aliases are not recognized before fallback, and the PR adds focused tests that exercise the expected off result for the reported DeepSeek configuration shape.

Review metrics: 1 noteworthy metric.

  • Per-model thinking aliases: 3 added disabled aliases. Existing configs using false, disabled, or none now resolve as explicit thinking off instead of inheriting later defaults.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🐚 platinum hermit
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Update the PR body with redacted current-head terminal output showing all three aliases resolving to off through both the shared resolver and auto-reply model-selection path.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR includes useful terminal-style resolver proof, but it targets an older head and does not cover the current head's added auto-reply path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The PR changes compatibility-sensitive config interpretation: existing per-model configs using false, disabled, or none now mean explicit thinking off instead of falling through to a global or provider default.
  • [P1] The supplied real-behavior proof is for older head 676e44b3db5b73dbd564221a2b023e708ea419a5 and only demonstrates the shared resolver; current head 0599a3ad36e376fc1c4e7996c861f6cdd059c1b1 also changes auto-reply and needs current-head proof before merge.

Maintainer options:

  1. Refresh Current-Head Proof (recommended)
    Have the PR body show current-head terminal output covering both resolveThinkingDefault and the auto-reply createModelSelectionState path before merge.
  2. Accept Alias Compatibility
    Maintainers can intentionally accept that false, disabled, and none now override provider/global defaults as explicit off, preferably with release-note context in the squash message or PR body.
  3. Pause For Narrower Alias Policy
    If generic disabled/none aliases are not desired for all per-model config, pause this PR and choose a narrower canonical normalization policy first.

Next step before merge

  • [P1] Remaining work is maintainer acceptance of the compatibility change plus current-head proof, not an automated code repair.

Security
Cleared: No security or supply-chain concern found; the diff is limited to TypeScript resolver logic and tests, with no dependency, workflow, secret, or package changes.

Review details

Best possible solution:

Land the narrow alias handling after current-head proof and maintainer acceptance of the config compatibility change; keep the broader extra_body collision work tracked separately at #75040 and #74403.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main source inspection shows the disabled aliases are not recognized before fallback, and the PR adds focused tests that exercise the expected off result for the reported DeepSeek configuration shape.

Is this the best way to solve the issue?

Yes for this PR's bug boundary. Updating the two existing thinking-default resolution paths is narrower than changing provider request wrappers, while the broader extra_body collision remains a separate canonical item.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 75e0053cf969.

Label changes

Label changes:

  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR includes useful terminal-style resolver proof, but it targets an older head and does not cover the current head's added auto-reply path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.
  • remove status: 👀 ready for maintainer look: Current PR status label is status: 📣 needs proof.

Label justifications:

  • P2: The PR fixes a normal-priority DeepSeek/provider thinking-default bug with limited surface area and focused tests.
  • merge-risk: 🚨 compatibility: The diff changes how existing per-model config values are interpreted during upgrades and model selection.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR includes useful terminal-style resolver proof, but it targets an older head and does not cover the current head's added auto-reply path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +16, Tests +103. Total +119 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 16 0 +16
Tests 2 103 0 +103
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 119 0 +119

What I checked:

Likely related people:

  • tynamite: Authored the current-main auto-reply change that made per-model params.thinking take precedence over the global thinking default. (role: recent area contributor; confidence: high; commits: 2f7e6ec196fd; files: src/auto-reply/reply/model-selection.ts, src/auto-reply/reply/model-selection.test.ts)
  • Mark L: Authored the earlier per-model thinking-default precedence change that this PR extends with disabled aliases. (role: introduced behavior; confidence: medium; commits: 0f2dce0483c0; files: src/agents/model-selection.ts, src/agents/model-selection.test.ts)
  • steipete: Assigned and force-pushed the current PR head, including the auto-reply disabled-alias follow-up commit. (role: recent PR follow-up owner; confidence: medium; commits: 0599a3ad36e3; files: src/auto-reply/reply/model-selection.ts, src/auto-reply/reply/model-selection.test.ts)
  • Vincent Koc: Moved the shared thinking default logic into model-thinking-default.ts, which is the central resolver this PR updates. (role: refactor owner; confidence: medium; commits: 117ae85bf5c7; files: src/agents/model-thinking-default.ts, src/agents/model-selection.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@yelog

yelog commented May 19, 2026

Copy link
Copy Markdown
Contributor Author

After-fix real behavior proof from the PR head, redacted to resolver inputs and outputs only.

Behavior addressed: DeepSeek V4 has provider default thinking high, but model-level disabled aliases must resolve to OpenClaw thinking off before request payload shaping.
Real environment tested: local OpenClaw source checkout using fork PR head 676e44b3db5b73dbd564221a2b023e708ea419a5.
Exact steps or command run after this patch:

node --import tsx -e '<script imports resolveThinkingDefault, defines a DeepSeek V4 catalog default of high, sets agents.defaults.models["deepseek/deepseek-v4-pro"].params.thinking to false/disabled/none, and prints only resolved levels>'

Evidence after fix:

{
  "branch": "fork/fix/deepseek-v4-thinking-false-74374",
  "head": "676e44b3db5b73dbd564221a2b023e708ea419a5",
  "command": "node --import tsx resolveThinkingDefault proof",
  "providerDefault": "high",
  "cases": [
    {
      "input": false,
      "resolved": "off"
    },
    {
      "input": "disabled",
      "resolved": "off"
    },
    {
      "input": "none",
      "resolved": "off"
    }
  ]
}

Observed result after fix: all three disabled aliases resolve to off instead of falling through to the provider default high.
What was not tested: No live DeepSeek HTTP request was sent; this proof exercises the production thinking resolver locally and avoids printing prompts, credentials, or provider responses.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels May 19, 2026
@giodl73-repo giodl73-repo removed the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 21, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 21, 2026
@clawsweeper

clawsweeper Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Clockwork Test Hopper

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: sparkles near resolved comments.
Image traits: location workflow harbor; accessory miniature diff map; palette pearl, teal, and neon green; mood determined; pose balancing on a branch marker; shell polished stone shell; lighting soft underwater shimmer; background quiet workflow signs.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Clockwork Test Hopper in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@yelog

yelog commented May 22, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 22, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 22, 2026
@yelog
yelog force-pushed the fix/deepseek-v4-thinking-false-74374 branch from 676e44b to d0a19d2 Compare May 27, 2026 09:05
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 27, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels May 27, 2026
@clawsweeper

clawsweeper Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@steipete steipete self-assigned this May 31, 2026
@steipete
steipete force-pushed the fix/deepseek-v4-thinking-false-74374 branch from d0a19d2 to 0599a3a Compare May 31, 2026 13:35
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 31, 2026
@steipete

Copy link
Copy Markdown
Contributor

Behavior addressed: params.thinking now treats false, disabled, and none as the existing off state in both normal agent model selection and auto-reply duplicate-precheck model selection.

Real environment tested: local targeted Vitest in this checkout plus GitHub Actions on PR head 0599a3a.

Exact steps or command run after this patch:

  • node scripts/run-vitest.mjs src/agents/model-selection.test.ts src/auto-reply/reply/model-selection.test.ts
  • git diff --check
  • .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
  • gh run rerun 26714087694 --failed
  • gh run view 26714087694 --job 78731190189 --log-failed

Evidence after fix:

  • Local targeted Vitest passed: 2 shards, 53 + 118 tests, 29.63s.
  • git diff --check passed.
  • Autoreview clean: no accepted/actionable findings reported.
  • CI run 26714087694 has 117 successful checks after rerun.

Observed result after fix: disabled model params keep thinking off ahead of any global thinkingDefault, including auto-reply precheck routing.

What was not tested: full local suite. Known CI proof gap: build-artifacts job 78731190189 fails in the unrelated core-support-boundary lane at scripts/plugin-prerelease-test-plan.test.ts:163 and :185 because that test still expects docker_e2e_docker_cmd stats --no-stream while the current scripts use docker_e2e_sample_stats_until_exit. This failure is outside the touched agent and auto-reply model-selection paths and reproduced after a failed-job rerun.

@steipete
steipete merged commit fdf6092 into openclaw:main May 31, 2026
263 of 272 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: DeepSeek v4-pro: 400 "reasoning_content must be passed back" with thinking=disabled

3 participants