diff --git a/internal/runtime/executor/kiro_executor.go b/internal/runtime/executor/kiro_executor.go index 5aaf3b97c9..ee90497bd4 100644 --- a/internal/runtime/executor/kiro_executor.go +++ b/internal/runtime/executor/kiro_executor.go @@ -1706,6 +1706,35 @@ func (e *KiroExecutor) mapModelToKiro(model string) string { "kiro-claude-sonnet-4-5-agentic": "claude-sonnet-4.5", "kiro-claude-sonnet-4-agentic": "claude-sonnet-4", "kiro-claude-haiku-4-5-agentic": "claude-haiku-4.5", + // --- Third-party / open-weight models (via Kiro) --- + // DeepSeek + "kiro-deepseek-3-2": "deepseek-3.2", + "deepseek-3-2": "deepseek-3.2", + "deepseek-3.2": "deepseek-3.2", + "kiro-deepseek-3-2-agentic": "deepseek-3.2", + "deepseek-3-2-agentic": "deepseek-3.2", + "deepseek-3.2-agentic": "deepseek-3.2", + // MiniMax + "kiro-minimax-m2-1": "minimax-m2.1", + "minimax-m2-1": "minimax-m2.1", + "minimax-m2.1": "minimax-m2.1", + "kiro-minimax-m2-1-agentic": "minimax-m2.1", + "minimax-m2-1-agentic": "minimax-m2.1", + "minimax-m2.1-agentic": "minimax-m2.1", + // Qwen3 Coder + "kiro-qwen3-coder-next": "qwen3-coder-next", + "qwen3-coder-next": "qwen3-coder-next", + "kiro-qwen3-coder-next-agentic": "qwen3-coder-next", + "qwen3-coder-next-agentic": "qwen3-coder-next", + // GPT models + "kiro-gpt-4o": "gpt-4o", + "gpt-4o": "gpt-4o", + "kiro-gpt-4": "gpt-4", + "kiro-gpt-4-turbo": "gpt-4-turbo", + "gpt-4-turbo": "gpt-4-turbo", + "kiro-gpt-3-5-turbo": "gpt-3.5-turbo", + "gpt-3-5-turbo": "gpt-3.5-turbo", + "gpt-3.5-turbo": "gpt-3.5-turbo", } if kiroID, ok := modelMap[model]; ok { return kiroID @@ -1750,6 +1779,42 @@ func (e *KiroExecutor) mapModelToKiro(model string) string { return "claude-opus-4.5" } + // Check for DeepSeek variants + if strings.Contains(modelLower, "deepseek") { + log.Debugf("kiro: unknown DeepSeek model '%s', mapping to deepseek-3.2", model) + return "deepseek-3.2" + } + + // Check for MiniMax variants + if strings.Contains(modelLower, "minimax") { + log.Debugf("kiro: unknown MiniMax model '%s', mapping to minimax-m2.1", model) + return "minimax-m2.1" + } + + // Check for Qwen variants + if strings.Contains(modelLower, "qwen") { + log.Debugf("kiro: unknown Qwen model '%s', mapping to qwen3-coder-next", model) + return "qwen3-coder-next" + } + + // Check for GPT variants + if strings.Contains(modelLower, "gpt-4o") { + log.Debugf("kiro: unknown GPT-4o model '%s', mapping to gpt-4o", model) + return "gpt-4o" + } + if strings.Contains(modelLower, "gpt-4-turbo") || strings.Contains(modelLower, "gpt-4turbo") { + log.Debugf("kiro: unknown GPT-4 Turbo model '%s', mapping to gpt-4-turbo", model) + return "gpt-4-turbo" + } + if strings.Contains(modelLower, "gpt-4") { + log.Debugf("kiro: unknown GPT-4 model '%s', mapping to gpt-4", model) + return "gpt-4" + } + if strings.Contains(modelLower, "gpt-3") || strings.Contains(modelLower, "gpt3") { + log.Debugf("kiro: unknown GPT-3 model '%s', mapping to gpt-3.5-turbo", model) + return "gpt-3.5-turbo" + } + // Final fallback to Sonnet 4.5 (most commonly used model) log.Warnf("kiro: unknown model '%s', falling back to claude-sonnet-4.5", model) return "claude-sonnet-4.5" diff --git a/internal/runtime/executor/kiro_executor_test.go b/internal/runtime/executor/kiro_executor_test.go index 7a2819fd74..8f97f9cfbf 100644 --- a/internal/runtime/executor/kiro_executor_test.go +++ b/internal/runtime/executor/kiro_executor_test.go @@ -398,6 +398,113 @@ func TestGetAccountKey(t *testing.T) { } } +func TestMapModelToKiro_OpenWeightModels(t *testing.T) { + e := &KiroExecutor{} + + tests := []struct { + name string + input string + expected string + }{ + // DeepSeek - all prefix formats + {"kiro-deepseek-3-2", "kiro-deepseek-3-2", "deepseek-3.2"}, + {"deepseek-3-2 (native hyphen)", "deepseek-3-2", "deepseek-3.2"}, + {"deepseek-3.2 (native dot)", "deepseek-3.2", "deepseek-3.2"}, + {"kiro-deepseek-3-2-agentic", "kiro-deepseek-3-2-agentic", "deepseek-3.2"}, + {"deepseek-3-2-agentic", "deepseek-3-2-agentic", "deepseek-3.2"}, + {"deepseek-3.2-agentic", "deepseek-3.2-agentic", "deepseek-3.2"}, + // MiniMax - all prefix formats + {"kiro-minimax-m2-1", "kiro-minimax-m2-1", "minimax-m2.1"}, + {"minimax-m2-1 (native hyphen)", "minimax-m2-1", "minimax-m2.1"}, + {"minimax-m2.1 (native dot)", "minimax-m2.1", "minimax-m2.1"}, + {"kiro-minimax-m2-1-agentic", "kiro-minimax-m2-1-agentic", "minimax-m2.1"}, + {"minimax-m2-1-agentic", "minimax-m2-1-agentic", "minimax-m2.1"}, + {"minimax-m2.1-agentic", "minimax-m2.1-agentic", "minimax-m2.1"}, + // Qwen3 Coder + {"kiro-qwen3-coder-next", "kiro-qwen3-coder-next", "qwen3-coder-next"}, + {"qwen3-coder-next (native)", "qwen3-coder-next", "qwen3-coder-next"}, + {"kiro-qwen3-coder-next-agentic", "kiro-qwen3-coder-next-agentic", "qwen3-coder-next"}, + {"qwen3-coder-next-agentic", "qwen3-coder-next-agentic", "qwen3-coder-next"}, + // GPT models + {"kiro-gpt-4o", "kiro-gpt-4o", "gpt-4o"}, + {"gpt-4o (native)", "gpt-4o", "gpt-4o"}, + {"kiro-gpt-4", "kiro-gpt-4", "gpt-4"}, + {"kiro-gpt-4-turbo", "kiro-gpt-4-turbo", "gpt-4-turbo"}, + {"gpt-4-turbo (native)", "gpt-4-turbo", "gpt-4-turbo"}, + {"kiro-gpt-3-5-turbo", "kiro-gpt-3-5-turbo", "gpt-3.5-turbo"}, + {"gpt-3-5-turbo (native hyphen)", "gpt-3-5-turbo", "gpt-3.5-turbo"}, + {"gpt-3.5-turbo (native dot)", "gpt-3.5-turbo", "gpt-3.5-turbo"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := e.mapModelToKiro(tt.input) + if result != tt.expected { + t.Errorf("mapModelToKiro(%q) = %q, want %q", tt.input, result, tt.expected) + } + }) + } +} + +func TestMapModelToKiro_FallbackPatterns(t *testing.T) { + e := &KiroExecutor{} + + tests := []struct { + name string + input string + expected string + }{ + // Open-weight fallback patterns + {"unknown deepseek variant", "some-deepseek-model", "deepseek-3.2"}, + {"unknown minimax variant", "some-minimax-model", "minimax-m2.1"}, + {"unknown qwen variant", "some-qwen-model", "qwen3-coder-next"}, + {"unknown gpt-4o variant", "custom-gpt-4o-fine", "gpt-4o"}, + {"unknown gpt-4-turbo variant", "custom-gpt-4-turbo-v2", "gpt-4-turbo"}, + {"unknown gpt-4 variant", "custom-gpt-4-latest", "gpt-4"}, + {"unknown gpt-3 variant", "custom-gpt-3-model", "gpt-3.5-turbo"}, + // Claude fallback patterns (existing, verify not broken) + {"unknown haiku variant", "some-haiku-model", "claude-haiku-4.5"}, + {"unknown sonnet variant", "some-sonnet-model", "claude-sonnet-4"}, + {"unknown opus variant", "some-opus-model", "claude-opus-4.5"}, + // Final fallback + {"completely unknown model", "totally-unknown-model", "claude-sonnet-4.5"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := e.mapModelToKiro(tt.input) + if result != tt.expected { + t.Errorf("mapModelToKiro(%q) = %q, want %q", tt.input, result, tt.expected) + } + }) + } +} + +func TestMapModelToKiro_ExistingClaudeModels(t *testing.T) { + e := &KiroExecutor{} + + // Verify existing Claude mappings are not broken + tests := []struct { + input string + expected string + }{ + {"kiro-auto", "auto"}, + {"kiro-claude-sonnet-4-5", "claude-sonnet-4.5"}, + {"kiro-claude-opus-4-6", "claude-opus-4.6"}, + {"claude-sonnet-4.5-agentic", "claude-sonnet-4.5"}, + {"amazonq-claude-haiku-4-5", "claude-haiku-4.5"}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + result := e.mapModelToKiro(tt.input) + if result != tt.expected { + t.Errorf("mapModelToKiro(%q) = %q, want %q", tt.input, result, tt.expected) + } + }) + } +} + func TestEndpointAliases(t *testing.T) { // Verify all expected aliases are defined expectedAliases := map[string]string{