mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat(provider): add lmstudio and align local provider default auth/base handling (#2193)
* feat(provider): add lmstudio vendor and local no-key behavior * refactor(provider): consolidate protocol metadata and local tests * fix(provider): sync lmstudio probing and model normalization * test(web): format lmstudio model status cases for golines
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
"github.com/sipeed/picoclaw/pkg/providers"
|
||||
)
|
||||
|
||||
const modelProbeTimeout = 800 * time.Millisecond
|
||||
@@ -60,10 +61,14 @@ func requiresRuntimeProbe(m *config.ModelConfig) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
switch modelProtocol(m.Model) {
|
||||
protocol := modelProtocol(m.Model)
|
||||
|
||||
switch protocol {
|
||||
case "claude-cli", "claudecli", "codex-cli", "codexcli", "github-copilot", "copilot":
|
||||
return true
|
||||
case "ollama", "vllm":
|
||||
}
|
||||
|
||||
if providers.IsEmptyAPIKeyAllowedForProtocol(protocol) {
|
||||
apiBase := strings.TrimSpace(m.APIBase)
|
||||
return apiBase == "" || hasLocalAPIBase(apiBase)
|
||||
}
|
||||
@@ -81,7 +86,7 @@ func probeLocalModelAvailability(m *config.ModelConfig) bool {
|
||||
switch protocol {
|
||||
case "ollama":
|
||||
return probeOllamaModelFunc(apiBase, modelID)
|
||||
case "vllm":
|
||||
case "vllm", "lmstudio":
|
||||
return probeOpenAICompatibleModelFunc(apiBase, modelID, m.APIKey())
|
||||
case "github-copilot", "copilot":
|
||||
return probeTCPServiceFunc(apiBase)
|
||||
@@ -100,11 +105,12 @@ func modelProbeAPIBase(m *config.ModelConfig) string {
|
||||
return normalizeModelProbeAPIBase(apiBase)
|
||||
}
|
||||
|
||||
switch modelProtocol(m.Model) {
|
||||
case "ollama":
|
||||
return "http://localhost:11434/v1"
|
||||
case "vllm":
|
||||
return "http://localhost:8000/v1"
|
||||
protocol := modelProtocol(m.Model)
|
||||
if providers.IsEmptyAPIKeyAllowedForProtocol(protocol) {
|
||||
return providers.DefaultAPIBaseForProtocol(protocol)
|
||||
}
|
||||
|
||||
switch protocol {
|
||||
case "github-copilot", "copilot":
|
||||
return "localhost:4321"
|
||||
default:
|
||||
|
||||
@@ -35,3 +35,53 @@ func TestProbeLocalModelAvailability_OpenAICompatibleIncludesAPIKey(t *testing.T
|
||||
t.Fatal("probeLocalModelAvailability() = false, want true when api_key is configured")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequiresRuntimeProbe_LMStudio(t *testing.T) {
|
||||
if !requiresRuntimeProbe(&config.ModelConfig{
|
||||
Model: "lmstudio/openai/gpt-oss-20b",
|
||||
}) {
|
||||
t.Fatal("requiresRuntimeProbe(lmstudio with default base) = false, want true")
|
||||
}
|
||||
|
||||
if requiresRuntimeProbe(&config.ModelConfig{
|
||||
Model: "lmstudio/openai/gpt-oss-20b",
|
||||
APIBase: "https://api.example.com/v1",
|
||||
}) {
|
||||
t.Fatal("requiresRuntimeProbe(lmstudio with remote base) = true, want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestModelProbeAPIBase_LMStudioDefault(t *testing.T) {
|
||||
got := modelProbeAPIBase(&config.ModelConfig{Model: "lmstudio/openai/gpt-oss-20b"})
|
||||
if got != "http://localhost:1234/v1" {
|
||||
t.Fatalf("modelProbeAPIBase(lmstudio) = %q, want %q", got, "http://localhost:1234/v1")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProbeLocalModelAvailability_LMStudioUsesOpenAICompatibleProbe(t *testing.T) {
|
||||
originalProbe := probeOpenAICompatibleModelFunc
|
||||
defer func() { probeOpenAICompatibleModelFunc = originalProbe }()
|
||||
|
||||
called := false
|
||||
probeOpenAICompatibleModelFunc = func(apiBase, modelID, apiKey string) bool {
|
||||
called = true
|
||||
if apiBase != "http://localhost:1234/v1" {
|
||||
t.Fatalf("apiBase = %q, want %q", apiBase, "http://localhost:1234/v1")
|
||||
}
|
||||
if modelID != "openai/gpt-oss-20b" {
|
||||
t.Fatalf("modelID = %q, want %q", modelID, "openai/gpt-oss-20b")
|
||||
}
|
||||
if apiKey != "" {
|
||||
t.Fatalf("apiKey = %q, want empty", apiKey)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
model := &config.ModelConfig{Model: "lmstudio/openai/gpt-oss-20b"}
|
||||
if !probeLocalModelAvailability(model) {
|
||||
t.Fatal("probeLocalModelAvailability(lmstudio) = false, want true")
|
||||
}
|
||||
if !called {
|
||||
t.Fatal("probeOpenAICompatibleModelFunc was not called for lmstudio")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user