mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-05 02:30:26 +08:00
REMOVED all hardcoded default backend/model values from defaultModelsConfig. Now ~/.codeagent/models.json is REQUIRED - missing config returns clear error with example configuration. BREAKING CHANGE: Users must configure ~/.codeagent/models.json before using --agent or parallel tasks with agent: field. Generated with SWE-Agent.ai Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
263 lines
7.3 KiB
Go
263 lines
7.3 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestResolveAgentConfig_NoConfig_ReturnsHelpfulError(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("HOME", home)
|
|
t.Setenv("USERPROFILE", home)
|
|
t.Cleanup(ResetModelsConfigCacheForTest)
|
|
ResetModelsConfigCacheForTest()
|
|
|
|
_, _, _, _, _, _, _, err := ResolveAgentConfig("develop")
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
msg := err.Error()
|
|
if !strings.Contains(msg, modelsConfigTildePath) {
|
|
t.Fatalf("error should mention %s, got: %s", modelsConfigTildePath, msg)
|
|
}
|
|
if !strings.Contains(msg, filepath.Join(home, ".codeagent", "models.json")) {
|
|
t.Fatalf("error should mention resolved config path, got: %s", msg)
|
|
}
|
|
if !strings.Contains(msg, "\"agents\"") {
|
|
t.Fatalf("error should include example config, got: %s", msg)
|
|
}
|
|
}
|
|
|
|
func TestLoadModelsConfig_NoFile(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("HOME", home)
|
|
t.Setenv("USERPROFILE", home)
|
|
t.Cleanup(ResetModelsConfigCacheForTest)
|
|
ResetModelsConfigCacheForTest()
|
|
|
|
_, err := loadModelsConfig()
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestLoadModelsConfig_WithFile(t *testing.T) {
|
|
// Create temp dir and config file
|
|
tmpDir := t.TempDir()
|
|
configDir := filepath.Join(tmpDir, ".codeagent")
|
|
if err := os.MkdirAll(configDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
configContent := `{
|
|
"default_backend": "claude",
|
|
"default_model": "claude-opus-4",
|
|
"backends": {
|
|
"Claude": {
|
|
"base_url": "https://backend.example",
|
|
"api_key": "backend-key"
|
|
},
|
|
"codex": {
|
|
"base_url": "https://openai.example",
|
|
"api_key": "openai-key"
|
|
}
|
|
},
|
|
"agents": {
|
|
"custom-agent": {
|
|
"backend": "codex",
|
|
"model": "gpt-4o",
|
|
"description": "Custom agent",
|
|
"base_url": "https://agent.example",
|
|
"api_key": "agent-key"
|
|
}
|
|
}
|
|
}`
|
|
configPath := filepath.Join(configDir, "models.json")
|
|
if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
t.Setenv("HOME", tmpDir)
|
|
t.Setenv("USERPROFILE", tmpDir)
|
|
t.Cleanup(ResetModelsConfigCacheForTest)
|
|
ResetModelsConfigCacheForTest()
|
|
|
|
cfg, err := loadModelsConfig()
|
|
if err != nil {
|
|
t.Fatalf("loadModelsConfig: %v", err)
|
|
}
|
|
|
|
if cfg.DefaultBackend != "claude" {
|
|
t.Errorf("DefaultBackend = %q, want %q", cfg.DefaultBackend, "claude")
|
|
}
|
|
if cfg.DefaultModel != "claude-opus-4" {
|
|
t.Errorf("DefaultModel = %q, want %q", cfg.DefaultModel, "claude-opus-4")
|
|
}
|
|
|
|
// Check custom agent
|
|
if agent, ok := cfg.Agents["custom-agent"]; !ok {
|
|
t.Error("custom-agent not found")
|
|
} else {
|
|
if agent.Backend != "codex" {
|
|
t.Errorf("custom-agent.Backend = %q, want %q", agent.Backend, "codex")
|
|
}
|
|
if agent.Model != "gpt-4o" {
|
|
t.Errorf("custom-agent.Model = %q, want %q", agent.Model, "gpt-4o")
|
|
}
|
|
}
|
|
|
|
if _, ok := cfg.Agents["oracle"]; ok {
|
|
t.Error("oracle should not be present without explicit config")
|
|
}
|
|
|
|
baseURL, apiKey := ResolveBackendConfig("claude")
|
|
if baseURL != "https://backend.example" {
|
|
t.Errorf("ResolveBackendConfig(baseURL) = %q, want %q", baseURL, "https://backend.example")
|
|
}
|
|
if apiKey != "backend-key" {
|
|
t.Errorf("ResolveBackendConfig(apiKey) = %q, want %q", apiKey, "backend-key")
|
|
}
|
|
|
|
backend, model, _, _, agentBaseURL, agentAPIKey, _, err := ResolveAgentConfig("custom-agent")
|
|
if err != nil {
|
|
t.Fatalf("ResolveAgentConfig(custom-agent): %v", err)
|
|
}
|
|
if backend != "codex" {
|
|
t.Errorf("ResolveAgentConfig(backend) = %q, want %q", backend, "codex")
|
|
}
|
|
if model != "gpt-4o" {
|
|
t.Errorf("ResolveAgentConfig(model) = %q, want %q", model, "gpt-4o")
|
|
}
|
|
if agentBaseURL != "https://agent.example" {
|
|
t.Errorf("ResolveAgentConfig(baseURL) = %q, want %q", agentBaseURL, "https://agent.example")
|
|
}
|
|
if agentAPIKey != "agent-key" {
|
|
t.Errorf("ResolveAgentConfig(apiKey) = %q, want %q", agentAPIKey, "agent-key")
|
|
}
|
|
}
|
|
|
|
func TestResolveAgentConfig_DynamicAgent(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("HOME", home)
|
|
t.Setenv("USERPROFILE", home)
|
|
t.Cleanup(ResetModelsConfigCacheForTest)
|
|
ResetModelsConfigCacheForTest()
|
|
|
|
agentDir := filepath.Join(home, ".codeagent", "agents")
|
|
if err := os.MkdirAll(agentDir, 0o755); err != nil {
|
|
t.Fatalf("MkdirAll: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(agentDir, "sarsh.md"), []byte("prompt\n"), 0o644); err != nil {
|
|
t.Fatalf("WriteFile: %v", err)
|
|
}
|
|
|
|
configDir := filepath.Join(home, ".codeagent")
|
|
if err := os.MkdirAll(configDir, 0o755); err != nil {
|
|
t.Fatalf("MkdirAll: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(configDir, "models.json"), []byte(`{
|
|
"default_backend": "codex",
|
|
"default_model": "gpt-test"
|
|
}`), 0o644); err != nil {
|
|
t.Fatalf("WriteFile: %v", err)
|
|
}
|
|
|
|
backend, model, promptFile, _, _, _, _, err := ResolveAgentConfig("sarsh")
|
|
if err != nil {
|
|
t.Fatalf("ResolveAgentConfig(sarsh): %v", err)
|
|
}
|
|
if backend != "codex" {
|
|
t.Errorf("backend = %q, want %q", backend, "codex")
|
|
}
|
|
if model != "gpt-test" {
|
|
t.Errorf("model = %q, want %q", model, "gpt-test")
|
|
}
|
|
if promptFile != "~/.codeagent/agents/sarsh.md" {
|
|
t.Errorf("promptFile = %q, want %q", promptFile, "~/.codeagent/agents/sarsh.md")
|
|
}
|
|
}
|
|
|
|
func TestLoadModelsConfig_InvalidJSON(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configDir := filepath.Join(tmpDir, ".codeagent")
|
|
if err := os.MkdirAll(configDir, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Write invalid JSON
|
|
configPath := filepath.Join(configDir, "models.json")
|
|
if err := os.WriteFile(configPath, []byte("invalid json {"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
t.Setenv("HOME", tmpDir)
|
|
t.Setenv("USERPROFILE", tmpDir)
|
|
t.Cleanup(ResetModelsConfigCacheForTest)
|
|
ResetModelsConfigCacheForTest()
|
|
|
|
_, err := loadModelsConfig()
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestResolveAgentConfig_UnknownAgent_ReturnsError(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("HOME", home)
|
|
t.Setenv("USERPROFILE", home)
|
|
t.Cleanup(ResetModelsConfigCacheForTest)
|
|
ResetModelsConfigCacheForTest()
|
|
|
|
configDir := filepath.Join(home, ".codeagent")
|
|
if err := os.MkdirAll(configDir, 0o755); err != nil {
|
|
t.Fatalf("MkdirAll: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(configDir, "models.json"), []byte(`{
|
|
"default_backend": "codex",
|
|
"default_model": "gpt-test",
|
|
"agents": {
|
|
"develop": { "backend": "codex", "model": "gpt-test" }
|
|
}
|
|
}`), 0o644); err != nil {
|
|
t.Fatalf("WriteFile: %v", err)
|
|
}
|
|
|
|
_, _, _, _, _, _, _, err := ResolveAgentConfig("unknown-agent")
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "unknown-agent") {
|
|
t.Fatalf("error should mention agent name, got: %s", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestResolveAgentConfig_EmptyModel_ReturnsError(t *testing.T) {
|
|
home := t.TempDir()
|
|
t.Setenv("HOME", home)
|
|
t.Setenv("USERPROFILE", home)
|
|
t.Cleanup(ResetModelsConfigCacheForTest)
|
|
ResetModelsConfigCacheForTest()
|
|
|
|
configDir := filepath.Join(home, ".codeagent")
|
|
if err := os.MkdirAll(configDir, 0o755); err != nil {
|
|
t.Fatalf("MkdirAll: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(configDir, "models.json"), []byte(`{
|
|
"agents": {
|
|
"bad-agent": { "backend": "codex", "model": " " }
|
|
}
|
|
}`), 0o644); err != nil {
|
|
t.Fatalf("WriteFile: %v", err)
|
|
}
|
|
|
|
_, _, _, _, _, _, _, err := ResolveAgentConfig("bad-agent")
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
if !strings.Contains(strings.ToLower(err.Error()), "empty model") {
|
|
t.Fatalf("error should mention empty model, got: %s", err.Error())
|
|
}
|
|
}
|