openclaw - ✅(Solved) Fix DeepSeek V4: xhigh/max thinking levels not exposed in model profile [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#77047Fetched 2026-05-05 05:53:05
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
3
Author
Timeline (top)
cross-referenced ×2closed ×1commented ×1

Root Cause

From code analysis of the dist:

  1. ws() function (which provides model thinking levels) only returns Ss = [off, minimal, low, medium, high] — the basic five levels.
  2. The full list Fs = [..., xhigh, adaptive, max] exists but is not returned by default for DeepSeek models.
  3. The model profile (deepseek-v4-pro) only has reasoning: true without any thinkingLevels declaration.
  4. The model schema has additionalProperties: false, so thinkingLevels cannot be added to the model config at user level.

Fix Action

Fixed

PR fix notes

PR #77151: fix(channels): do not mark optional-with-default fields as required in channel config json schema

Description (problem / solution / changelog)

Summary

  • Problem: Pre-existing channel configs (Feishu, Bluebubbles, IRC, Line, Nextcloud Talk, Zalouser) crash the gateway in a restart loop after upgrading to 2026.5.x because the bundled JSON schema marks .optional().default(X) fields as required. Existing configs that omit these defaulted fields fail validation with "must have required property" errors.
  • Why it matters: Users on 2026.4.22 with valid Feishu configs hit a ~80x restart loop after upgrading to 2026.5.2; only workaround was downgrading. Affects all six channels listed above.
  • What changed: Pass io: 'input' to schema.toJSONSchema() in buildChannelConfigSchema so the generated JSON schema reflects user input requirements (not Zod's output type). Regenerated bundled-channel-config-metadata.generated.ts. Added a regression unit test.
  • What did NOT change (scope boundary): No plugin schema changes, no validator changes, no defaults removed — defaults still apply at runtime via Zod's safeParse. Only the JSON schema's required array shrinks to truly mandatory fields.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Integrations
  • API / contracts

Linked Issue/PR

  • Closes #77116
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: Zod 4's toJSONSchema() defaults to io: 'output'. With .optional().default(X), the output type is always X (never undefined), so the converter marks the field as required in the generated JSON schema. The runtime config validator validates user input via Ajv with useDefaults: false against this generated schema, so any pre-existing config that omits a defaulted field is rejected.
  • Missing detection / guardrail: buildChannelConfigSchema did not specify io, so it used Zod's default. No test covered the input-vs-output JSON schema distinction.
  • Contributing context: Six bundled channels use the .optional().default() pattern (Feishu has 8 such fields, the others have 1-2 each). Issue #77116 surfaced via Feishu because it has the most fields, but the same class of bug exists in Bluebubbles, IRC, Line, Nextcloud Talk, Zalouser.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
  • Target test or file: src/channels/plugins/config-schema.test.ts — new test does not mark optional-with-default fields as required (#77116).
  • Scenario the test should lock in: A schema with one mandatory field, one .optional().default() field, and one .optional() field generates required: ["mandatory"] only.
  • Why this is the smallest reliable guardrail: Asserts the exact required shape that the runtime validator consumes. If a future change reverts to io: 'output' or removes the option, the test fails immediately.
  • Existing test that already covers this (if any): None — passes draft-07 compatibility options to toJSONSchema was updated to also assert io: 'input'.

User-visible / Behavior Changes

Pre-existing Feishu/Bluebubbles/IRC/Line/Nextcloud-Talk/Zalouser configs that omit fields like domain, connectionMode, webhookPath, dmPolicy, groupPolicy, reactionNotifications, typingIndicator, resolveSenderNames are accepted again. Defaults still apply at runtime via the Zod safeParse path. No new permissions or surfaces.

Diagram (if applicable)

Before:
[user config: {accounts: {...}}] -> [JSON schema with required:[domain, ...]] -> [Ajv reject: missing required] -> [gateway crash loop]

After:
[user config: {accounts: {...}}] -> [JSON schema with required:[]] -> [Ajv ok] -> [Zod safeParse applies defaults] -> [gateway ready]

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS (Darwin 25.2.0, arm64)
  • Runtime: Node 24, gateway via node dist/index.js gateway --port 18789
  • Integration/channel: Feishu (with 6+ named accounts)
  • Relevant config (redacted): see #77116 — channels.feishu with enabled, dmPolicy: "allowlist", groupPolicy: "allowlist", allowFrom: ["*"], accounts.{main,finance,...,default} with appId/appSecret.

Steps

  1. Use the redacted config from #77116 at ~/.openclaw/openclaw.json.
  2. Run gateway under stock 2026.5.2: gateway crashes in restart loop with must NOT have additional properties (paraphrased) / must have required property "domain" etc.
  3. Apply this PR's commit, regenerate, restart: gateway starts cleanly.

Expected

  • Gateway boots, Feishu plugin loads, no validation errors.

Actual (after fix)

  • Verified with the user's exact config from #77116 against the regenerated bundled-channel-config-metadata.generated.ts via Ajv: validates ok.

Evidence

  • Failing-before / passing-after via 1 new test in src/channels/plugins/config-schema.test.ts
  • Updated existing passes draft-07 compatibility options test to assert io: 'input'
  • Re-ran user's exact reported config through Ajv → validates ok

Human Verification (required)

  • Verified scenarios: Validated user's reported config from #77116 against the regenerated schema via Ajv — passes. Ran pnpm vitest run src/channels/plugins/config-schema.test.ts src/config/validation.channel-metadata.test.ts extensions/feishu/src/config-schema.test.ts — 36/36 pass. Ran pnpm vitest run src/config/ — 1231/1232 pass (1 unrelated pre-existing bun fallback test failure that fails on stock main too).
  • Edge cases checked (in tests): mandatory-only field stays in required; .optional() only stays out of required; .optional().default() stays out of required.
  • What I did not verify manually: End-to-end gateway restart on the user's exact config — relied on Ajv-level validation since the gateway pipeline uses the same generated schema.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes — only relaxes input validation; no semantics change at runtime.
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Other consumers of the JSON schema (UI pickers, doc generators) may have implicitly relied on required reflecting the output type rather than input requirements.
    • Mitigation: required for .optional().default() fields is widely considered a Zod 4 footgun; the input-shape semantics is the canonical interpretation for runtime input validation. UI consumers that need the output shape can use the Zod schema directly (still exported by each plugin).

Changed files

  • src/channels/plugins/config-schema-input-mode.test.ts (added, +45/-0)
  • src/channels/plugins/config-schema-input-mode.ts (added, +37/-0)
  • src/channels/plugins/config-schema.test.ts (modified, +21/-0)
  • src/channels/plugins/config-schema.ts (modified, +4/-10)
  • src/config/bundled-channel-config-metadata.generated.ts (modified, +152/-192)
RAW_BUFFERClick to expand / collapse

Issue

DeepSeek V4 Pro supports reasoning_effort: "max" natively, but OpenClaw 2026.5.2 only exposes the basic five thinking levels (off/minimal/low/medium/high) for the model. The extended levels xhigh and max are not available.

According to the docs at docs/tools/thinking.md:

DeepSeek V4 models expose /think xhigh|max; both map to DeepSeek reasoning_effort: "max" while lower non-off levels map to high.

Root Cause

From code analysis of the dist:

  1. ws() function (which provides model thinking levels) only returns Ss = [off, minimal, low, medium, high] — the basic five levels.
  2. The full list Fs = [..., xhigh, adaptive, max] exists but is not returned by default for DeepSeek models.
  3. The model profile (deepseek-v4-pro) only has reasoning: true without any thinkingLevels declaration.
  4. The model schema has additionalProperties: false, so thinkingLevels cannot be added to the model config at user level.

Expected

  • /think max and /think xhigh should work for DeepSeek V4 models
  • Both should map to reasoning_effort: "max" in the API request

Actual

  • Only off/minimal/low/medium/high available
  • max and xhigh are not recognized / silently fall back

Environment

  • OpenClaw 2026.5.2 (8b2a6e5)
  • macOS Darwin 25.4.0 (arm64)
  • Model: deepseek/deepseek-v4-pro

extent analysis

TL;DR

Modify the ws() function to return the full list of thinking levels, including xhigh and max, for DeepSeek V4 models.

Guidance

  • Review the code analysis findings to understand why the ws() function only returns the basic five thinking levels.
  • Consider updating the model profile (deepseek-v4-pro) to include a thinkingLevels declaration, although this may be restricted by the model schema.
  • Investigate alternative ways to expose the extended thinking levels, such as modifying the ws() function or adding a custom configuration option.
  • Verify that the /think max and /think xhigh commands work as expected after making any changes.

Example

No code snippet is provided as the issue does not contain sufficient information to create a specific example.

Notes

The model schema's additionalProperties: false restriction may limit the ability to add custom configuration options, such as thinkingLevels, to the model config.

Recommendation

Apply a workaround, such as modifying the ws() function, to expose the extended thinking levels for DeepSeek V4 models, as upgrading to a fixed version is not mentioned in the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING