Add ovms support
This commit is contained in:
parent
5e44a99410
commit
793357c61e
10 changed files with 37 additions and 10 deletions
|
|
@ -25,10 +25,11 @@ Examples:
|
||||||
picoclaw model # Show current default model
|
picoclaw model # Show current default model
|
||||||
picoclaw model gpt-5.2 # Set gpt-5.2 as default
|
picoclaw model gpt-5.2 # Set gpt-5.2 as default
|
||||||
picoclaw model claude-sonnet-4.6 # Set claude-sonnet-4.6 as default
|
picoclaw model claude-sonnet-4.6 # Set claude-sonnet-4.6 as default
|
||||||
picoclaw model local-model # Set local VLLM server as default
|
picoclaw model local-model # Set local VLLM/OVMS server as default
|
||||||
|
|
||||||
Note: 'local-model' is a special value for using a local VLLM server
|
Note: 'local-model' is a special value for using a local VLLM server
|
||||||
(running at localhost:8000 by default) which does not require an API key.`,
|
(running at localhost:8000 by default) which does not require an API key.
|
||||||
|
You can also use OVMS (OpenVINO Model Server) or other OpenAI-compatible servers.`,
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
configPath := internal.GetConfigPath()
|
configPath := internal.GetConfigPath()
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ func supportsAudioTranscription(model string) bool {
|
||||||
case "openai", "azure", "azure-openai",
|
case "openai", "azure", "azure-openai",
|
||||||
"litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
|
"litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
|
||||||
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
|
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
|
||||||
"vivgrid", "volcengine", "vllm", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
|
"vivgrid", "volcengine", "vllm", "ovms", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
|
||||||
"qwen-us", "dashscope-us", "mistral", "avian", "minimax", "longcat", "modelscope", "novita",
|
"qwen-us", "dashscope-us", "mistral", "avian", "minimax", "longcat", "modelscope", "novita",
|
||||||
"coding-plan", "alibaba-coding", "qwen-coding":
|
"coding-plan", "alibaba-coding", "qwen-coding":
|
||||||
// These protocols all go through the OpenAI-compatible or Azure provider path in
|
// These protocols all go through the OpenAI-compatible or Azure provider path in
|
||||||
|
|
@ -47,7 +47,7 @@ func supportsWhisperTranscription(model string) bool {
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case "openai", "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
|
case "openai", "litellm", "openrouter", "groq", "zhipu", "gemini", "nvidia",
|
||||||
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
|
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
|
||||||
"vivgrid", "volcengine", "vllm", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
|
"vivgrid", "volcengine", "vllm", "ovms", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
|
||||||
"qwen-us", "dashscope-us", "mistral", "avian", "minimax", "longcat", "modelscope", "novita",
|
"qwen-us", "dashscope-us", "mistral", "avian", "minimax", "longcat", "modelscope", "novita",
|
||||||
"coding-plan", "alibaba-coding", "qwen-coding", "mimo":
|
"coding-plan", "alibaba-coding", "qwen-coding", "mimo":
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -347,6 +347,13 @@ func DefaultConfig() *Config {
|
||||||
APIBase: "http://localhost:8000/v1",
|
APIBase: "http://localhost:8000/v1",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// OVMS (local) - http://localhost:8000
|
||||||
|
{
|
||||||
|
ModelName: "local-ovms",
|
||||||
|
Model: "ovms/custom-model",
|
||||||
|
APIBase: "http://localhost:8000/v3",
|
||||||
|
},
|
||||||
|
|
||||||
// LM Studio (local) - http://localhost:1234
|
// LM Studio (local) - http://localhost:1234
|
||||||
{
|
{
|
||||||
ModelName: "lmstudio-local",
|
ModelName: "lmstudio-local",
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ var protocolMetaByName = map[string]protocolMeta{
|
||||||
"coding-plan-anthropic": {defaultAPIBase: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic"},
|
"coding-plan-anthropic": {defaultAPIBase: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic"},
|
||||||
"alibaba-coding-anthropic": {defaultAPIBase: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic"},
|
"alibaba-coding-anthropic": {defaultAPIBase: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic"},
|
||||||
"vllm": {defaultAPIBase: "http://localhost:8000/v1", emptyAPIKeyAllowed: true},
|
"vllm": {defaultAPIBase: "http://localhost:8000/v1", emptyAPIKeyAllowed: true},
|
||||||
|
"ovms": {defaultAPIBase: "http://localhost:8000/v3", emptyAPIKeyAllowed: true},
|
||||||
"mistral": {defaultAPIBase: "https://api.mistral.ai/v1"},
|
"mistral": {defaultAPIBase: "https://api.mistral.ai/v1"},
|
||||||
"avian": {defaultAPIBase: "https://api.avian.io/v1"},
|
"avian": {defaultAPIBase: "https://api.avian.io/v1"},
|
||||||
"minimax": {defaultAPIBase: "https://api.minimaxi.com/v1"},
|
"minimax": {defaultAPIBase: "https://api.minimaxi.com/v1"},
|
||||||
|
|
@ -220,7 +221,7 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
||||||
|
|
||||||
case "litellm", "lmstudio", "openrouter", "groq", "zhipu", "gemini", "nvidia", "venice",
|
case "litellm", "lmstudio", "openrouter", "groq", "zhipu", "gemini", "nvidia", "venice",
|
||||||
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
|
"ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras",
|
||||||
"vivgrid", "volcengine", "vllm", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
|
"vivgrid", "volcengine", "vllm", "ovms", "qwen", "qwen-intl", "qwen-international", "dashscope-intl",
|
||||||
"qwen-us", "dashscope-us", "mistral", "avian", "longcat", "modelscope", "novita",
|
"qwen-us", "dashscope-us", "mistral", "avian", "longcat", "modelscope", "novita",
|
||||||
"coding-plan", "alibaba-coding", "qwen-coding", "mimo":
|
"coding-plan", "alibaba-coding", "qwen-coding", "mimo":
|
||||||
// All other OpenAI-compatible HTTP providers
|
// All other OpenAI-compatible HTTP providers
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ func TestCreateProviderFromConfig_DefaultAPIBase(t *testing.T) {
|
||||||
{"vivgrid", "vivgrid"},
|
{"vivgrid", "vivgrid"},
|
||||||
{"qwen", "qwen"},
|
{"qwen", "qwen"},
|
||||||
{"vllm", "vllm"},
|
{"vllm", "vllm"},
|
||||||
|
{"ovms", "ovms"},
|
||||||
{"deepseek", "deepseek"},
|
{"deepseek", "deepseek"},
|
||||||
{"ollama", "ollama"},
|
{"ollama", "ollama"},
|
||||||
{"lmstudio", "lmstudio"},
|
{"lmstudio", "lmstudio"},
|
||||||
|
|
@ -237,6 +238,20 @@ func TestCreateProviderFromConfig_LocalProviders(t *testing.T) {
|
||||||
apiKey: "",
|
apiKey: "",
|
||||||
wantModelID: "Qwen/Qwen3-8B",
|
wantModelID: "Qwen/Qwen3-8B",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "OVMS with API key",
|
||||||
|
modelName: "test-ovms",
|
||||||
|
model: "ovms/llama3",
|
||||||
|
apiKey: "test-key",
|
||||||
|
wantModelID: "llama3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OVMS without API key",
|
||||||
|
modelName: "test-ovms",
|
||||||
|
model: "ovms/llama3",
|
||||||
|
apiKey: "",
|
||||||
|
wantModelID: "llama3",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
|
||||||
|
|
@ -357,7 +357,7 @@ Check these in the dashboard:
|
||||||
|
|
||||||
- a default model is selected
|
- a default model is selected
|
||||||
- the model has credentials or OAuth state
|
- the model has credentials or OAuth state
|
||||||
- local models such as Ollama or vLLM are reachable
|
- local models such as Ollama, vLLM, or OVMS are reachable
|
||||||
|
|
||||||
### The launcher cannot find `picoclaw`
|
### The launcher cannot find `picoclaw`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ func runLocalModelProbe(m *config.ModelConfig) bool {
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case "ollama":
|
case "ollama":
|
||||||
return probeOllamaModelFunc(apiBase, modelID)
|
return probeOllamaModelFunc(apiBase, modelID)
|
||||||
case "vllm", "lmstudio":
|
case "vllm", "ovms", "lmstudio":
|
||||||
return probeOpenAICompatibleModelFunc(apiBase, modelID, m.APIKey())
|
return probeOpenAICompatibleModelFunc(apiBase, modelID, m.APIKey())
|
||||||
case "github-copilot", "copilot":
|
case "github-copilot", "copilot":
|
||||||
return probeTCPServiceFunc(apiBase)
|
return probeTCPServiceFunc(apiBase)
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,10 @@ const PROVIDER_PRIORITY: Record<string, number> = {
|
||||||
shengsuanyun: 14,
|
shengsuanyun: 14,
|
||||||
ollama: 15,
|
ollama: 15,
|
||||||
vllm: 16,
|
vllm: 16,
|
||||||
mistral: 17,
|
ovms: 17,
|
||||||
avian: 18,
|
mistral: 18,
|
||||||
mimo: 19,
|
avian: 19,
|
||||||
|
mimo: 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProviderGroup {
|
interface ProviderGroup {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ const PROVIDER_DOMAINS: Record<string, string> = {
|
||||||
mistral: "mistral.ai",
|
mistral: "mistral.ai",
|
||||||
avian: "avian.io",
|
avian: "avian.io",
|
||||||
vllm: "vllm.ai",
|
vllm: "vllm.ai",
|
||||||
|
ovms: "docs.openvino.ai",
|
||||||
zhipu: "zhipuai.cn",
|
zhipu: "zhipuai.cn",
|
||||||
mimo: "xiaomi.com",
|
mimo: "xiaomi.com",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ const PROVIDER_LABELS: Record<string, string> = {
|
||||||
mistral: "Mistral AI",
|
mistral: "Mistral AI",
|
||||||
avian: "Avian",
|
avian: "Avian",
|
||||||
vllm: "VLLM (local)",
|
vllm: "VLLM (local)",
|
||||||
|
ovms: "OVMS (local)",
|
||||||
zhipu: "Zhipu AI (智谱)",
|
zhipu: "Zhipu AI (智谱)",
|
||||||
mimo: "Xiaomi MiMo",
|
mimo: "Xiaomi MiMo",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue