package agent import ( "context" "testing" "time" ) func TestCoopBaseURL(t *testing.T) { tests := []struct { name string provider string engine string baseURL string want string }{ // ---- pi / claude(用 @anthropic-ai/sdk,自带 /v1/messages,不能补 /v1)---- // Anthropic:剥离 /v1,避免双重 /v1/v1/messages {"pi/anthropic bare", "anthropic", "pi", "https://api.deepseek.com/anthropic", "https://api.deepseek.com/anthropic"}, {"pi/anthropic trailing slash", "anthropic", "pi", "https://api.deepseek.com/anthropic/", "https://api.deepseek.com/anthropic"}, {"pi/anthropic with /v1", "anthropic", "pi", "https://api.deepseek.com/anthropic/v1", "https://api.deepseek.com/anthropic"}, {"pi/anthropic with /v1/messages", "anthropic", "pi", "https://api.deepseek.com/anthropic/v1/messages", "https://api.deepseek.com/anthropic"}, {"pi/anthropic with /messages", "anthropic", "pi", "https://api.deepseek.com/anthropic/messages", "https://api.deepseek.com/anthropic"}, {"pi/anthropic anthropic.com", "anthropic", "pi", "https://api.anthropic.com", "https://api.anthropic.com"}, // claude 行为与 pi 一致 {"claude/anthropic bare", "anthropic", "claude", "https://api.deepseek.com/anthropic", "https://api.deepseek.com/anthropic"}, {"claude/anthropic with /v1", "anthropic", "claude", "https://api.deepseek.com/anthropic/v1", "https://api.deepseek.com/anthropic"}, // ---- pigo(anthropicCompatDriver 只追加 /messages,需补 /v1)---- {"pigo/anthropic bare", "anthropic", "pigo", "https://api.deepseek.com/anthropic", "https://api.deepseek.com/anthropic/v1"}, {"pigo/anthropic trailing slash", "anthropic", "pigo", "https://api.deepseek.com/anthropic/", "https://api.deepseek.com/anthropic/v1"}, {"pigo/anthropic with /v1", "anthropic", "pigo", "https://api.deepseek.com/anthropic/v1", "https://api.deepseek.com/anthropic/v1"}, {"pigo/anthropic with /v1/messages", "anthropic", "pigo", "https://api.deepseek.com/anthropic/v1/messages", "https://api.deepseek.com/anthropic/v1"}, {"pigo/anthropic with /messages", "anthropic", "pigo", "https://api.deepseek.com/anthropic/messages", "https://api.deepseek.com/anthropic/v1"}, {"pigo/anthropic anthropic.com", "anthropic", "pigo", "https://api.anthropic.com", "https://api.anthropic.com/v1"}, // ---- OpenAI 协议(三种 engine 行为一致:保留 /v1,剥离 /chat/completions)---- {"pi/openai full url", "openai", "pi", "https://api.siliconflow.cn/v1/chat/completions", "https://api.siliconflow.cn/v1"}, {"pi/openai with /v1", "openai", "pi", "https://api.siliconflow.cn/v1", "https://api.siliconflow.cn/v1"}, {"pi/openai bare", "openai", "pi", "https://api.siliconflow.cn", "https://api.siliconflow.cn"}, {"pigo/openai full url", "openai", "pigo", "https://api.siliconflow.cn/v1/chat/completions", "https://api.siliconflow.cn/v1"}, {"pigo/openai bare", "openai", "pigo", "https://api.siliconflow.cn", "https://api.siliconflow.cn"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := coopBaseURL(tt.provider, tt.baseURL, tt.engine) if got != tt.want { t.Errorf("coopBaseURL(%q, %q, %q) = %q, want %q", tt.provider, tt.baseURL, tt.engine, got, tt.want) } }) } } func TestRunCoopErrorPaths(t *testing.T) { apiCfg := &APIConfigStore{} apiCfg.config = APIConfig{APIKey: "test-key", BaseURL: "https://api.deepseek.com/anthropic", Model: "deepseek-chat"} toolset := &Toolset{ Workspace: ".", Timeout: 30 * time.Second, MaxOutput: 4000, apiCfg: apiCfg, dockerSocket: defaultDockerSocket, coop: NewCoopManager(), sessionRoot: t.TempDir(), } // 1. 缺少 task r := toolset.runCoop(context.Background(), "test-session", map[string]any{}) if r.Success || r.Output == "" { t.Fatalf("empty task should fail, got %#v", r) } // 2. 正常参数:应进入 Docker 检查阶段(本机无 Docker 时返回连接/镜像错误而非 panic) r = toolset.runCoop(context.Background(), "test-session", map[string]any{ "task": "测试任务", "round_max": 2, "timeout": 30, }) t.Logf("runCoop output: %s", r.Output) if r.Success { // 若真的跑成功了(有 Docker 且镜像存在),也无妨 t.Logf("coop unexpectedly succeeded") } }