From 8498e603077dcd4e0e7925eac158c9d58902a749 Mon Sep 17 00:00:00 2001 From: piekstra Date: Fri, 7 Aug 2026 07:38:35 -0400 Subject: [PATCH] fix(config): run the Claude CLI small tier on Sonnet, not Haiku #557 mapped small to claude-haiku-4-5 to stop an agent's small tier from aborting the whole review. That fixed the abort and picked the wrong model: Haiku is not one a code review should rest on, and the tier existed so an agent could say "this job is narrow", not "grade this with the weakest model available". Map small to claude-sonnet-5, the same model medium resolves to. A tier is what an agent asks for and the built-in is what this CLI is willing to run a review on; nothing obliges the two smallest tiers to differ when the cheaper model is not one worth running. An operator who does want a smaller model for small still names it in llm.model_map, which is where a cost-quality judgment belongs. --- README.md | 10 ++++++++-- internal/cmd/configcmd/configcmd_test.go | 2 +- internal/cmd/initcmd/initcmd_test.go | 2 +- internal/config/config.go | 2 +- internal/config/config_test.go | 2 +- internal/stagemodel/resolver_test.go | 2 +- internal/view/config_test.go | 2 +- 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f72885a..91c64eb 100644 --- a/README.md +++ b/README.md @@ -683,14 +683,20 @@ Built-in model maps: |----------|---------|-------|--------|-------| | `openai` | `codex_cli` | `gpt-5.4-mini` | `gpt-5.4` | `gpt-5.5` | | `openai` | `openai_api` | `gpt-5.4-mini` | `gpt-5.4` | `gpt-5.5` | -| `anthropic` | `claude_cli` | `claude-haiku-4-5` | `claude-sonnet-5` | `claude-opus-5` | +| `anthropic` | `claude_cli` | `claude-sonnet-5` | `claude-sonnet-5` | `claude-opus-5` | | `anthropic` | `anthropic_api` | unset | unset | unset | | `pi` | `pi_rpc` | unset | unset | unset | `anthropic_api` and `pi_rpc` require explicit `llm.model_map` entries for every tier an agent asks for; an unmapped tier fails the run and names the entry to add. A built-in mapping is a floor, not a recommendation: override the tier in -`llm.model_map` when a stage deserves a stronger model than its tier implies. +`llm.model_map` when a stage deserves a different model than its tier implies. + +`claude_cli` maps `small` and `medium` to the same model deliberately. A tier is +what an agent asks for, and the built-in is what this CLI is willing to run a +review on; nothing obliges the two smallest tiers to differ when the cheaper +model is not one a review should rest on. An operator who wants a genuinely +smaller model for `small` names it in `llm.model_map`. For Anthropic subscription profiles, `adapter: claude_cli` runs Claude Code background jobs, writes the full review task to `cr-prompt.txt` in an diff --git a/internal/cmd/configcmd/configcmd_test.go b/internal/cmd/configcmd/configcmd_test.go index e6e00d2..4572877 100644 --- a/internal/cmd/configcmd/configcmd_test.go +++ b/internal/cmd/configcmd/configcmd_test.go @@ -2130,7 +2130,7 @@ func TestConfigLLMModelsListAndResolve(t *testing.T) { if err := root.Execute(cmd, []string{"--profile", "home", "config", "llm", "models", "list"}); err != nil { t.Fatalf("Execute list: %v", err) } - if !strings.Contains(out.String(), "small: claude-haiku-4-5 (built_in)") || + if !strings.Contains(out.String(), "small: claude-sonnet-5 (built_in)") || !strings.Contains(out.String(), "medium: claude-sonnet-5 (built_in)") || !strings.Contains(out.String(), "large: claude-opus-5 (built_in)") { t.Fatalf("list stdout = %q, want effective Claude CLI defaults", out.String()) diff --git a/internal/cmd/initcmd/initcmd_test.go b/internal/cmd/initcmd/initcmd_test.go index 0b7c233..1f23a71 100644 --- a/internal/cmd/initcmd/initcmd_test.go +++ b/internal/cmd/initcmd/initcmd_test.go @@ -10365,7 +10365,7 @@ func TestInitProfileV2LLMRuntimeSelectionRefreshesModelMapFields(t *testing.T) { }, } model := newInitProfileV2ReadOnlyModel(newTestInitProfileV2EditorWithRuntimeAndModelMap("monit", "github.com/SignalFT", llmRuntimes, "claude-work"), 160, 24) - if got := model.document.fieldValue(initProfileV2FieldModelMap(config.ModelTierSmall)); got != "claude-haiku-4-5" { + if got := model.document.fieldValue(initProfileV2FieldModelMap(config.ModelTierSmall)); got != "claude-sonnet-5" { t.Fatalf("initial small model = %q, want Claude built-in", got) } if got := model.document.fieldValue(initProfileV2FieldModelMap(config.ModelTierMedium)); got != "claude-sonnet-5" { diff --git a/internal/config/config.go b/internal/config/config.go index 1989bb3..c1caad1 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -539,7 +539,7 @@ var llmRuntimeSpecs = []LLMRuntimeSpec{ SuggestedName: "claude-cli", DisplayName: "Claude CLI", BuiltInModelMap: ModelMap{ - string(ModelTierSmall): "claude-haiku-4-5", + string(ModelTierSmall): "claude-sonnet-5", string(ModelTierMedium): "claude-sonnet-5", string(ModelTierLarge): "claude-opus-5", }, diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 9f4a0fb..8251182 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -450,7 +450,7 @@ func TestBuiltInModelMapIsProviderAdapterSpecific(t *testing.T) { provider: LLMProviderAnthropic, adapter: LLMAdapterClaudeCLI, want: ModelMap{ - "small": "claude-haiku-4-5", + "small": "claude-sonnet-5", "medium": "claude-sonnet-5", "large": "claude-opus-5", }, diff --git a/internal/stagemodel/resolver_test.go b/internal/stagemodel/resolver_test.go index cad301c..3db0ae9 100644 --- a/internal/stagemodel/resolver_test.go +++ b/internal/stagemodel/resolver_test.go @@ -177,7 +177,7 @@ func TestResolveStageModelMapsSmallTierForClaudeCLI(t *testing.T) { if err != nil { t.Fatalf("ResolveStageModel: %v", err) } - if resolved.Model != "claude-haiku-4-5" || resolved.Source != config.ModelMapSourceBuiltIn { + if resolved.Model != "claude-sonnet-5" || resolved.Source != config.ModelMapSourceBuiltIn { t.Fatalf("resolved = %#v, want the built-in Claude CLI small model", resolved) } } diff --git a/internal/view/config_test.go b/internal/view/config_test.go index 9eb5256..ba4a555 100644 --- a/internal/view/config_test.go +++ b/internal/view/config_test.go @@ -209,7 +209,7 @@ LLM: Adapter: claude_cli Credential name: adapter-managed; not stored by cr Model map: - small: claude-haiku-4-5 (built_in) + small: claude-sonnet-5 (built_in) medium: claude-sonnet-5 (built_in) large: claude-opus-5 (built_in) Credentials: