Add Gondola provider
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- commit
- d761259be71933bff8508782b885c1727b53562a
- author
- Codonyat · · 2026-08-11 12:52 UTC
- parent
- 9fa3d04
- signature
- unsigned
8 files · +39 -2
M docs/providers.md +1 -0
| @@ -112,6 +112,7 @@ show instructions and should be configured with environment variables. | |||
| 112 | 112 | | Together AI | `TOGETHER_API_KEY` | `together` | | |
| 113 | 113 | | Hugging Face | `HF_TOKEN` | `huggingface` | | |
| 114 | 114 | | OpenRouter | `OPENROUTER_API_KEY` | `openrouter` | | |
| 115 | + | | Gondola | `GONDOLA_API_KEY` | `gondola` | | |
| 115 | 116 | | Mistral | `MISTRAL_API_KEY` | `mistral` | | |
| 116 | 117 | | ZAI | `ZAI_API_KEY` | `zai` | | |
| 117 | 118 | | Xiaomi MiMo | `XIAOMI_API_KEY` | `xiaomi` | | |
| @@ -112,6 +112,7 @@ show instructions and should be configured with environment variables. | |||||
| 112 | | Together AI | `TOGETHER_API_KEY` | `together` | | 112 | | Together AI | `TOGETHER_API_KEY` | `together` | | ||
| 113 | | Hugging Face | `HF_TOKEN` | `huggingface` | | 113 | | Hugging Face | `HF_TOKEN` | `huggingface` | | ||
| 114 | | OpenRouter | `OPENROUTER_API_KEY` | `openrouter` | | 114 | | OpenRouter | `OPENROUTER_API_KEY` | `openrouter` | | ||
| 115 | + | | Gondola | `GONDOLA_API_KEY` | `gondola` | | |||
| 115 | | Mistral | `MISTRAL_API_KEY` | `mistral` | | 116 | | Mistral | `MISTRAL_API_KEY` | `mistral` | | ||
| 116 | | ZAI | `ZAI_API_KEY` | `zai` | | 117 | | ZAI | `ZAI_API_KEY` | `zai` | | ||
| 117 | | Xiaomi MiMo | `XIAOMI_API_KEY` | `xiaomi` | | 118 | | Xiaomi MiMo | `XIAOMI_API_KEY` | `xiaomi` | | ||
M packages/agent/build.go +7 -1
| @@ -183,6 +183,8 @@ func defaultModelForProvider(prov string) string { | |||
| 183 | 183 | return "moonshotai/Kimi-K2-Instruct" | |
| 184 | 184 | case "openrouter": | |
| 185 | 185 | return "anthropic/claude-sonnet-4.5" | |
| 186 | + | case "gondola": | |
| 187 | + | return "claude-opus-5" | |
| 186 | 188 | case "mistral": | |
| 187 | 189 | return "mistral-large-latest" | |
| 188 | 190 | case "zai": | |
| @@ -224,7 +226,7 @@ func defaultModelForProvider(prov string) string { | |||
| 224 | 226 | var knownProviders = []string{ | |
| 225 | 227 | "anthropic", "openai", "openai-codex", "openai-responses", "kimi", "deepseek", "google", "ollama", provider.LlamaCPPProviderID, | |
| 226 | 228 | "moonshotai", "moonshotai-cn", | |
| 227 | - | "cerebras", "groq", "xai", "together", "huggingface", "openrouter", | |
| 229 | + | "cerebras", "groq", "xai", "together", "huggingface", "openrouter", "gondola", | |
| 228 | 230 | "mistral", "zai", | |
| 229 | 231 | "xiaomi", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "xiaomi-token-plan-sgp", | |
| 230 | 232 | "minimax", "minimax-cn", | |
| @@ -831,6 +833,8 @@ func (r Resolved) NewClient() provider.Client { | |||
| 831 | 833 | return wrap(provider.NewHuggingFace(r.Credential, r.BaseURL)) | |
| 832 | 834 | case "openrouter": | |
| 833 | 835 | return wrap(provider.NewOpenRouter(r.Credential, r.BaseURL)) | |
| 836 | + | case "gondola": | |
| 837 | + | return wrap(provider.NewGondola(r.Credential, r.BaseURL)) | |
| 834 | 838 | case "zai": | |
| 835 | 839 | return wrap(provider.NewZAI(r.Credential, r.BaseURL)) | |
| 836 | 840 | case "xiaomi": | |
| @@ -1073,6 +1077,8 @@ func envVarName(provider string) string { | |||
| 1073 | 1077 | return "HF" | |
| 1074 | 1078 | case "openrouter": | |
| 1075 | 1079 | return "OPENROUTER" | |
| 1080 | + | case "gondola": | |
| 1081 | + | return "GONDOLA" | |
| 1076 | 1082 | case "mistral": | |
| 1077 | 1083 | return "MISTRAL" | |
| 1078 | 1084 | case "zai": | |
| @@ -183,6 +183,8 @@ func defaultModelForProvider(prov string) string { | |||||
| 183 | return "moonshotai/Kimi-K2-Instruct" | 183 | return "moonshotai/Kimi-K2-Instruct" | ||
| 184 | case "openrouter": | 184 | case "openrouter": | ||
| 185 | return "anthropic/claude-sonnet-4.5" | 185 | return "anthropic/claude-sonnet-4.5" | ||
| 186 | + | case "gondola": | |||
| 187 | + | return "claude-opus-5" | |||
| 186 | case "mistral": | 188 | case "mistral": | ||
| 187 | return "mistral-large-latest" | 189 | return "mistral-large-latest" | ||
| 188 | case "zai": | 190 | case "zai": | ||
| @@ -224,7 +226,7 @@ func defaultModelForProvider(prov string) string { | |||||
| 224 | var knownProviders = []string{ | 226 | var knownProviders = []string{ | ||
| 225 | "anthropic", "openai", "openai-codex", "openai-responses", "kimi", "deepseek", "google", "ollama", provider.LlamaCPPProviderID, | 227 | "anthropic", "openai", "openai-codex", "openai-responses", "kimi", "deepseek", "google", "ollama", provider.LlamaCPPProviderID, | ||
| 226 | "moonshotai", "moonshotai-cn", | 228 | "moonshotai", "moonshotai-cn", | ||
| 227 | - | "cerebras", "groq", "xai", "together", "huggingface", "openrouter", | 229 | + | "cerebras", "groq", "xai", "together", "huggingface", "openrouter", "gondola", |
| 228 | "mistral", "zai", | 230 | "mistral", "zai", | ||
| 229 | "xiaomi", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "xiaomi-token-plan-sgp", | 231 | "xiaomi", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "xiaomi-token-plan-sgp", | ||
| 230 | "minimax", "minimax-cn", | 232 | "minimax", "minimax-cn", | ||
| @@ -831,6 +833,8 @@ func (r Resolved) NewClient() provider.Client { | |||||
| 831 | return wrap(provider.NewHuggingFace(r.Credential, r.BaseURL)) | 833 | return wrap(provider.NewHuggingFace(r.Credential, r.BaseURL)) | ||
| 832 | case "openrouter": | 834 | case "openrouter": | ||
| 833 | return wrap(provider.NewOpenRouter(r.Credential, r.BaseURL)) | 835 | return wrap(provider.NewOpenRouter(r.Credential, r.BaseURL)) | ||
| 836 | + | case "gondola": | |||
| 837 | + | return wrap(provider.NewGondola(r.Credential, r.BaseURL)) | |||
| 834 | case "zai": | 838 | case "zai": | ||
| 835 | return wrap(provider.NewZAI(r.Credential, r.BaseURL)) | 839 | return wrap(provider.NewZAI(r.Credential, r.BaseURL)) | ||
| 836 | case "xiaomi": | 840 | case "xiaomi": | ||
| @@ -1073,6 +1077,8 @@ func envVarName(provider string) string { | |||||
| 1073 | return "HF" | 1077 | return "HF" | ||
| 1074 | case "openrouter": | 1078 | case "openrouter": | ||
| 1075 | return "OPENROUTER" | 1079 | return "OPENROUTER" | ||
| 1080 | + | case "gondola": | |||
| 1081 | + | return "GONDOLA" | |||
| 1076 | case "mistral": | 1082 | case "mistral": | ||
| 1077 | return "MISTRAL" | 1083 | return "MISTRAL" | ||
| 1078 | case "zai": | 1084 | case "zai": | ||
M packages/agent/config.go +4 -0
| @@ -415,6 +415,10 @@ func resolveCredentialFull(ctx context.Context, provider, explicit string, comma | |||
| 415 | 415 | if v := os.Getenv("OPENROUTER_API_KEY"); v != "" { | |
| 416 | 416 | return v, "apikey", "", nil | |
| 417 | 417 | } | |
| 418 | + | case "gondola": | |
| 419 | + | if v := os.Getenv("GONDOLA_API_KEY"); v != "" { | |
| 420 | + | return v, "apikey", "", nil | |
| 421 | + | } | |
| 418 | 422 | case "mistral": | |
| 419 | 423 | if v := os.Getenv("MISTRAL_API_KEY"); v != "" { | |
| 420 | 424 | return v, "apikey", "", nil | |
| @@ -415,6 +415,10 @@ func resolveCredentialFull(ctx context.Context, provider, explicit string, comma | |||||
| 415 | if v := os.Getenv("OPENROUTER_API_KEY"); v != "" { | 415 | if v := os.Getenv("OPENROUTER_API_KEY"); v != "" { | ||
| 416 | return v, "apikey", "", nil | 416 | return v, "apikey", "", nil | ||
| 417 | } | 417 | } | ||
| 418 | + | case "gondola": | |||
| 419 | + | if v := os.Getenv("GONDOLA_API_KEY"); v != "" { | |||
| 420 | + | return v, "apikey", "", nil | |||
| 421 | + | } | |||
| 418 | case "mistral": | 422 | case "mistral": | ||
| 419 | if v := os.Getenv("MISTRAL_API_KEY"); v != "" { | 423 | if v := os.Getenv("MISTRAL_API_KEY"); v != "" { | ||
| 420 | return v, "apikey", "", nil | 424 | return v, "apikey", "", nil | ||
M packages/provider/auth/probe.go +6 -0
| @@ -99,6 +99,12 @@ func ProbeAPIKey(ctx context.Context, provider, key string) error { | |||
| 99 | 99 | return err | |
| 100 | 100 | } | |
| 101 | 101 | req.Header.Set("authorization", "Bearer "+key) | |
| 102 | + | case "gondola": | |
| 103 | + | req, err = http.NewRequestWithContext(ctx, "GET", "https://api.gondola-ai.com/v1/models", nil) | |
| 104 | + | if err != nil { | |
| 105 | + | return err | |
| 106 | + | } | |
| 107 | + | req.Header.Set("authorization", "Bearer "+key) | |
| 102 | 108 | case "huggingface": | |
| 103 | 109 | req, err = http.NewRequestWithContext(ctx, "GET", "https://router.huggingface.co/v1/models", nil) | |
| 104 | 110 | if err != nil { | |
| @@ -99,6 +99,12 @@ func ProbeAPIKey(ctx context.Context, provider, key string) error { | |||||
| 99 | return err | 99 | return err | ||
| 100 | } | 100 | } | ||
| 101 | req.Header.Set("authorization", "Bearer "+key) | 101 | req.Header.Set("authorization", "Bearer "+key) | ||
| 102 | + | case "gondola": | |||
| 103 | + | req, err = http.NewRequestWithContext(ctx, "GET", "https://api.gondola-ai.com/v1/models", nil) | |||
| 104 | + | if err != nil { | |||
| 105 | + | return err | |||
| 106 | + | } | |||
| 107 | + | req.Header.Set("authorization", "Bearer "+key) | |||
| 102 | case "huggingface": | 108 | case "huggingface": | ||
| 103 | req, err = http.NewRequestWithContext(ctx, "GET", "https://router.huggingface.co/v1/models", nil) | 109 | req, err = http.NewRequestWithContext(ctx, "GET", "https://router.huggingface.co/v1/models", nil) | ||
| 104 | if err != nil { | 110 | if err != nil { | ||
M packages/provider/auth/server.go +1 -1
| @@ -138,7 +138,7 @@ func APIKeyProviders() []string { | |||
| 138 | 138 | return []string{ | |
| 139 | 139 | "anthropic", "openai", "kimi", "deepseek", "google", "llama.cpp", | |
| 140 | 140 | "moonshotai", "moonshotai-cn", "groq", "cerebras", "xai", "together", | |
| 141 | - | "huggingface", "openrouter", "mistral", "zai", | |
| 141 | + | "huggingface", "openrouter", "gondola", "mistral", "zai", | |
| 142 | 142 | "xiaomi", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "xiaomi-token-plan-sgp", | |
| 143 | 143 | "minimax", "minimax-cn", "fireworks", "vercel-ai-gateway", | |
| 144 | 144 | "opencode", "opencode-go", "amazon-bedrock", "google-vertex", "azure-openai-responses", | |
| @@ -138,7 +138,7 @@ func APIKeyProviders() []string { | |||||
| 138 | return []string{ | 138 | return []string{ | ||
| 139 | "anthropic", "openai", "kimi", "deepseek", "google", "llama.cpp", | 139 | "anthropic", "openai", "kimi", "deepseek", "google", "llama.cpp", | ||
| 140 | "moonshotai", "moonshotai-cn", "groq", "cerebras", "xai", "together", | 140 | "moonshotai", "moonshotai-cn", "groq", "cerebras", "xai", "together", | ||
| 141 | - | "huggingface", "openrouter", "mistral", "zai", | 141 | + | "huggingface", "openrouter", "gondola", "mistral", "zai", |
| 142 | "xiaomi", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "xiaomi-token-plan-sgp", | 142 | "xiaomi", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "xiaomi-token-plan-sgp", | ||
| 143 | "minimax", "minimax-cn", "fireworks", "vercel-ai-gateway", | 143 | "minimax", "minimax-cn", "fireworks", "vercel-ai-gateway", | ||
| 144 | "opencode", "opencode-go", "amazon-bedrock", "google-vertex", "azure-openai-responses", | 144 | "opencode", "opencode-go", "amazon-bedrock", "google-vertex", "azure-openai-responses", | ||
M packages/provider/extra_providers.go +6 -0
| @@ -116,6 +116,12 @@ func NewOpenRouter(apiKey, baseURL string) Client { | |||
| 116 | 116 | return NewOpenAICompat("openrouter", apiKey, baseURL, openrouterDefaultBaseURL) | |
| 117 | 117 | } | |
| 118 | 118 | ||
| 119 | + | // NewGondola: Gondola, a USDC-paid marketplace gateway for Venice AI | |
| 120 | + | // inference. OpenAI Chat Completions-compatible. | |
| 121 | + | func NewGondola(apiKey, baseURL string) Client { | |
| 122 | + | return NewOpenAICompat("gondola", apiKey, baseURL, "https://api.gondola-ai.com/v1") | |
| 123 | + | } | |
| 124 | + | ||
| 119 | 125 | // NewOpenCode is the opencode.ai Zen endpoint. Mixed APIs upstream; this | |
| 120 | 126 | // constructor wires the openai-completions flavor only. Models that need | |
| 121 | 127 | // the anthropic-messages flavor under the same provider should be built | |
| @@ -116,6 +116,12 @@ func NewOpenRouter(apiKey, baseURL string) Client { | |||||
| 116 | return NewOpenAICompat("openrouter", apiKey, baseURL, openrouterDefaultBaseURL) | 116 | return NewOpenAICompat("openrouter", apiKey, baseURL, openrouterDefaultBaseURL) | ||
| 117 | } | 117 | } | ||
| 118 | 118 | ||||
| 119 | + | // NewGondola: Gondola, a USDC-paid marketplace gateway for Venice AI | |||
| 120 | + | // inference. OpenAI Chat Completions-compatible. | |||
| 121 | + | func NewGondola(apiKey, baseURL string) Client { | |||
| 122 | + | return NewOpenAICompat("gondola", apiKey, baseURL, "https://api.gondola-ai.com/v1") | |||
| 123 | + | } | |||
| 124 | + | ||||
| 119 | // NewOpenCode is the opencode.ai Zen endpoint. Mixed APIs upstream; this | 125 | // NewOpenCode is the opencode.ai Zen endpoint. Mixed APIs upstream; this | ||
| 120 | // constructor wires the openai-completions flavor only. Models that need | 126 | // constructor wires the openai-completions flavor only. Models that need | ||
| 121 | // the anthropic-messages flavor under the same provider should be built | 127 | // the anthropic-messages flavor under the same provider should be built | ||
M packages/provider/labels.go +2 -0
| @@ -37,6 +37,8 @@ func ProviderLabel(id string) string { | |||
| 37 | 37 | return "Hugging Face" | |
| 38 | 38 | case "openrouter": | |
| 39 | 39 | return "OpenRouter" | |
| 40 | + | case "gondola": | |
| 41 | + | return "Gondola" | |
| 40 | 42 | case "mistral": | |
| 41 | 43 | return "Mistral" | |
| 42 | 44 | case "zai": | |
| @@ -37,6 +37,8 @@ func ProviderLabel(id string) string { | |||||
| 37 | return "Hugging Face" | 37 | return "Hugging Face" | ||
| 38 | case "openrouter": | 38 | case "openrouter": | ||
| 39 | return "OpenRouter" | 39 | return "OpenRouter" | ||
| 40 | + | case "gondola": | |||
| 41 | + | return "Gondola" | |||
| 40 | case "mistral": | 42 | case "mistral": | ||
| 41 | return "Mistral" | 43 | return "Mistral" | ||
| 42 | case "zai": | 44 | case "zai": | ||
M packages/provider/models.go +12 -0
| @@ -254,6 +254,18 @@ var Catalog = []Model{ | |||
| 254 | 254 | BaseURL: openrouterDefaultBaseURL, | |
| 255 | 255 | }, | |
| 256 | 256 | ||
| 257 | + | // ---- Gondola ---- | |
| 258 | + | // Seed entry only: the default model returned by defaultModelForProvider | |
| 259 | + | // so it resolves offline. Gondola is a USDC-paid marketplace gateway for | |
| 260 | + | // Venice AI inference; prices/limits pulled live from | |
| 261 | + | // https://api.gondola-ai.com/v1/models (2026-08-11). | |
| 262 | + | { | |
| 263 | + | Provider: "gondola", ID: "claude-opus-5", DisplayName: "Claude Opus 5 (Gondola)", | |
| 264 | + | ContextWindow: 1000000, MaxOutput: 128000, Reasoning: true, AdaptiveThinking: true, | |
| 265 | + | PriceInput: 1.836, PriceOutput: 9.18, | |
| 266 | + | BaseURL: "https://api.gondola-ai.com/v1", | |
| 267 | + | }, | |
| 268 | + | ||
| 257 | 269 | // ---- Speculative: Anthropic ---- | |
| 258 | 270 | { | |
| 259 | 271 | Provider: "anthropic", ID: "claude-opus-4-5", DisplayName: "Claude Opus 4.5 (latest)", | |
| @@ -254,6 +254,18 @@ var Catalog = []Model{ | |||||
| 254 | BaseURL: openrouterDefaultBaseURL, | 254 | BaseURL: openrouterDefaultBaseURL, | ||
| 255 | }, | 255 | }, | ||
| 256 | 256 | ||||
| 257 | + | // ---- Gondola ---- | |||
| 258 | + | // Seed entry only: the default model returned by defaultModelForProvider | |||
| 259 | + | // so it resolves offline. Gondola is a USDC-paid marketplace gateway for | |||
| 260 | + | // Venice AI inference; prices/limits pulled live from | |||
| 261 | + | // https://api.gondola-ai.com/v1/models (2026-08-11). | |||
| 262 | + | { | |||
| 263 | + | Provider: "gondola", ID: "claude-opus-5", DisplayName: "Claude Opus 5 (Gondola)", | |||
| 264 | + | ContextWindow: 1000000, MaxOutput: 128000, Reasoning: true, AdaptiveThinking: true, | |||
| 265 | + | PriceInput: 1.836, PriceOutput: 9.18, | |||
| 266 | + | BaseURL: "https://api.gondola-ai.com/v1", | |||
| 267 | + | }, | |||
| 268 | + | ||||
| 257 | // ---- Speculative: Anthropic ---- | 269 | // ---- Speculative: Anthropic ---- | ||
| 258 | { | 270 | { | ||
| 259 | Provider: "anthropic", ID: "claude-opus-4-5", DisplayName: "Claude Opus 4.5 (latest)", | 271 | Provider: "anthropic", ID: "claude-opus-4-5", DisplayName: "Claude Opus 4.5 (latest)", | ||