diff --git a/README.md b/README.md index 84fc86ba..18f3568b 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,7 @@ export ANTHROPIC_API_KEY=... export GEMINI_API_KEY=... export AIMLAPI_API_KEY=... export LONGCAT_API_KEY=... +export FIREWORKS_API_KEY=... export MINIMAX_API_KEY=... export MINIMAXI_API_KEY=... ``` @@ -147,6 +148,12 @@ To configure Meituan LongCat (LongCat-2.0) directly, run: zero providers setup longcat --set-active ``` +To configure Fireworks AI directly, run: + +```bash +zero providers setup fireworks --set-active +``` + MiniMax presets use the Anthropic-compatible endpoints for the global and China regions: diff --git a/internal/cli/provider_catalog_onboarding_test.go b/internal/cli/provider_catalog_onboarding_test.go index c9da4219..7891aba6 100644 --- a/internal/cli/provider_catalog_onboarding_test.go +++ b/internal/cli/provider_catalog_onboarding_test.go @@ -19,6 +19,7 @@ func TestProviderCatalogRuntimeProvidersShowOnboardingSetupHints(t *testing.T) { {id: "openai", name: "OpenAI", transport: "openai", defaultModel: "gpt-4.1"}, {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: "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 9108b857..edee8cf0 100644 --- a/internal/providercatalog/catalog.go +++ b/internal/providercatalog/catalog.go @@ -138,6 +138,7 @@ var descriptors = []Descriptor{ openAICompat("groq", "Groq", "https://api.groq.com/openai/v1", "llama-3.3-70b-versatile", []string{"GROQ_API_KEY"}), openAICompat("deepseek", "DeepSeek", "https://api.deepseek.com/v1", "deepseek-chat", []string{"DEEPSEEK_API_KEY"}), openAICompat("together", "Together AI", "https://api.together.xyz/v1", "meta-llama/Llama-3.3-70B-Instruct-Turbo", []string{"TOGETHER_API_KEY"}), + openAICompat("fireworks", "Fireworks AI", "https://api.fireworks.ai/inference/v1", "accounts/fireworks/models/kimi-k2p7-code", []string{"FIREWORKS_API_KEY"}, "fireworks-ai"), 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"), diff --git a/internal/providercatalog/catalog_test.go b/internal/providercatalog/catalog_test.go index 8fd245ea..7467bfe7 100644 --- a/internal/providercatalog/catalog_test.go +++ b/internal/providercatalog/catalog_test.go @@ -22,6 +22,7 @@ var expectedCatalogIDs = []string{ "groq", "deepseek", "together", + "fireworks", "dashscope", "moonshot", "atlascloud", @@ -155,6 +156,28 @@ func TestLongCatDescriptor(t *testing.T) { } } +func TestFireworksDescriptor(t *testing.T) { + descriptor, err := Require("fireworks") + if err != nil { + t.Fatalf("Require(fireworks) error = %v", err) + } + if descriptor.Name != "Fireworks AI" { + t.Fatalf("Name = %q, want Fireworks AI", descriptor.Name) + } + if descriptor.DefaultBaseURL != "https://api.fireworks.ai/inference/v1" { + t.Fatalf("DefaultBaseURL = %q, want Fireworks OpenAI-compatible endpoint", descriptor.DefaultBaseURL) + } + if descriptor.DefaultModel != "accounts/fireworks/models/kimi-k2p7-code" { + t.Fatalf("DefaultModel = %q, want accounts/fireworks/models/kimi-k2p7-code", descriptor.DefaultModel) + } + if descriptor.Transport != TransportOpenAICompatible { + t.Fatalf("Transport = %q, want %q", descriptor.Transport, TransportOpenAICompatible) + } + if !reflect.DeepEqual(descriptor.AuthEnvVars, []string{"FIREWORKS_API_KEY"}) { + t.Fatalf("AuthEnvVars = %#v, want FIREWORKS_API_KEY", descriptor.AuthEnvVars) + } +} + func TestAtlasCloudDescriptor(t *testing.T) { descriptor, err := Require("atlascloud") if err != nil { @@ -346,7 +369,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", "openrouter", "huggingface", "chatgpt", "groq", "deepseek", "together", "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", "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"}, } for transport, wantIDs := range cases { diff --git a/internal/providermodelcatalog/catalog.go b/internal/providermodelcatalog/catalog.go index 73dcbb7e..8b945762 100644 --- a/internal/providermodelcatalog/catalog.go +++ b/internal/providermodelcatalog/catalog.go @@ -122,6 +122,14 @@ var curatedModels = map[string][]Model{ {ID: "deepseek-ai/DeepSeek-R1", Description: "reasoning model"}, {ID: "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", Description: "multimodal model"}, }, + "fireworks": { + // Serverless-only curated set: ordinary API-key setups hit /inference/v1 + // and cannot use on-demand deployment IDs. + {ID: "accounts/fireworks/models/kimi-k2p7-code", Description: "catalog default"}, + {ID: "accounts/fireworks/models/deepseek-v4-flash", Description: "fast coding model"}, + {ID: "accounts/fireworks/models/gpt-oss-120b", Description: "general model"}, + {ID: "accounts/fireworks/models/deepseek-v4-pro", Description: "reasoning model"}, + }, "dashscope": { {ID: "qwen-plus", Description: "catalog default"}, {ID: "qwen-max", Description: "strong general model"}, diff --git a/internal/providermodelcatalog/catalog_test.go b/internal/providermodelcatalog/catalog_test.go index 6489e763..ae597039 100644 --- a/internal/providermodelcatalog/catalog_test.go +++ b/internal/providermodelcatalog/catalog_test.go @@ -28,6 +28,11 @@ func TestModelsAreProviderScoped(t *testing.T) { want: []string{"llama-3.3-70b-versatile", "openai/gpt-oss-120b"}, notWant: []string{"gpt-4.1", "claude-sonnet-4.5"}, }, + { + provider: "fireworks", + want: []string{"accounts/fireworks/models/kimi-k2p7-code", "accounts/fireworks/models/deepseek-v4-flash"}, + notWant: []string{"gpt-4.1", "llama-3.3-70b-versatile"}, + }, { provider: "chatgpt", want: []string{"gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark"}, diff --git a/internal/providermodelcatalog/remote.go b/internal/providermodelcatalog/remote.go index 994bcc00..5d884105 100644 --- a/internal/providermodelcatalog/remote.go +++ b/internal/providermodelcatalog/remote.go @@ -132,6 +132,8 @@ func ModelsDevProviderID(provider providercatalog.Descriptor) string { return "zai" case "minimaxi-cn": return "minimax" + case "fireworks": + return "fireworks-ai" default: return strings.TrimSpace(provider.ID) } diff --git a/internal/providermodelcatalog/remote_test.go b/internal/providermodelcatalog/remote_test.go index 4e3d5da0..d7e83bf4 100644 --- a/internal/providermodelcatalog/remote_test.go +++ b/internal/providermodelcatalog/remote_test.go @@ -131,6 +131,7 @@ func TestModelsDevProviderIDMapsZeroAliases(t *testing.T) { "ollama-cloud": "ollama-cloud", "zai-cn": "zai", "minimaxi-cn": "minimax", + "fireworks": "fireworks-ai", } for zeroID, want := range tests { provider, ok := providercatalog.Get(zeroID)