Skip to content

fix(model-effort): preserve inherited default selections in chat and spawn dialog#257

Open
DerrickBarra wants to merge 2 commits intodaggerhashimoto:masterfrom
GambitGamesLLC:bug/default-model-effort
Open

fix(model-effort): preserve inherited default selections in chat and spawn dialog#257
DerrickBarra wants to merge 2 commits intodaggerhashimoto:masterfrom
GambitGamesLLC:bug/default-model-effort

Conversation

@DerrickBarra
Copy link
Copy Markdown
Contributor

@DerrickBarra DerrickBarra commented Apr 10, 2026

What

Fix the model / effort UI so sessions that inherit OpenClaw defaults keep showing the inherited selection instead of looking like they were explicitly overridden.

In Plain English

This PR makes Nerve tell the truth about default model settings.

When a session or spawn flow is using the inherited OpenClaw defaults, the UI could make it look like some other model or effort level was explicitly selected. That is confusing because the screen stops matching the actual config.

This fix keeps inherited defaults visible as inherited defaults, so users can trust what the chat controls and spawn dialog are showing.

This covers two user-visible surfaces:

  • the chat model / effort controls
  • the spawn dialog model picker

On the validated dogfood setup, inherited defaults now display as primary model and medium effort, matching our openclaw.json configuration file for the primary model and default thinking level.

Why

Closes #255

Before this change, Nerve could resolve inherited defaults down to a concrete provider/model string or otherwise lose the inherited-default state in the UI. That made a default-inheriting session look like it had an explicit override, which is misleading and makes model / effort selection harder to reason about.

How

  • keep inherited model selection represented as primary in useModelEffort
  • preserve inherited effort/default-thinking handling instead of flattening it into the wrong visible state
  • ensure explicit overrides still remain explicit
  • update the spawn dialog so primary is shown as the default inherited model option
  • omit model from spawn payloads when the user keeps the inherited primary selection
  • add / update targeted tests for both the hook and the spawn dialog

Branch / validation notes for maintainers:

  • branch: bug/default-model-effort
  • head fork/branch is clean and directly based on upstream/master
  • branch state at open: 0 behind / 2 ahead versus upstream/master
  • validated already with:
    • targeted tests covering the two touched areas
    • npm run lint (passes with pre-existing warnings only)
    • npm run build (passes)
  • any non-blocking warnings seen during lint were pre-existing / unrelated to this fix

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📝 Documentation update
  • 🔧 Refactor / chore (no functional change)

Checklist

  • npm run lint passes
  • npm run build && npm run build:server succeeds
  • npm test -- --run passes
  • New features include tests
  • UI changes include a screenshot or screen recording

Summary by CodeRabbit

New Features

  • Added "primary" model selection option that uses inherited/default settings instead of explicitly selecting a specific model.
  • Introduced support for inherited thinking effort levels that automatically apply defaults when not explicitly overridden.
  • Enhanced model role classification with improved resolution logic to better identify and match models across different representations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

This PR fixes inherited default model and effort display in chat and spawn dialogs by introducing sentinel values (primary for models, thinkingDefault for effort) that preserve inherited-default state instead of displaying resolved concrete values. The implementation adds a role field to model catalog entries and reworks model/effort resolution logic across multiple components.

Changes

Cohort / File(s) Summary
Inherited Default Values
src/features/chat/components/useModelEffort.ts, src/features/sessions/SpawnAgentDialog.tsx
Introduced sentinel constants INHERITED_MODEL_VALUE = 'primary' and INHERITED_EFFORT_VALUE = 'thinkingDefault' to represent inherited defaults. Updated dropdown options and model/effort selection logic to treat these as special cases during session updates and spawn operations.
Model Catalog Extension
src/features/chat/components/useModelEffort.ts
Extended GatewayModelInfo type with optional role field ('primary' | 'fallback' | 'allowed') to support role-based model categorization from gateway API responses.
Model Resolution & Synchronization
src/features/chat/components/useModelEffort.ts
Added modelRefsMatch(...) function to treat different representations of the same model as equivalent. Updated currentSessionModel and model dropdown sync to map primary/inherited selections to 'primary' string value.
Effort Selection Reworking
src/features/chat/components/useModelEffort.ts
Refactored selectedEffort initialization and localStorage persistence to support 'thinkingDefault' as inherited state. Removed fallback logic that previously defaulted to concrete effort levels. Updated currentSessionThinking to prefer explicit thinkingLevel and compute derived values when gateway thinking differs from inherited default.
Handler Updates
src/features/chat/components/useModelEffort.ts
Reworked handleModelChange to treat 'primary' selection specially: WS patch uses primaryModelId instead of null; HTTP fallback requires primary model lookup. Reworked handleEffortChange to map 'thinkingDefault' to undefined in session updates and patch with null for inherited behavior.
Session-Info Fetching
src/features/chat/components/useModelEffort.ts
Simplified session-info fetch effect by removing preexisting fetch-and-set of effort when no local session thinking override existed. Adjusted effect dependencies accordingly.
SpawnAgentDialog Model Selection
src/features/sessions/SpawnAgentDialog.tsx
Updated modelOptions to prepend inherited 'primary' option when models are fetched; defaultModelId defaults to 'primary' when models are available. During spawn, 'primary' selection is converted to undefined before passing to onSpawn.
Test Coverage
src/features/chat/components/useModelEffort.test.ts, src/features/sessions/SpawnAgentDialog.test.tsx
Added and updated test fixtures with role field on models. Added test cases verifying inherited default selection, effort preservation, and spawn payload correctness when inheriting defaults. Updated assertions to expect 'primary' in model options and selectors.

Sequence Diagram(s)

sequenceDiagram
    participant User as User (Chat UI)
    participant Hook as useModelEffort Hook
    participant Session as Session Context
    participant Gateway as Gateway API
    participant WS as WebSocket/HTTP

    User->>Hook: Component mounts with inherited defaults
    Hook->>Gateway: Fetch /api/gateway/models (get role: 'primary')
    Gateway-->>Hook: Return models with roles
    
    Note over Hook: Detect inherited state:<br/>- No explicit sessionModel<br/>- No explicit thinkingLevel
    
    Hook->>Hook: Resolve inherited defaults<br/>selectedModel = 'primary'<br/>selectedEffort = 'thinkingDefault'
    Hook-->>User: Display 'primary' in model dropdown<br/>Display 'thinkingDefault' in effort dropdown
    
    User->>Hook: Keep inherited defaults (no change)
    Hook->>Session: updateSession(thinkingLevel: undefined)
    Session->>WS: PATCH with primaryModelId<br/>and thinkingLevel: null
    WS-->>Session: Confirm update
    
    Note over User: UI now correctly shows<br/>inherited state, not concrete<br/>resolved values
Loading
sequenceDiagram
    participant User as User (Spawn Dialog)
    participant Dialog as SpawnAgentDialog
    participant Gateway as Gateway API
    participant Callback as onSpawn Callback

    User->>Dialog: Open spawn dialog
    Dialog->>Gateway: Fetch /api/gateway/models (with roles)
    Gateway-->>Dialog: Return models including primary role
    
    Dialog->>Dialog: Build modelOptions:<br/>1. 'primary' option (inherited)<br/>2. Other fetched models
    Dialog->>Dialog: Set defaultModelId = 'primary'
    Dialog-->>User: Display 'primary' as default<br/>model selector option
    
    User->>Dialog: Select 'primary' (inherited default)
    User->>Dialog: Click spawn
    
    Dialog->>Dialog: Convert 'primary' → undefined<br/>spawnModel = undefined
    Dialog->>Callback: Call onSpawn({<br/>  kind, agentName, task,<br/>  model: undefined  ← inherited<br/>})
    
    Note over Callback: Downstream handler knows<br/>undefined = use inherited default
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 Hop along to inherited bliss,
Where "primary" no longer is missed!
No more concrete deceit in the view,
Defaults now shine as they're meant to do. 🌟
A sentinel value saves the day,
And confusion hops far, far away!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: preserving inherited default selections (primary model and default effort) in the chat and spawn dialog UI.
Linked Issues check ✅ Passed All coding requirements from #255 are met: inherited model selection displays as 'primary', inherited effort handling is preserved, explicit overrides remain explicit, spawn dialog shows 'primary' as default, and model is omitted from spawn payloads when 'primary' is retained.
Out of Scope Changes check ✅ Passed All changes are directly scoped to addressing the linked issue: test updates for useModelEffort hook and SpawnAgentDialog, implementation changes to handle inherited default representation, and no unrelated modifications.
Description check ✅ Passed PR description is comprehensive and follows the template with all required sections present: What, Why, How, Type of Change, and Checklist.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@DerrickBarra
Copy link
Copy Markdown
Contributor Author

Supersedes #256 solely to correct source-fork provenance. This PR uses the same validated bug/default-model-effort branch from GambitGamesLLC/openclaw-nerve, which is the fork we want maintainers and tooling to review against.

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.

[Bug] Inherited default model/effort is displayed incorrectly in chat and spawn dialog

1 participant