diff --git a/README.md b/README.md index 562a6b3bf..45d94976a 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,19 @@ zero exec --output-format stream-json < turns.jsonl Concentrate Exa + + + + + + GMI Cloud logo + + + + + + GMI Cloud + ## Why Zero @@ -190,6 +203,7 @@ export GEMINI_API_KEY=... export AIMLAPI_API_KEY=... export LONGCAT_API_KEY=... export FIREWORKS_API_KEY=... +export GMI_API_KEY=... export MINIMAX_API_KEY=... export MINIMAXI_API_KEY=... ``` @@ -212,6 +226,12 @@ To configure Fireworks AI directly, run: zero providers setup fireworks --set-active ``` +To configure GMI Cloud directly, run: + +```bash +zero providers setup gmicloud --set-active +``` + MiniMax presets use the Anthropic-compatible endpoints for the global and China regions: diff --git a/README_ZH.md b/README_ZH.md index fd87d1696..822d61968 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -76,6 +76,19 @@ zero exec --output-format stream-json < turns.jsonl Concentrate Exa + + + + + + GMI Cloud logo + + + + + + GMI Cloud + ## 为什么选择 Zero @@ -163,6 +176,7 @@ export OPENAI_API_KEY=sk-... export ANTHROPIC_API_KEY=... export GEMINI_API_KEY=... export LONGCAT_API_KEY=... +export GMI_API_KEY=... ``` 要直接配置美团 LongCat(LongCat-2.0),运行: @@ -171,6 +185,12 @@ export LONGCAT_API_KEY=... zero providers setup longcat --set-active ``` +要直接配置 GMI Cloud,运行: + +```bash +zero providers setup gmicloud --set-active +``` + 对于本地模型,运行 Ollama、LM Studio 或 [Atomic Chat](https://atomic.chat) 桌面应用, 然后使用 `zero setup` 或 `zero providers detect`。使用 Atomic Chat 时,请先加载模型并启用 本地 OpenAI 兼容 API(默认地址为 `http://127.0.0.1:1337/v1`),再选择 `atomic-chat-local`。 diff --git a/docs/assets/gmi-cloud-logo-dark.svg b/docs/assets/gmi-cloud-logo-dark.svg new file mode 100644 index 000000000..a0562b356 --- /dev/null +++ b/docs/assets/gmi-cloud-logo-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/assets/gmi-cloud-logo.svg b/docs/assets/gmi-cloud-logo.svg new file mode 100644 index 000000000..4e928e6f4 --- /dev/null +++ b/docs/assets/gmi-cloud-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/internal/cli/provider_catalog_onboarding_test.go b/internal/cli/provider_catalog_onboarding_test.go index 7891aba60..4bd2e9d88 100644 --- a/internal/cli/provider_catalog_onboarding_test.go +++ b/internal/cli/provider_catalog_onboarding_test.go @@ -20,6 +20,7 @@ func TestProviderCatalogRuntimeProvidersShowOnboardingSetupHints(t *testing.T) { {id: "groq", name: "Groq", transport: "openai-compatible", defaultModel: "llama-3.3-70b-versatile"}, {id: "longcat", name: "LongCat", transport: "openai-compatible", defaultModel: "LongCat-2.0"}, {id: "fireworks", name: "Fireworks AI", transport: "openai-compatible", defaultModel: "accounts/fireworks/models/kimi-k2p7-code"}, + {id: "gmicloud", name: "GMI Cloud", transport: "openai-compatible", defaultModel: "Qwen/Qwen3.8-Max"}, {id: "ollama-cloud", name: "Ollama Cloud", transport: "openai-compatible", defaultModel: "qwen3-coder:480b"}, {id: "ollama", name: "Ollama Local", transport: "openai-compatible", defaultModel: "llama3.1"}, } diff --git a/internal/providercatalog/catalog.go b/internal/providercatalog/catalog.go index 46ac4b828..e5f916eb6 100644 --- a/internal/providercatalog/catalog.go +++ b/internal/providercatalog/catalog.go @@ -143,6 +143,10 @@ var descriptors = []Descriptor{ openAICompat("dashscope", "DashScope", "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", "qwen-plus", []string{"DASHSCOPE_API_KEY", "QWEN_API_KEY"}, "qwen"), openAICompat("moonshot", "Moonshot AI", "https://api.moonshot.ai/v1", "kimi-k2-0905-preview", []string{"MOONSHOT_API_KEY"}, "kimi"), openAICompat("atlascloud", "Atlas Cloud", "https://api.atlascloud.ai/v1", "qwen/qwen3.5-flash", []string{"ATLASCLOUD_API_KEY"}, "atlas cloud", "atlas"), + // GMI Cloud — OpenAI-compatible inference. The id matches the models.dev + // provider id so the remote catalog resolves without a mapping; GMI's own + // docs name the key GMI_API_KEY, models.dev names it GMICLOUD_API_KEY. + openAICompat("gmicloud", "GMI Cloud", "https://api.gmi-serving.com/v1", "Qwen/Qwen3.8-Max", []string{"GMI_API_KEY", "GMICLOUD_API_KEY"}, "gmi cloud", "gmi"), openAICompat("longcat", "LongCat", "https://api.longcat.chat/openai", "LongCat-2.0", []string{"LONGCAT_API_KEY"}, "meituan longcat", "meituan", "longcat-2.0"), openAICompat("nvidia-nim", "NVIDIA NIM", "https://integrate.api.nvidia.com/v1", "nvidia/llama-3.1-nemotron-70b-instruct", []string{"NVIDIA_API_KEY"}, "nvidia nim"), anthropicCompat("minimax", "MiniMax", "https://api.minimax.io/anthropic", "MiniMax-M3", []string{"MINIMAX_API_KEY"}, "mini-max", "mini_max"), diff --git a/internal/providercatalog/catalog_test.go b/internal/providercatalog/catalog_test.go index 43d8d4fdf..0a3b6f2ae 100644 --- a/internal/providercatalog/catalog_test.go +++ b/internal/providercatalog/catalog_test.go @@ -27,6 +27,7 @@ var expectedCatalogIDs = []string{ "dashscope", "moonshot", "atlascloud", + "gmicloud", "longcat", "nvidia-nim", "minimax", @@ -201,6 +202,31 @@ func TestAtlasCloudDescriptor(t *testing.T) { } } +func TestGMICloudDescriptor(t *testing.T) { + descriptor, err := Require("gmicloud") + if err != nil { + t.Fatalf("Require(gmicloud) error = %v", err) + } + if descriptor.Name != "GMI Cloud" { + t.Fatalf("Name = %q, want GMI Cloud", descriptor.Name) + } + if descriptor.DefaultBaseURL != "https://api.gmi-serving.com/v1" { + t.Fatalf("DefaultBaseURL = %q, want GMI Cloud OpenAI-compatible endpoint", descriptor.DefaultBaseURL) + } + if descriptor.DefaultModel != "Qwen/Qwen3.8-Max" { + t.Fatalf("DefaultModel = %q, want Qwen/Qwen3.8-Max", descriptor.DefaultModel) + } + if descriptor.Transport != TransportOpenAICompatible { + t.Fatalf("Transport = %q, want %q", descriptor.Transport, TransportOpenAICompatible) + } + if !descriptor.RequiresAuth { + t.Fatal("RequiresAuth = false, want true") + } + if !reflect.DeepEqual(descriptor.AuthEnvVars, []string{"GMI_API_KEY", "GMICLOUD_API_KEY"}) { + t.Fatalf("AuthEnvVars = %#v, want GMI_API_KEY then GMICLOUD_API_KEY", descriptor.AuthEnvVars) + } +} + func TestCatalogDescriptorsExposeRequiredDefaults(t *testing.T) { for _, descriptor := range All() { if descriptor.ID == "" { @@ -321,6 +347,9 @@ func TestLookupNormalizesIDsAndAliases(t *testing.T) { "mini_max": "minimax", "Moonshot": "moonshot", "Atlas Cloud": "atlascloud", + "GMI Cloud": "gmicloud", + "gmi-cloud": "gmicloud", + "gmi": "gmicloud", "nvidia nim": "nvidia-nim", "xiaomi mimo": "xiaomi-mimo", "custom_openai_compatible": "custom-openai-compatible", @@ -371,7 +400,7 @@ func TestListByTransportPreservesCatalogOrder(t *testing.T) { TransportBedrock: {"bedrock"}, TransportVertex: {"vertex"}, TransportAnthropicCompat: {"minimax", "minimaxi-cn", "opencode-go-anthropic-compatible", "custom-anthropic-compatible"}, - TransportOpenAICompat: {"gitlawb-opengateway", "aimlapi", "ollama-cloud", "ollama", "lmstudio", "atomic-chat-local", "openrouter", "huggingface", "chatgpt", "groq", "deepseek", "together", "fireworks", "dashscope", "moonshot", "atlascloud", "longcat", "nvidia-nim", "mistral", "github", "xai", "venice", "xiaomi-mimo", "bankr", "zai", "zai-cn", "kilocode", "opencode", "opencode-go", "atomic-chat", "chatgpt-proxy", "custom-openai-compatible"}, + TransportOpenAICompat: {"gitlawb-opengateway", "aimlapi", "ollama-cloud", "ollama", "lmstudio", "atomic-chat-local", "openrouter", "huggingface", "chatgpt", "groq", "deepseek", "together", "fireworks", "dashscope", "moonshot", "atlascloud", "gmicloud", "longcat", "nvidia-nim", "mistral", "github", "xai", "venice", "xiaomi-mimo", "bankr", "zai", "zai-cn", "kilocode", "opencode", "opencode-go", "atomic-chat", "chatgpt-proxy", "custom-openai-compatible"}, } for transport, wantIDs := range cases { diff --git a/internal/providermodelcatalog/catalog.go b/internal/providermodelcatalog/catalog.go index cf0e6bf7e..953619418 100644 --- a/internal/providermodelcatalog/catalog.go +++ b/internal/providermodelcatalog/catalog.go @@ -149,6 +149,12 @@ var curatedModels = map[string][]Model{ {ID: "qwen/qwen3.5-flash", Description: "catalog default"}, {ID: "deepseek-ai/deepseek-v4-pro", Description: "reasoning model"}, }, + "gmicloud": { + {ID: "Qwen/Qwen3.8-Max", Description: "catalog default"}, + {ID: "Qwen/Qwen3.8-Flash", Description: "fast model"}, + {ID: "deepseek-ai/DeepSeek-V4-Pro", Description: "reasoning model"}, + {ID: "deepseek-ai/DeepSeek-V4-Flash", Description: "fast coding model"}, + }, "nvidia-nim": { {ID: "nvidia/llama-3.1-nemotron-70b-instruct", Description: "catalog default"}, {ID: "meta/llama-3.1-70b-instruct", Description: "general model"}, diff --git a/internal/providermodelcatalog/catalog_test.go b/internal/providermodelcatalog/catalog_test.go index 640b7a35a..736a9b60f 100644 --- a/internal/providermodelcatalog/catalog_test.go +++ b/internal/providermodelcatalog/catalog_test.go @@ -48,6 +48,11 @@ func TestModelsAreProviderScoped(t *testing.T) { want: []string{"qwen/qwen3.5-flash", "deepseek-ai/deepseek-v4-pro"}, notWant: []string{"gpt-4.1", "claude-sonnet-4.5", "openai/gpt-4.1"}, }, + { + provider: "gmicloud", + want: []string{"Qwen/Qwen3.8-Max", "Qwen/Qwen3.8-Flash", "deepseek-ai/DeepSeek-V4-Pro", "deepseek-ai/DeepSeek-V4-Flash"}, + notWant: []string{"gpt-4.1", "claude-sonnet-4.5", "deepseek-ai/deepseek-v4-pro"}, + }, { provider: "mistral", want: []string{"mistral-large-latest", "codestral-latest"},