Skip to content

feat(model): support none and xhigh effort - #1474

Merged
zhangmo8 merged 4 commits into
devfrom
feat/publicdb-reasoning-effort
Apr 16, 2026
Merged

feat(model): support none and xhigh effort#1474
zhangmo8 merged 4 commits into
devfrom
feat/publicdb-reasoning-effort

Conversation

@yyhhyyyyyy

@yyhhyyyyyy yyhhyyyyyy commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator

support none and xhigh effort
image

Summary by CodeRabbit

  • New Features

    • Added two new reasoning effort levels ("None" and "XHigh") and a per-model reasoning toggle; UI now shows appropriate effort options, indicator/readonly modes, and disabled toggle behaviors based on model capabilities.
  • Chores

    • Updated many agent entries to newer versions and improved how reasoning/verbosity settings are derived and propagated to providers and the UI.
    • Updated localization strings for the new reasoning options across supported languages.
  • Tests

    • Added and extended tests for reasoning effort defaults, portraits, provider mapping, and UI behavior.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Centralized ReasoningEffort/Verbosity enums, guards, and helpers were added/expanded (including 'none' and 'xhigh'); agent registry entries were version-bumped; reasoning-related logic was propagated across presenters, provider option mapping, DB mappers, renderer components, types, i18n, and tests.

Changes

Cohort / File(s) Summary
Agent Registry
resources/acp-registry/registry.json
Bumped versions for ~17 agents; crow-cli distribution moved from uvx to per-platform binary with cmd/args and website.
Provider DB Fetch
scripts/fetch-provider-db.mjs
Expanded allowed REASONING_EFFORT_VALUES to include 'none' and 'xhigh' and preserved upstream effort values when sanitizing.
Shared Types & Helpers
src/shared/types/model-db.ts
Added REASONING_EFFORT_VALUES, DEFAULT_REASONING_EFFORT_OPTIONS, type guards (isReasoningEffort, isVerbosity), reasoning-capability helpers (supportsReasoningCapability, getReasoningControlMode, hasIndependentReasoningToggle, getReasoningEffectiveEnabled, normalizeReasoningEffortValue).
Presenters — Config & Capabilities
src/main/presenter/configPresenter/...
Refactored capability resolution and model reasoning defaults; new helper to resolve NewAPI endpoint types; recompute model.reasoning using capability checks.
Presenters — Runtime & Provider Mapping
src/main/presenter/agentRuntimePresenter/index.ts, src/main/presenter/llmProviderPresenter/aiSdk/providerOptionsMapper.ts
Replaced local guards with shared ones; compute reasoning portrait and effective reasoningEnabled; gate provider thinking/reasoning options on the effective value.
DB Mappers / Types
src/main/presenter/sqlitePresenter/tables/..., src/main/presenter/sessionPresenter/types.ts
Switched DB row typings and runtime mappers to validate reasoningEffort/verbosity with shared guards; session types now use shared enums.
Renderer — Components & Composables
src/renderer/src/components/..., src/renderer/src/composables/useChatConfigFields.ts
Props, emits, and internal state updated to use shared ReasoningEffort/Verbosity; option derivation uses DEFAULT_REASONING_EFFORT_OPTIONS and shared guards; ModelConfigDialog updated to compute toggle modes and disable behavior via capability helpers.
Store Logic
src/renderer/src/stores/modelStore.ts
Adjusted how reasoning is derived for custom vs non-custom and how fallback normalized reason is applied.
Type Definitions / Presenters
src/shared/types/*.d.ts
Replaced many inline string-union types with imported ReasoningEffort and Verbosity in presenter/type definition files and interfaces.
Localization
src/renderer/src/i18n/*/settings.json
Added none and xhigh reasoning-effort option labels and new reasoningToggle translations across locales; zh-CN updated several parameter labels.
Tests
test/**/*.test.ts
Updated tests to use shared types and added test cases covering preservation/handling of 'none' and 'xhigh', portrait-driven defaults, provider-option gating, and UI toggle modes.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(220,230,241,0.5)
  participant UI as Renderer (ModelConfig / Chat)
  end
  rect rgba(200,230,200,0.5)
  participant Presenter as ConfigPresenter / AgentRuntime
  end
  rect rgba(241,220,220,0.5)
  participant Cap as ModelCapabilities
  end
  rect rgba(255,245,200,0.5)
  participant DB as Provider DB / Registry
  end
  rect rgba(230,230,255,0.5)
  participant Provider as LLM Provider Mapper
  end

  UI->>Presenter: request model portrait / update generation settings
  Presenter->>Cap: getReasoningPortrait(modelId)
  Cap->>DB: read merged portrait (registry, legacy, extra)
  DB-->>Cap: portrait (may include effort, effortOptions)
  Cap-->>Presenter: reasoningPortrait
  Presenter->>Presenter: normalizeReasoningEffort & compute reasoningEnabled
  Presenter->>Provider: buildProviderOptions(reasoningEnabled, reasoningEffort, thinkingBudget)
  Provider-->Provider: gate vendor flags (sendReasoning/thinking/effort)
  Provider-->>UI: provider options applied / session started
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • zerob13

