Skip to content

feat(web): small_model picker in settings — Model roles section - #139

Merged
cnjack merged 2 commits into
mainfrom
feat/small-model-settings-ui
Jul 14, 2026
Merged

feat(web): small_model picker in settings — Model roles section#139
cnjack merged 2 commits into
mainfrom
feat/small-model-settings-ui

Conversation

@cnjack

@cnjack cnjack commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

Related Issues / Tickets

Type of Change

  • New feature
  • Documentation update
  • Test update

Changes Made

  1. BackendPOST /api/small-model sets/clears small_model (both fields empty = clear; unknown provider and half-set requests are 400). The handler mutates the live shared config pointer in place (same discipline as the browser-config handler) so call-time readers — the ModelFactory "small" alias, the automation model override, the title refiner — see the change immediately; the providers-style s.cfg reassign would leave buildWebTask's closure reading the stale value until restart. A failed SaveConfig restores the previous value so memory never advertises a value disk doesn't have. GET /api/config now returns small_model.
  2. Frontend — "Model roles" section at the top of Settings → Providers: enabled models grouped by provider (native select + optgroup, mirroring the existing language-row pattern), "Not set (follow main model)" clears, save-on-change with inline saved/failed feedback. A configured ref whose model was since disabled/removed still renders as its raw ref marked unavailable so it can be seen and cleared. Localized in en / zh-Hans / zh-Hant / ja / ko.
  3. Docssite/docs/overview/models.md mentions the settings path; design rationale (API shape, effect semantics, the in-place-vs-reassign pitfall) recorded in internal-doc/small-model-settings-ui-design.md.

Testing

  • New handler tests (internal/web/small_model_test.go): in-place mutate + disk persist + GET round-trip; clear; four invalid-request cases leave config untouched; nil-config → 500.
  • go test ./internal/... green, golangci-lint run internal/web/ clean, tsc --noEmit clean.
  • Live end-to-end against an isolated-HOME backend through the vite dev server: enable a model → pick it as small model → config.json gains "small_model": "zai/glm-4.5-flash" → full page reload round-trips the selection; set/clear/validation also exercised over raw HTTP.

Screenshots / Recordings

The section renders as: ⚡ Small model + purpose description on the left, grouped picker on the right, directly above the provider cards (both light and dark themes verified).

Checklist

  • I have read the contributing guidelines.
  • My code follows the project's style guidelines.
  • I have performed a self-review of my code.
  • I have added/updated tests as needed.
  • I have updated relevant documentation.
  • All new and existing tests pass.

Additional Notes

  • Deliberately out of scope (recorded in the design doc): TUI settings entry, a "test connection" button (doctor already probes small_model), exposing memory.model, and auto-recommending a small model.
  • internal/model/registry_generated.go has unrelated pending churn in the working tree from a separate task; it is intentionally not part of this PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a Small model selector under Settings → Providers → Model roles.
    • Choose an enabled model by provider, clear the selection to follow the main model, and apply changes immediately without restarting.
    • Previously configured models that are no longer available are shown as unavailable.
    • Added localized interface support in English, Japanese, Korean, Simplified Chinese, and Traditional Chinese.
  • Documentation

    • Updated model role documentation with instructions for configuring the Small model.

Expose config.small_model in the web/desktop settings UI (Settings →
Providers), closing the v2 gap left by the small_model feature PR
(config-file only until now).

- POST /api/small-model sets/clears small_model; validates the provider
  exists and that provider/model are set-or-empty together. The handler
  mutates the live shared config pointer IN PLACE (browser-config
  pattern) so call-time readers — ModelFactory ("small" alias),
  automation override, title refiner — see the change immediately; the
  providers-style s.cfg reassign would leave buildWebTask's closure on
  the stale value until restart. A failed SaveConfig restores the
  previous value so memory never advertises a value disk doesn't have.
- GET /api/config now returns small_model.
- Settings → Providers gains a "Model roles" section: enabled models
  grouped by provider (native select + optgroup, mirroring the language
  row), "not set (follow main model)" clears, save-on-change with
  inline saved/failed feedback. A configured ref that is no longer
  enabled renders as its raw ref marked unavailable so it can still be
  cleared. i18n: en / zh-Hans / zh-Hant / ja / ko.
- Docs: models.md mentions the settings path; UI design doc + hi-fi
  mockup rationale under internal-doc/.

Verified: handler unit tests (in-place mutate + persist + GET
round-trip, clear, 4 invalid-request cases leave config untouched,
nil-config 500); go test ./internal/... green; golangci-lint clean;
web tsc clean; live e2e against an isolated-HOME backend through the
vite dev server — enable model → pick as small → config.json persisted
→ full page reload round-trips the selection.

Generated with Jack AI bot

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@cnjack, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 22a7ccaa-bebb-40f5-947e-0ef737ac3937

📥 Commits

Reviewing files that changed from the base of the PR and between ee42031 and 30ac116.

