mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat(providers): add LongCat model provider support (#1317)
* feat(providers): add LongCat model provider support Add LongCat as an OpenAI-compatible provider with base URL https://api.longcat.chat/openai and default model LongCat-Flash-Thinking. Includes provider config, migration, factory routing, example config, tests, and README entries for all 6 locales. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(providers): address LongCat review feedback - Add dedicated factory routing test for LongCat provider - Add longcat to DefaultAPIBase test coverage - Set default api_base in example config providers section Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test(providers): add ResolveProviderSelection tests for LongCat Add two test cases to TestResolveProviderSelection: - Explicit provider selection with api_base default and proxy wiring - Fallback inference from model name with api_base default --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -221,6 +221,15 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
|
||||
sel.apiBase = "https://api.minimaxi.com/v1"
|
||||
}
|
||||
}
|
||||
case "longcat":
|
||||
if cfg.Providers.LongCat.APIKey != "" {
|
||||
sel.apiKey = cfg.Providers.LongCat.APIKey
|
||||
sel.apiBase = cfg.Providers.LongCat.APIBase
|
||||
sel.proxy = cfg.Providers.LongCat.Proxy
|
||||
if sel.apiBase == "" {
|
||||
sel.apiBase = "https://api.longcat.chat/openai"
|
||||
}
|
||||
}
|
||||
case "github_copilot", "copilot":
|
||||
sel.providerType = providerTypeGitHubCopilot
|
||||
if cfg.Providers.GitHubCopilot.APIBase != "" {
|
||||
@@ -352,6 +361,13 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
|
||||
if sel.apiBase == "" {
|
||||
sel.apiBase = "https://api.avian.io/v1"
|
||||
}
|
||||
case (strings.Contains(lowerModel, "longcat") || strings.HasPrefix(model, "longcat/")) && cfg.Providers.LongCat.APIKey != "":
|
||||
sel.apiKey = cfg.Providers.LongCat.APIKey
|
||||
sel.apiBase = cfg.Providers.LongCat.APIBase
|
||||
sel.proxy = cfg.Providers.LongCat.Proxy
|
||||
if sel.apiBase == "" {
|
||||
sel.apiBase = "https://api.longcat.chat/openai"
|
||||
}
|
||||
case cfg.Providers.VLLM.APIBase != "":
|
||||
sel.apiKey = cfg.Providers.VLLM.APIKey
|
||||
sel.apiBase = cfg.Providers.VLLM.APIBase
|
||||
|
||||
@@ -95,7 +95,7 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
||||
case "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
|
||||
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
|
||||
"vivgrid", "volcengine", "vllm", "qwen", "mistral", "avian",
|
||||
"minimax":
|
||||
"minimax", "longcat":
|
||||
// All other OpenAI-compatible HTTP providers
|
||||
if cfg.APIKey == "" && cfg.APIBase == "" {
|
||||
return nil, "", fmt.Errorf("api_key or api_base is required for HTTP-based protocol %q", protocol)
|
||||
@@ -215,6 +215,8 @@ func getDefaultAPIBase(protocol string) string {
|
||||
return "https://api.avian.io/v1"
|
||||
case "minimax":
|
||||
return "https://api.minimaxi.com/v1"
|
||||
case "longcat":
|
||||
return "https://api.longcat.chat/openai"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ func TestCreateProviderFromConfig_DefaultAPIBase(t *testing.T) {
|
||||
{"vllm", "vllm"},
|
||||
{"deepseek", "deepseek"},
|
||||
{"ollama", "ollama"},
|
||||
{"longcat", "longcat"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -162,6 +163,29 @@ func TestCreateProviderFromConfig_LiteLLM(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateProviderFromConfig_LongCat(t *testing.T) {
|
||||
cfg := &config.ModelConfig{
|
||||
ModelName: "test-longcat",
|
||||
Model: "longcat/LongCat-Flash-Thinking",
|
||||
APIKey: "test-key",
|
||||
APIBase: "https://api.longcat.chat/openai",
|
||||
}
|
||||
|
||||
provider, modelID, err := CreateProviderFromConfig(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateProviderFromConfig() error = %v", err)
|
||||
}
|
||||
if provider == nil {
|
||||
t.Fatal("CreateProviderFromConfig() returned nil provider")
|
||||
}
|
||||
if modelID != "LongCat-Flash-Thinking" {
|
||||
t.Errorf("modelID = %q, want %q", modelID, "LongCat-Flash-Thinking")
|
||||
}
|
||||
if _, ok := provider.(*HTTPProvider); !ok {
|
||||
t.Fatalf("expected *HTTPProvider, got %T", provider)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateProviderFromConfig_Anthropic(t *testing.T) {
|
||||
cfg := &config.ModelConfig{
|
||||
ModelName: "test-anthropic",
|
||||
|
||||
@@ -178,6 +178,26 @@ func TestResolveProviderSelection(t *testing.T) {
|
||||
wantAPIBase: "https://api.moonshot.cn/v1",
|
||||
wantProxy: "http://127.0.0.1:7890",
|
||||
},
|
||||
{
|
||||
name: "explicit longcat provider uses defaults",
|
||||
setup: func(cfg *config.Config) {
|
||||
cfg.Agents.Defaults.Provider = "longcat"
|
||||
cfg.Providers.LongCat.APIKey = "longcat-key"
|
||||
cfg.Providers.LongCat.Proxy = "http://127.0.0.1:7890"
|
||||
},
|
||||
wantType: providerTypeHTTPCompat,
|
||||
wantAPIBase: "https://api.longcat.chat/openai",
|
||||
wantProxy: "http://127.0.0.1:7890",
|
||||
},
|
||||
{
|
||||
name: "longcat model fallback uses longcat base default",
|
||||
setup: func(cfg *config.Config) {
|
||||
cfg.Agents.Defaults.Model = "longcat/LongCat-Flash-Thinking"
|
||||
cfg.Providers.LongCat.APIKey = "longcat-key"
|
||||
},
|
||||
wantType: providerTypeHTTPCompat,
|
||||
wantAPIBase: "https://api.longcat.chat/openai",
|
||||
},
|
||||
{
|
||||
name: "missing keys returns model config error",
|
||||
setup: func(cfg *config.Config) {
|
||||
|
||||
Reference in New Issue
Block a user