Poem

"I'm a rabbit in the code, ears twitch with delight,
Added 'none' and 'xhigh' to reasoning's light.
Guards snug and types aligned, portraits set just so,
Toggles, providers, locales — now ready to go.
Hop—small changes, big thinking, off we sprint! 🐇"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(model): support none and xhigh effort' directly and concisely summarizes the main change—adding support for two new reasoning effort levels ('none' and 'xhigh')—which is clearly the primary objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/publicdb-reasoning-effort

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/renderer/components/ChatStatusBar.test.ts (1)

878-901: Use a selectable model id in this test setup

Line 881-883 and Line 895 use gpt-5.2, but the local mocked model list doesn’t include it. This can make the test pass for the wrong reason and become brittle if selection validation tightens.

💡 Proposed test tightening
-      preferredModel: { providerId: 'openai', modelId: 'gpt-5.2' },
-      defaultModel: { providerId: 'openai', modelId: 'gpt-5.2' },
+      preferredModel: { providerId: 'openai', modelId: 'gpt-4' },
+      defaultModel: { providerId: 'openai', modelId: 'gpt-4' },
@@
-    await (wrapper.vm as any).openModelSettings('openai', 'gpt-5.2')
+    await (wrapper.vm as any).openModelSettings('openai', 'gpt-4')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/renderer/components/ChatStatusBar.test.ts` around lines 878 - 901, The
test uses a hard-coded model id 'gpt-5.2' that isn't present in the mocked model
list, making selection brittle; update the test setup to use a selectable model
id from the mock data (or add 'gpt-5.2' to the mock models) so
openModelSettings('openai','gpt-5.2') actually selects a real entry—adjust the
setup call or the mock model list referenced by setup(...) so the
localSettings.reasoningEffort assertion and wrapper.text() checks exercise the
real model selection path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/presenter/configPresenter/modelCapabilities.ts`:
- Around line 83-91: The helper uses a local DEFAULT_REASONING_EFFORT_OPTIONS
list which is out of sync with the shared reasoning-effort domain; update
usesExtendedEffortDefaultWithoutOptions to reference the canonical/shared
default-effort options (the exported constant or accessor from the
reasoning-effort domain) instead of DEFAULT_REASONING_EFFORT_OPTIONS, and adjust
the Boolean check so newly supported defaults (e.g., 'none', 'xhigh') are
treated correctly; apply the same replacement to the other occurrence that
touches resolvedPortrait.effortOptions (the logic that may delete
resolvedPortrait.effortOptions) so both places use the shared domain
constant/function and remain consistent with main-process portrait
normalization.

---

Nitpick comments:
In `@test/renderer/components/ChatStatusBar.test.ts`:
- Around line 878-901: The test uses a hard-coded model id 'gpt-5.2' that isn't
present in the mocked model list, making selection brittle; update the test
setup to use a selectable model id from the mock data (or add 'gpt-5.2' to the
mock models) so openModelSettings('openai','gpt-5.2') actually selects a real
entry—adjust the setup call or the mock model list referenced by setup(...) so
the localSettings.reasoningEffort assertion and wrapper.text() checks exercise
the real model selection path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5fd2a9a2-44b7-4d34-a37f-cb5ebb42ca61

📥 Commits