📒 Files selected for processing (1)
  • web/src/components/SettingsDialog.tsx
📝 Walkthrough

Walkthrough

Adds a small-model configuration API, persistence and validation tests, and a localized Providers settings picker that updates the live configuration without restart. Documentation and changelog entries describe the new role-selection workflow.

Changes

Small model settings

Layer / File(s) Summary
Small model API contract
internal-doc/small-model-settings-ui-design.md, internal/web/models.go, internal/web/server.go
Defines and implements small-model reading, clearing, provider validation, persistence, rollback, and route registration.
Backend persistence and validation
internal/web/small_model_test.go
Tests successful updates, clearing, disk persistence, API visibility, invalid requests, and nil configuration handling.
Providers model-role selection
web/src/lib/api.ts, web/src/app/store.ts, web/src/components/SettingsDialog.tsx, web/src/i18n/locales/*
Loads and stores small_model, posts selections, groups enabled models by provider, displays unavailable configured models, and adds translations in five locales.
Documentation and release notes
CHANGELOG.md, site/docs/overview/models.md
Documents the small-model picker, immediate updates, API exposure, and settings navigation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProvidersTab
  participant SmallModelAPI
  participant Config
  User->>ProvidersTab: Select small model
  ProvidersTab->>SmallModelAPI: POST provider and model
  SmallModelAPI->>Config: Update and save SmallModel
  Config-->>SmallModelAPI: Save result
  SmallModelAPI-->>ProvidersTab: Return configured small_model
  ProvidersTab-->>User: Show saved or failed status
Loading

Possibly related PRs

  • cnjack/jcode#137: Adds the small-model alias and routing behavior consumed by this configuration flow.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding a small_model picker in web settings under the Model roles section.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/small-model-settings-ui

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
web/src/components/SettingsDialog.tsx (1)

462-466: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add defensive check for missing separator.

If the backend configuration file was manually edited and lacks a /, indexOf('/') returns -1. The subsequent slice(0, -1) would silently strip the last character from the string before passing it as the provider. Adding a fallback ensures malformed inputs are correctly rejected by the API's validation.

🛡️ Proposed defensive fix
-      // Provider ids never contain '/'; model ids may (custom endpoints).
-      const i = value.indexOf('/')
-      provider = value.slice(0, i)
-      model = value.slice(i + 1)
+      // Provider ids never contain '/'; model ids may (custom endpoints).
+      const i = value.indexOf('/')
+      if (i >= 0) {
+        provider = value.slice(0, i)
+        model = value.slice(i + 1)
+      } else {
+        provider = ''
+        model = value
+      }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/SettingsDialog.tsx` around lines 462 - 466, Update the
provider/model parsing logic around indexOf('/') to detect a missing separator
before slicing; reject or otherwise pass the malformed value through the
existing API validation path instead of deriving provider and model from an
index of -1. Preserve the current first-separator parsing behavior for valid
values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@web/src/components/SettingsDialog.tsx`:
- Around line 462-466: Update the provider/model parsing logic around
indexOf('/') to detect a missing separator before slicing; reject or otherwise
pass the malformed value through the existing API validation path instead of
deriving provider and model from an index of -1. Preserve the current
first-separator parsing behavior for valid values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 85d644b9-ab0b-436f-affd-da763541d7aa

📥 Commits

Reviewing files that changed from the base of the PR and between 19f9250 and ee42031.

📒 Files selected for processing (14)
  • CHANGELOG.md
  • internal-doc/small-model-settings-ui-design.md
  • internal/web/models.go
  • internal/web/server.go
  • internal/web/small_model_test.go
  • site/docs/overview/models.md
  • web/src/app/store.ts
  • web/src/components/SettingsDialog.tsx
  • web/src/i18n/locales/en.ts
  • web/src/i18n/locales/ja.ts
  • web/src/i18n/locales/ko.ts
  • web/src/i18n/locales/zh-Hans.ts
  • web/src/i18n/locales/zh-Hant.ts
  • web/src/lib/api.ts

A hand-edited config can hold a ref without '/', which surfaces through
the "unavailable" select option; indexOf returning -1 made slice(0, -1)
chop the last character off the provider name before the API rejected
it. Pass such values as model-only so the backend's set-or-empty
validation rejects them intact.

Review: coderabbit nitpick on PR #139.

Generated with Jack AI bot

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cnjack

cnjack commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

Addressed the CodeRabbit nitpick in 30ac116: a separator-less small_model ref (hand-edited config surfaced via the "unavailable" option) is now passed as model-only so the API's set-or-empty validation rejects it intact, instead of slice(0, -1) chopping the provider name. Typecheck clean.

🤖 Addressed by Claude Code

@cnjack
cnjack merged commit ca81c56 into main Jul 14, 2026
4 of 5 checks passed
@cnjack
cnjack deleted the feat/small-model-settings-ui branch July 14, 2026 17:48
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.

1 participant