shelley: add Claude Opus 4.6 as the default model

Philip Zeyliger and Shelley created

Prompt: Opus 4.6 just released. Add it to shelley. Make it the default model.

Add claude-opus-4-6 model constant and make it the new default model
for Shelley. Claude Opus 4.5 remains available as a fallback option.

Co-authored-by: Shelley <shelley@exe.dev>

Change summary

llm/ant/ant.go        |  3 ++-
models/models.go      | 21 +++++++++++++++++++--
models/models_test.go | 17 +++++++++--------
3 files changed, 30 insertions(+), 11 deletions(-)

Detailed changes

llm/ant/ant.go 🔗

@@ -32,6 +32,7 @@ const (
 	Claude4Sonnet  = "claude-sonnet-4-20250514"
 	Claude45Sonnet = "claude-sonnet-4-5-20250929"
 	Claude45Opus   = "claude-opus-4-5-20251101"
+	Claude46Opus   = "claude-opus-4-6"
 )
 
 // IsClaudeModel reports whether userName is a user-friendly Claude model.
@@ -65,7 +66,7 @@ func (s *Service) TokenContextWindow() int {
 		return 200000
 	case Claude45Haiku:
 		return 200000
-	case Claude45Opus:
+	case Claude45Opus, Claude46Opus:
 		return 200000
 	default:
 		// Default for unknown models

models/models.go 🔗

@@ -156,10 +156,27 @@ func (c *Config) getFireworksURL() string {
 // All returns all available models in Shelley
 func All() []Model {
 	return []Model{
+		{
+			ID:              "claude-opus-4.6",
+			Provider:        ProviderAnthropic,
+			Description:     "Claude Opus 4.6 (default)",
+			RequiredEnvVars: []string{"ANTHROPIC_API_KEY"},
+			GatewayEnabled:  true,
+			Factory: func(config *Config, httpc *http.Client) (llm.Service, error) {
+				if config.AnthropicAPIKey == "" {
+					return nil, fmt.Errorf("claude-opus-4.6 requires ANTHROPIC_API_KEY")
+				}
+				svc := &ant.Service{APIKey: config.AnthropicAPIKey, Model: ant.Claude46Opus, HTTPC: httpc, ThinkingLevel: llm.ThinkingLevelMedium}
+				if url := config.getAnthropicURL(); url != "" {
+					svc.URL = url
+				}
+				return svc, nil
+			},
+		},
 		{
 			ID:              "claude-opus-4.5",
 			Provider:        ProviderAnthropic,
-			Description:     "Claude Opus 4.5 (default)",
+			Description:     "Claude Opus 4.5",
 			RequiredEnvVars: []string{"ANTHROPIC_API_KEY"},
 			GatewayEnabled:  true,
 			Factory: func(config *Config, httpc *http.Client) (llm.Service, error) {
@@ -343,7 +360,7 @@ func IDs() []string {
 
 // Default returns the default model
 func Default() Model {
-	return All()[0] // claude-opus-4.5
+	return All()[0] // claude-opus-4.6
 }
 
 // Manager manages LLM services for all configured models

models/models_test.go 🔗

@@ -40,6 +40,7 @@ func TestByID(t *testing.T) {
 		{id: "claude-sonnet-4.5", wantID: "claude-sonnet-4.5", wantNil: false},
 		{id: "claude-haiku-4.5", wantID: "claude-haiku-4.5", wantNil: false},
 		{id: "claude-opus-4.5", wantID: "claude-opus-4.5", wantNil: false},
+		{id: "claude-opus-4.6", wantID: "claude-opus-4.6", wantNil: false},
 		{id: "nonexistent", wantNil: true},
 	}
 
@@ -64,8 +65,8 @@ func TestByID(t *testing.T) {
 
 func TestDefault(t *testing.T) {
 	d := Default()
-	if d.ID != "claude-opus-4.5" {
-		t.Errorf("Default().ID = %q, want %q", d.ID, "claude-opus-4.5")
+	if d.ID != "claude-opus-4.6" {
+		t.Errorf("Default().ID = %q, want %q", d.ID, "claude-opus-4.6")
 	}
 }
 
@@ -299,8 +300,8 @@ func TestManagerHasModel(t *testing.T) {
 	}
 
 	// Should not have models requiring API keys
-	if manager.HasModel("claude-opus-4.5") {
-		t.Error("HasModel('claude-opus-4.5') should return false without API key")
+	if manager.HasModel("claude-opus-4.6") {
+		t.Error("HasModel('claude-opus-4.6') should return false without API key")
 	}
 
 	// Should not have non-existent model
@@ -415,19 +416,19 @@ func TestGetModelSource(t *testing.T) {
 		{
 			name:    "anthropic with env var only",
 			cfg:     &Config{AnthropicAPIKey: "test-key"},
-			modelID: "claude-opus-4.5",
+			modelID: "claude-opus-4.6",
 			want:    "$ANTHROPIC_API_KEY",
 		},
 		{
 			name:    "anthropic with gateway implicit key",
 			cfg:     &Config{Gateway: "https://gateway.example.com", AnthropicAPIKey: "implicit"},
-			modelID: "claude-opus-4.5",
+			modelID: "claude-opus-4.6",
 			want:    "exe.dev gateway",
 		},
 		{
 			name:    "anthropic with gateway but explicit key",
 			cfg:     &Config{Gateway: "https://gateway.example.com", AnthropicAPIKey: "actual-key"},
-			modelID: "claude-opus-4.5",
+			modelID: "claude-opus-4.6",
 			want:    "$ANTHROPIC_API_KEY",
 		},
 		{
@@ -497,7 +498,7 @@ func TestGetAvailableModelsUnion(t *testing.T) {
 	models := manager.GetAvailableModels()
 
 	// Should have anthropic models and fireworks models, plus predictable
-	expectedModels := []string{"claude-opus-4.5", "qwen3-coder-fireworks", "glm-4p6-fireworks", "claude-sonnet-4.5", "claude-haiku-4.5", "predictable"}
+	expectedModels := []string{"claude-opus-4.6", "claude-opus-4.5", "qwen3-coder-fireworks", "glm-4p6-fireworks", "claude-sonnet-4.5", "claude-haiku-4.5", "predictable"}
 	for _, expected := range expectedModels {
 		found := false
 		for _, m := range models {