Reviewing files that changed from the base of the PR and between fd4eb51 and 4fb085c.

📒 Files selected for processing (39)
  • resources/acp-registry/registry.json
  • resources/model-db/providers.json
  • scripts/fetch-provider-db.mjs
  • src/main/presenter/agentRuntimePresenter/index.ts
  • src/main/presenter/configPresenter/index.ts
  • src/main/presenter/configPresenter/modelCapabilities.ts
  • src/main/presenter/configPresenter/modelConfig.ts
  • src/main/presenter/sessionPresenter/types.ts
  • src/main/presenter/sqlitePresenter/tables/conversations.ts
  • src/main/presenter/sqlitePresenter/tables/deepchatSessions.ts
  • src/renderer/src/components/ChatConfig.vue
  • src/renderer/src/components/chat/ChatStatusBar.vue
  • src/renderer/src/components/settings/ModelConfigDialog.vue
  • src/renderer/src/composables/useChatConfigFields.ts
  • src/renderer/src/i18n/da-DK/settings.json
  • src/renderer/src/i18n/en-US/settings.json
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/fr-FR/settings.json
  • src/renderer/src/i18n/he-IL/settings.json
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/ru-RU/settings.json
  • src/renderer/src/i18n/zh-CN/settings.json
  • src/renderer/src/i18n/zh-HK/settings.json
  • src/renderer/src/i18n/zh-TW/settings.json
  • src/shared/types/agent-interface.d.ts
  • src/shared/types/model-db.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/shared/types/presenters/session.presenter.d.ts
  • src/shared/types/presenters/thread.presenter.d.ts
  • test/main/presenter/agentSessionPresenter/integration.test.ts
  • test/main/presenter/configPresenter/modelCapabilities.test.ts
  • test/main/presenter/llmProviderPresenter/aiSdkProviderOptionsMapper.test.ts
  • test/main/presenter/providerDbModelConfig.test.ts
  • test/main/shared/modelDb.test.ts
  • test/renderer/components/ChatStatusBar.test.ts
  • test/renderer/components/ModelConfigDialog.test.ts
  • test/renderer/components/NewThreadPage.test.ts

