Skip to content

fix: code reviewer config — model dropdown, and default to your AI provider - #5990

Merged
atomantic merged 1 commit into
mainfrom
cos/task-mtl0oy4x/agent-7a16f4be
Sep 3, 2026
Merged

fix: code reviewer config — model dropdown, and default to your AI provider#5990
atomantic merged 1 commit into
mainfrom
cos/task-mtl0oy4x/agent-7a16f4be

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Two bugs in the Code Review Defaults panel (Settings › Code Reviewers) and the reviewer chain behind it.

1. The Model cell is a dropdown, not a text box

Every model-taking reviewer with a resolved catalog now renders a <select> of its ids, the same way the Effort column already worked.

CLI reviewers keep the ability to name an id no catalog can enumerate — an Ollama-backed claude, a Bedrock-form id — through a trailing Custom… entry that swaps the cell for a free-text input with the catalog offered as a <datalist>. Leaving that input empty returns the cell to the dropdown (on blur, not on an empty keystroke, so clearing the field to retype doesn't swap the control out from under the cursor).

Two cases deliberately still start as free text:

  • a reviewer whose catalog resolved empty (grok/kimi/opencode ship only a configured-default sentinel) — a select of nothing is a dead control;
  • a row already pinned to an id outside its catalog, so that pin stays editable rather than reading as an unpickable oddity.

A probed local backend (ollama/lmstudio) keeps its closed select — those ids came from the running daemon, so one it doesn't list isn't installed.

The Custom… sentinel is [custom], chosen so it can never be confused for a pin: sanitizeReviewerModelInput strips [/] as the user types and the server's REVIEWER_MODEL_FORBIDDEN_RE rejects them, so no build could have persisted it.

2. The unconfigured default follows your default AI provider

An install that had never opened the panel reviewed with GitHub Copilot — which needs a subscription it may not have, and ignores the agent the user already told PortOS to run.

The fallback now derives from the active AI provider: its reviewer slug, its defaultModel, and its reasoning effort. New in server/lib/reviewerConfig.js:

  • reviewerForProvider(provider) — local-LLM reviewers matched by provider id (ollama/lmstudio/mtplx, which spawn no binary), CLI reviewers matched by the binary the provider spawns, looked up through the existing REVIEWER_CLI_BINARIES table so the slug↔executable mapping (antigravityagy) stays in one place.
  • codeReviewDefaultsFromProvider(provider) — the reviewer plus its model and effort, or null when the provider maps to no reviewer.

Guardrails, all covered by tests:

  • a saved reviewer chain is never re-derived — the provider is consulted only when the user configured none;
  • a stored <reviewer>Model / <reviewer>Effort pin still wins over the derived one, per key;
  • a *-configured-default sentinel is dropped rather than pinned as a model (it means "whatever the CLI is configured for", not an id --model could take);
  • an effort outside the reviewer's own ladder is dropped, not clamped (agy really does reject --effort max);
  • copilot remains the last resort, for a hosted API provider that maps to no reviewer, or no provider at all.

getCodeReviewDefaults memoizes only the settings-derived answer, which settings:updated fully invalidates. The provider-derived one is re-resolved per call — switching the active provider fires no settings event, and the toolkit already caches the provider list in memory, so this costs no disk I/O.

Test plan

  • server/lib/reviewerConfig.test.js — CLI-binary and local-id mapping, locally-served wrappers, providers that map to nothing; sentinel-model and out-of-ladder-effort drops.
  • server/services/codeReview.test.js — derive from the active provider; leave a configured chain alone; stored pin beats derived; copilot kept for an unmappable provider; getCodeReviewDefaults end to end.
  • client/src/components/cos/ReviewerPicker.test.jsx — CLI reviewer renders a dropdown; Custom… swaps in the input and stores nothing; no escape offered to a probed backend; blur-with-nothing-pinned reverts; the input survives a clear-and-retype; an out-of-catalog pin stays editable.
  • Full suites green: server 38,084 passed, client 10,098 passed, npm run build clean.

Reviewed locally by claude (--review-with claude[claude-sonnet-5]~opt~max=1~effort=low) — clean, no findings.

https://claude.ai/code/session_016N4hdoetFHnLbmoUi2VqfR

…ovider

Two fixes to the Code Review Defaults panel (Settings › Code Reviewers) and
the reviewer chain behind it.

**Model is a dropdown, not a text box.** Every model-taking reviewer with a
resolved catalog now renders a `<select>` of its ids. CLI reviewers keep the
ability to name an id no catalog can enumerate (an Ollama-backed `claude`, a
Bedrock-form id) through a trailing "Custom…" entry that swaps the cell for a
free-text input; leaving that field empty returns it to the dropdown. A probed
local backend stays a closed list — its ids came from the running daemon — and a
reviewer whose catalog resolved empty still starts as free text rather than a
dead select.

**The unconfigured default follows your default AI provider.** An install that
has never opened the panel used to review with GitHub Copilot, which needs a
subscription it may not have and ignores the agent the user already chose. The
fallback now derives from the active provider — its reviewer slug, its default
model, its reasoning effort — with `copilot` kept only as the last resort for a
provider that maps to no reviewer at all (a hosted API provider, or none set). A
saved chain is untouched, a stored per-reviewer pin still wins over the derived
one, a `*-configured-default` sentinel is never pinned as a model, and an effort
outside the reviewer's own ladder is dropped rather than clamped.

Claude-Session: https://claude.ai/code/session_016N4hdoetFHnLbmoUi2VqfR
@atomantic
atomantic merged commit b35b914 into main Sep 3, 2026
10 of 14 checks passed
@atomantic
atomantic deleted the cos/task-mtl0oy4x/agent-7a16f4be branch September 3, 2026 04:53
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