Comment on lines +83 to +91
const usesExtendedEffortDefaultWithoutOptions = (
portrait: ReasoningPortrait | undefined
): boolean => {
if (!portrait || portrait.effortOptions !== undefined || portrait.mode === 'budget') {
return false
}

return Boolean(portrait.effort && !DEFAULT_REASONING_EFFORT_OPTIONS.includes(portrait.effort))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use the shared reasoning-effort domain here.

This helper still keys off the local four-value DEFAULT_REASONING_EFFORT_OPTIONS, so newly supported defaults like none/xhigh are classified as “extended” and can hit the delete resolvedPortrait.effortOptions path below. That leaves the main-process portrait normalization out of sync with the PR’s expanded effort support.

♻️ Suggested fix
-import {
-  ProviderAggregate,
-  ProviderModel,
-  ReasoningPortrait,
-  type ReasoningEffort,
-  type Verbosity
-} from '@shared/types/model-db'
+import {
+  DEFAULT_REASONING_EFFORT_OPTIONS,
+  ProviderAggregate,
+  ProviderModel,
+  ReasoningPortrait,
+  type ReasoningEffort,
+  type Verbosity
+} from '@shared/types/model-db'
@@
-const DEFAULT_REASONING_EFFORT_OPTIONS: ReasoningEffort[] = ['minimal', 'low', 'medium', 'high']
 const BINARY_REASONING_EFFORT_OPTIONS: ReasoningEffort[] = ['low', 'high']

Also applies to: 478-480

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/configPresenter/modelCapabilities.ts` around lines 83 -
91, The helper uses a local DEFAULT_REASONING_EFFORT_OPTIONS list which is out
of sync with the shared reasoning-effort domain; update
usesExtendedEffortDefaultWithoutOptions to reference the canonical/shared
default-effort options (the exported constant or accessor from the
reasoning-effort domain) instead of DEFAULT_REASONING_EFFORT_OPTIONS, and adjust
the Boolean check so newly supported defaults (e.g., 'none', 'xhigh') are
treated correctly; apply the same replacement to the other occurrence that
touches resolvedPortrait.effortOptions (the logic that may delete
resolvedPortrait.effortOptions) so both places use the shared domain
constant/function and remain consistent with main-process portrait
normalization.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/presenter/configPresenter/index.ts (1)

1046-1067: ⚠️ Potential issue | 🟠 Major

Resolve DB-backed reasoning support through the capability helper.

Line 1066 bypasses resolveCapabilityProviderId(...)/supportsReasoningCapability(...) and queries modelCapabilities with the raw providerId. That will misreport reasoning support for aliased providers and new-api models, so the renderer can hide the new reasoning controls for supported models.

Suggested fix
-      reasoning: modelCapabilities.supportsReasoning(providerId, m.id),
+      reasoning: this.supportsReasoningCapability(providerId, m.id),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/configPresenter/index.ts` around lines 1046 - 1067, In
getDbProviderModels, the reasoning support check uses
modelCapabilities.supportsReasoning(providerId, m.id) with the raw providerId
which misreports for aliased/new-api providers; replace that call to use the
capability-resolved provider id by calling
resolveCapabilityProviderId(providerId) (falling back to providerId) and then
invoke
modelCapabilities.supportsReasoningCapability(resolvedCapabilityProviderId,
m.id) (or the corresponding helper) so reasoning is determined via the
capability helper for aliased/new-api providers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/presenter/llmProviderPresenter/aiSdk/providerOptionsMapper.ts`:
- Around line 123-130: The code calls modelCapabilities.getReasoningPortrait
directly with params.providerId and params.modelId which can bypass provider
aliasing; instead first resolve the effective provider id using
resolveCapabilityProviderId(...) (the same mapper used by the runtime) and then
call modelCapabilities.getReasoningPortrait with that resolved provider id and
params.modelId before passing the portrait into getReasoningEffectiveEnabled;
update the block referencing modelCapabilities.getReasoningPortrait,
resolveCapabilityProviderId, getReasoningEffectiveEnabled, and
params.providerId/params.modelId so reasoningEnabled is derived from the same
resolved provider the runtime uses.

---

Outside diff comments:
In `@src/main/presenter/configPresenter/index.ts`:
- Around line 1046-1067: In getDbProviderModels, the reasoning support check
uses modelCapabilities.supportsReasoning(providerId, m.id) with the raw
providerId which misreports for aliased/new-api providers; replace that call to
use the capability-resolved provider id by calling
resolveCapabilityProviderId(providerId) (falling back to providerId) and then
invoke
modelCapabilities.supportsReasoningCapability(resolvedCapabilityProviderId,
m.id) (or the corresponding helper) so reasoning is determined via the
capability helper for aliased/new-api providers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1f66a6c-8e84-42aa-9e1b-054fe2b11993

📥 Commits

Reviewing files that changed from the base of the PR and between 4fb085c and 0ccd758.

📒 Files selected for processing (21)
  • src/main/presenter/agentRuntimePresenter/index.ts
  • src/main/presenter/configPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/aiSdk/providerOptionsMapper.ts
  • src/renderer/src/components/settings/ModelConfigDialog.vue
  • src/renderer/src/i18n/da-DK/settings.json
  • src/renderer/src/i18n/en-US/settings.json
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/fr-FR/settings.json
  • src/renderer/src/i18n/he-IL/settings.json
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/ru-RU/settings.json
  • src/renderer/src/i18n/zh-CN/settings.json
  • src/renderer/src/i18n/zh-HK/settings.json
  • src/renderer/src/i18n/zh-TW/settings.json
  • src/renderer/src/stores/modelStore.ts
  • src/shared/types/model-db.ts
  • test/main/presenter/llmProviderPresenter/aiSdkProviderOptionsMapper.test.ts
  • test/main/shared/modelDb.test.ts
  • test/renderer/components/ModelConfigDialog.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/renderer/src/i18n/zh-TW/settings.json
  • src/renderer/src/i18n/ru-RU/settings.json
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/en-US/settings.json
  • test/main/shared/modelDb.test.ts
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/fr-FR/settings.json
  • test/main/presenter/llmProviderPresenter/aiSdkProviderOptionsMapper.test.ts
  • test/renderer/components/ModelConfigDialog.test.ts
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/da-DK/settings.json
  • src/renderer/src/i18n/ja-JP/settings.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/presenter/llmProviderPresenter/aiSdk/providerOptionsMapper.ts (1)

233-245: ⚠️ Potential issue | 🟠 Major

Guard effort behind reasoningEnabled and explicitly map extended enum values instead of collapsing them to 'medium'.

The current condition sends config.effort whenever reasoningEffort is set, but this doesn't account for the reasoning disabled state. More critically, it collapses all non-'low'/'high' values to 'medium', which is incorrect:

  • reasoningEffort: 'none' emits config.effort = 'medium' (should omit effort entirely)
  • reasoningEffort: 'xhigh' emits config.effort = 'medium' (should map to 'high')

Add the reasoningEnabled check to match the sendReasoning guard (line 31), and explicitly map all enum values ('none', 'minimal', 'low', 'medium', 'high', 'xhigh') to their Anthropic equivalents instead of defaulting unknown values to 'medium'.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/llmProviderPresenter/aiSdk/providerOptionsMapper.ts`
around lines 233 - 245, Guard setting config.effort by the existing
reasoningEnabled flag and explicitly map every allowed
params.modelConfig.reasoningEffort enum to the correct Anthropic value instead
of collapsing unknowns to "medium": when officialAnthropicProvider &&
reasoningEnabled && params.modelConfig.reasoningEffort is set, translate values
as follows — 'none' = do not set config.effort (omit it), 'minimal' -> 'low',
'low' -> 'low', 'medium' -> 'medium', 'high' -> 'high', 'xhigh' -> 'high' — and
assign the mapped value to config.effort; use the symbols
officialAnthropicProvider, reasoningEnabled, params.modelConfig.reasoningEffort
and config.effort in providerOptionsMapper.ts to locate and implement the
change.
🧹 Nitpick comments (2)
test/main/presenter/agentRuntimePresenter/agentRuntimePresenter.test.ts (1)

1991-2012: Add a none regression beside this xhigh case.

This only proves stale values collapse to a fixed default. The other half of the feature is reasoningEffort: 'none' disabling reasoning, so a sibling test would better protect the new request-mapping path from regressing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/main/presenter/agentRuntimePresenter/agentRuntimePresenter.test.ts`
around lines 1991 - 2012, Add a sibling test to the existing "normalizes stale
reasoning effort values to a fixed portrait default" spec that verifies stale
reasoning values map to 'none' to disable reasoning: mock
configPresenter.getReasoningPortrait to return mode: 'effort' with effort:
'none', call agent.initSession('s1', ...) and then
agent.updateGenerationSettings('s1', { reasoningEffort: 'low' }) and assert the
returned updated.reasoningEffort is 'none' and that
sqlitePresenter.deepchatSessionsTable.updateGenerationSettings was called with
an objectContaining { reasoningEffort: 'none' }; mirror the structure and
assertions used in the existing test that checks for 'xhigh' to ensure parity.
test/main/presenter/configPresenter/providerModelCapabilityMapping.test.ts (1)

15-22: Redundant vi.restoreAllMocks() call in afterEach.

vi.restoreAllMocks() is already called in beforeEach (line 17), which runs before each test. The afterEach call at line 21 is redundant since beforeEach will reset mocks before the next test anyway.

🧹 Suggested cleanup
-  afterEach(() => {
-    vi.restoreAllMocks()
-  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/main/presenter/configPresenter/providerModelCapabilityMapping.test.ts`
around lines 15 - 22, The afterEach block contains a redundant
vi.restoreAllMocks() because beforeEach already calls vi.resetModules() and
vi.restoreAllMocks(); remove the vi.restoreAllMocks() call from the afterEach so
mocks are only restored in beforeEach and avoid duplicate restores—update the
afterEach (or remove it entirely if it no longer contains any statements) in
providerModelCapabilityMapping.test.ts to eliminate the redundant
vi.restoreAllMocks() invocation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/shared/types/model-db.ts`:
- Around line 177-205: The function normalizeReasoningEffortValue currently
falls through to returning the original value even when portrait.mode is
'budget', 'level', or 'mixed', allowing stale reasoningEffort to be preserved;
update normalizeReasoningEffortValue to return undefined for portraits that do
not support effort controls (i.e., when
canResolveReasoningEffortFromPortrait(portrait) is false or portrait.mode is
'budget'|'level'|'mixed'), keeping the existing logic that validates against
portrait.effort and portrait.effortOptions (use isReasoningEffort and
options.includes checks as-is) but replace the final return value with undefined
for non-effort portraits so callers (e.g.,
ModelConfigHelper.buildConfigFromProviderModel) cannot emit an unsupported
reasoningEffort.

---

Outside diff comments:
In `@src/main/presenter/llmProviderPresenter/aiSdk/providerOptionsMapper.ts`:
- Around line 233-245: Guard setting config.effort by the existing
reasoningEnabled flag and explicitly map every allowed
params.modelConfig.reasoningEffort enum to the correct Anthropic value instead
of collapsing unknowns to "medium": when officialAnthropicProvider &&
reasoningEnabled && params.modelConfig.reasoningEffort is set, translate values
as follows — 'none' = do not set config.effort (omit it), 'minimal' -> 'low',
'low' -> 'low', 'medium' -> 'medium', 'high' -> 'high', 'xhigh' -> 'high' — and
assign the mapped value to config.effort; use the symbols
officialAnthropicProvider, reasoningEnabled, params.modelConfig.reasoningEffort
and config.effort in providerOptionsMapper.ts to locate and implement the
change.

---

Nitpick comments:
In `@test/main/presenter/agentRuntimePresenter/agentRuntimePresenter.test.ts`:
- Around line 1991-2012: Add a sibling test to the existing "normalizes stale
reasoning effort values to a fixed portrait default" spec that verifies stale
reasoning values map to 'none' to disable reasoning: mock
configPresenter.getReasoningPortrait to return mode: 'effort' with effort:
'none', call agent.initSession('s1', ...) and then
agent.updateGenerationSettings('s1', { reasoningEffort: 'low' }) and assert the
returned updated.reasoningEffort is 'none' and that
sqlitePresenter.deepchatSessionsTable.updateGenerationSettings was called with
an objectContaining { reasoningEffort: 'none' }; mirror the structure and
assertions used in the existing test that checks for 'xhigh' to ensure parity.

In `@test/main/presenter/configPresenter/providerModelCapabilityMapping.test.ts`:
- Around line 15-22: The afterEach block contains a redundant
vi.restoreAllMocks() because beforeEach already calls vi.resetModules() and
vi.restoreAllMocks(); remove the vi.restoreAllMocks() call from the afterEach so
mocks are only restored in beforeEach and avoid duplicate restores—update the
afterEach (or remove it entirely if it no longer contains any statements) in
providerModelCapabilityMapping.test.ts to eliminate the redundant
vi.restoreAllMocks() invocation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b27e1ed-cfab-4ef5-985c-34626f403021

📥 Commits

Reviewing files that changed from the base of the PR and between 0ccd758 and 56ff639.

📒 Files selected for processing (12)
  • src/main/presenter/agentRuntimePresenter/index.ts
  • src/main/presenter/configPresenter/index.ts
  • src/main/presenter/configPresenter/modelConfig.ts
  • src/main/presenter/llmProviderPresenter/aiSdk/providerOptionsMapper.ts
  • src/renderer/src/components/settings/ModelConfigDialog.vue
  • src/renderer/src/stores/modelStore.ts
  • src/shared/types/model-db.ts
  • test/main/presenter/agentRuntimePresenter/agentRuntimePresenter.test.ts
  • test/main/presenter/configPresenter/providerModelCapabilityMapping.test.ts
  • test/main/presenter/llmProviderPresenter/aiSdkProviderOptionsMapper.test.ts
  • test/main/shared/modelDb.test.ts
  • test/renderer/stores/modelStore.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/main/presenter/llmProviderPresenter/aiSdkProviderOptionsMapper.test.ts

Comment on lines +177 to +205
const canResolveReasoningEffortFromPortrait = (
portrait: ReasoningPortrait | null | undefined
): boolean =>
portrait?.mode !== 'budget' && portrait?.mode !== 'level' && portrait?.mode !== 'mixed'

export const normalizeReasoningEffortValue = (
portrait: ReasoningPortrait | null | undefined,
value: unknown
): ReasoningEffort | undefined => {
if (!isReasoningEffort(value)) {
return undefined
}

const options = portrait?.effortOptions?.filter(isReasoningEffort)
if (options && options.length > 0) {
if (options.includes(value)) {
return value
}

return isReasoningEffort(portrait?.effort) && options.includes(portrait.effort)
? portrait.effort
: undefined
}

if (canResolveReasoningEffortFromPortrait(portrait) && isReasoningEffort(portrait?.effort)) {
return value === portrait.effort ? value : portrait.effort
}

return value

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Don't preserve reasoningEffort for non-effort portraits.

This helper falls through to return value when portrait.mode is budget, level,
or mixed, so callers like ModelConfigHelper.buildConfigFromProviderModel() can still
emit a stale reasoningEffort for models that do not support effort controls.

💡 Proposed fix
 export const normalizeReasoningEffortValue = (
   portrait: ReasoningPortrait | null | undefined,
   value: unknown
 ): ReasoningEffort | undefined => {
   if (!isReasoningEffort(value)) {
     return undefined
   }
+
+  if (portrait && !canResolveReasoningEffortFromPortrait(portrait)) {
+    return undefined
+  }
 
   const options = portrait?.effortOptions?.filter(isReasoningEffort)
   if (options && options.length > 0) {
     if (options.includes(value)) {
       return value
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const canResolveReasoningEffortFromPortrait = (
portrait: ReasoningPortrait | null | undefined
): boolean =>
portrait?.mode !== 'budget' && portrait?.mode !== 'level' && portrait?.mode !== 'mixed'
export const normalizeReasoningEffortValue = (
portrait: ReasoningPortrait | null | undefined,
value: unknown
): ReasoningEffort | undefined => {
if (!isReasoningEffort(value)) {
return undefined
}
const options = portrait?.effortOptions?.filter(isReasoningEffort)
if (options && options.length > 0) {
if (options.includes(value)) {
return value
}
return isReasoningEffort(portrait?.effort) && options.includes(portrait.effort)
? portrait.effort
: undefined
}
if (canResolveReasoningEffortFromPortrait(portrait) && isReasoningEffort(portrait?.effort)) {
return value === portrait.effort ? value : portrait.effort
}
return value
const canResolveReasoningEffortFromPortrait = (
portrait: ReasoningPortrait | null | undefined
): boolean =>
portrait?.mode !== 'budget' && portrait?.mode !== 'level' && portrait?.mode !== 'mixed'
export const normalizeReasoningEffortValue = (
portrait: ReasoningPortrait | null | undefined,
value: unknown
): ReasoningEffort | undefined => {
if (!isReasoningEffort(value)) {
return undefined
}
if (portrait && !canResolveReasoningEffortFromPortrait(portrait)) {
return undefined
}
const options = portrait?.effortOptions?.filter(isReasoningEffort)
if (options && options.length > 0) {
if (options.includes(value)) {
return value
}
return isReasoningEffort(portrait?.effort) && options.includes(portrait.effort)
? portrait.effort
: undefined
}
if (canResolveReasoningEffortFromPortrait(portrait) && isReasoningEffort(portrait?.effort)) {
return value === portrait.effort ? value : portrait.effort
}
return value
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/shared/types/model-db.ts` around lines 177 - 205, The function
normalizeReasoningEffortValue currently falls through to returning the original
value even when portrait.mode is 'budget', 'level', or 'mixed', allowing stale
reasoningEffort to be preserved; update normalizeReasoningEffortValue to return
undefined for portraits that do not support effort controls (i.e., when
canResolveReasoningEffortFromPortrait(portrait) is false or portrait.mode is
'budget'|'level'|'mixed'), keeping the existing logic that validates against
portrait.effort and portrait.effortOptions (use isReasoningEffort and
options.includes checks as-is) but replace the final return value with undefined
for non-effort portraits so callers (e.g.,
ModelConfigHelper.buildConfigFromProviderModel) cannot emit an unsupported
reasoningEffort.

@zhangmo8
zhangmo8 merged commit 639712e into dev Apr 16, 2026
3 checks passed
@zhangmo8
zhangmo8 deleted the feat/publicdb-reasoning-effort branch April 21, 2026 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants