diff --git a/docs/docs/waveai-modes.mdx b/docs/docs/waveai-modes.mdx index 93403db800..cb7290877b 100644 --- a/docs/docs/waveai-modes.mdx +++ b/docs/docs/waveai-modes.mdx @@ -36,6 +36,7 @@ Wave AI now supports provider-based configuration which automatically applies se - **`openrouter`** - OpenRouter API (automatically configures endpoint and secret name) [[see example](#openrouter)] - **`nanogpt`** - NanoGPT API (automatically configures endpoint and secret name) [[see example](#nanogpt)] - **`groq`** - Groq API (automatically configures endpoint and secret name) [[see example](#groq)] +- **`cheaperinference`** - Cheaper Inference API (automatically configures endpoint and secret name) [[see example](#cheaper-inference)] - **`google`** - Google AI (Gemini) [[see example](#google-ai-gemini)] - **`azure`** - Azure OpenAI Service (modern API) [[see example](#azure-openai-modern-api)] - **`azure-legacy`** - Azure OpenAI Service (legacy deployment API) [[see example](#azure-openai-legacy-deployment-api)] @@ -319,6 +320,39 @@ The provider automatically sets: For Groq, you must manually specify `ai:capabilities` based on your model's features. ::: +### Cheaper Inference + +[Cheaper Inference](https://cheaperinference.com) is an OpenAI-compatible gateway with models from several labs. Using the `cheaperinference` provider simplifies configuration: + +```json +{ + "cheaperinference-gpt54mini": { + "display:name": "Cheaper Inference - GPT-5.4 mini", + "ai:provider": "cheaperinference", + "ai:model": "gpt-5.4-mini" + } +} +``` + +The provider automatically sets: +- `ai:endpoint` to `https://api.cheaperinference.com/v1/chat/completions` +- `ai:apitype` to `openai-chat` +- `ai:apitokensecretname` to `CHEAPER_INFERENCE_KEY` (store your Cheaper Inference API key with this name) + +:::note +For Cheaper Inference, you must manually specify `ai:capabilities` based on your model's features. Model IDs have no provider prefix (for example `gpt-5.4-mini`, `claude-sonnet-5`, `deepseek-v4-flash`). Example for a vision-capable model with tool support: +```json +{ + "cheaperinference-gpt54mini": { + "display:name": "Cheaper Inference - GPT-5.4 mini", + "ai:provider": "cheaperinference", + "ai:model": "gpt-5.4-mini", + "ai:capabilities": ["tools", "images"] + } +} +``` +::: + ### Google AI (Gemini) [Google AI](https://ai.google.dev) provides the Gemini family of models. Using the `google` provider simplifies configuration: @@ -532,7 +566,7 @@ If you get "model not found" errors: | `display:order` | No | Sort order in the selector (lower numbers first) | | `display:icon` | No | Icon identifier for the mode (can use any [FontAwesome icon](https://fontawesome.com/search), use the name without the "fa-" prefix). Default is "sparkles" | | `display:description` | No | Full description of the mode | -| `ai:provider` | No | Provider preset: `openai`, `openrouter`, `nanogpt`, `groq`, `google`, `azure`, `azure-legacy`, `custom` | +| `ai:provider` | No | Provider preset: `openai`, `openrouter`, `nanogpt`, `groq`, `cheaperinference`, `google`, `azure`, `azure-legacy`, `custom` | | `ai:apitype` | No | API type: `openai-chat`, `openai-responses`, or `google-gemini` (defaults to `openai-chat` if not specified) | | `ai:model` | No | Model identifier (required for most providers) | | `ai:thinkinglevel` | No | Thinking level: `low`, `medium`, or `high` | @@ -556,7 +590,7 @@ The `ai:capabilities` field specifies what features the AI mode supports: **Provider-specific behavior:** - **OpenAI and Google providers**: Capabilities are automatically configured based on the model. You don't need to specify them. -- **OpenRouter, NanoGPT, Groq, Azure, Azure-Legacy, and Custom providers**: You must manually specify capabilities based on your model's features. +- **OpenRouter, NanoGPT, Groq, Cheaper Inference, Azure, Azure-Legacy, and Custom providers**: You must manually specify capabilities based on your model's features. :::warning If you don't include `"tools"` in the `ai:capabilities` array, the AI model will not be able to interact with your Wave terminal widgets, read/write files, or execute commands. Most AI modes should include `"tools"` for the best Wave experience. diff --git a/pkg/aiusechat/uctypes/uctypes.go b/pkg/aiusechat/uctypes/uctypes.go index a222eb5c9c..e0cb9e71b8 100644 --- a/pkg/aiusechat/uctypes/uctypes.go +++ b/pkg/aiusechat/uctypes/uctypes.go @@ -24,15 +24,16 @@ const ( ) const ( - AIProvider_Wave = "wave" - AIProvider_Google = "google" - AIProvider_Groq = "groq" - AIProvider_OpenRouter = "openrouter" - AIProvider_NanoGPT = "nanogpt" - AIProvider_OpenAI = "openai" - AIProvider_Azure = "azure" - AIProvider_AzureLegacy = "azure-legacy" - AIProvider_Custom = "custom" + AIProvider_Wave = "wave" + AIProvider_Google = "google" + AIProvider_Groq = "groq" + AIProvider_CheaperInference = "cheaperinference" + AIProvider_OpenRouter = "openrouter" + AIProvider_NanoGPT = "nanogpt" + AIProvider_OpenAI = "openai" + AIProvider_Azure = "azure" + AIProvider_AzureLegacy = "azure-legacy" + AIProvider_Custom = "custom" ) type UseChatRequest struct { diff --git a/pkg/aiusechat/usechat-mode.go b/pkg/aiusechat/usechat-mode.go index 94fe20ef9d..001819f37d 100644 --- a/pkg/aiusechat/usechat-mode.go +++ b/pkg/aiusechat/usechat-mode.go @@ -23,6 +23,7 @@ const ( OpenRouterChatEndpoint = "https://openrouter.ai/api/v1/chat/completions" NanoGPTChatEndpoint = "https://nano-gpt.com/api/v1/chat/completions" GroqChatEndpoint = "https://api.groq.com/openai/v1/chat/completions" + CheaperInferenceChatEndpoint = "https://api.cheaperinference.com/v1/chat/completions" AzureLegacyEndpointTemplate = "https://%s.openai.azure.com/openai/deployments/%s/chat/completions?api-version=%s" AzureResponsesEndpointTemplate = "https://%s.openai.azure.com/openai/v1/responses" AzureChatEndpointTemplate = "https://%s.openai.azure.com/openai/v1/chat/completions" @@ -30,12 +31,13 @@ const ( AzureLegacyDefaultAPIVersion = "2025-04-01-preview" - OpenAIAPITokenSecretName = "OPENAI_KEY" - OpenRouterAPITokenSecretName = "OPENROUTER_KEY" - NanoGPTAPITokenSecretName = "NANOGPT_KEY" - GroqAPITokenSecretName = "GROQ_KEY" - AzureOpenAIAPITokenSecretName = "AZURE_OPENAI_KEY" - GoogleAIAPITokenSecretName = "GOOGLE_AI_KEY" + OpenAIAPITokenSecretName = "OPENAI_KEY" + OpenRouterAPITokenSecretName = "OPENROUTER_KEY" + NanoGPTAPITokenSecretName = "NANOGPT_KEY" + GroqAPITokenSecretName = "GROQ_KEY" + CheaperInferenceAPITokenSecretName = "CHEAPER_INFERENCE_KEY" + AzureOpenAIAPITokenSecretName = "AZURE_OPENAI_KEY" + GoogleAIAPITokenSecretName = "GOOGLE_AI_KEY" ) func resolveAIMode(requestedMode string, premium bool) (string, *wconfig.AIModeConfigType, error) { @@ -125,6 +127,17 @@ func applyProviderDefaults(config *wconfig.AIModeConfigType) { config.APITokenSecretName = GroqAPITokenSecretName } } + if config.Provider == uctypes.AIProvider_CheaperInference { + if config.APIType == "" { + config.APIType = uctypes.APIType_OpenAIChat + } + if config.Endpoint == "" { + config.Endpoint = CheaperInferenceChatEndpoint + } + if config.APITokenSecretName == "" { + config.APITokenSecretName = CheaperInferenceAPITokenSecretName + } + } if config.Provider == uctypes.AIProvider_AzureLegacy { if config.AzureAPIVersion == "" { config.AzureAPIVersion = AzureLegacyDefaultAPIVersion diff --git a/pkg/aiusechat/usechat_mode_test.go b/pkg/aiusechat/usechat_mode_test.go index 73959f9585..18b74a6b33 100644 --- a/pkg/aiusechat/usechat_mode_test.go +++ b/pkg/aiusechat/usechat_mode_test.go @@ -26,6 +26,22 @@ func TestApplyProviderDefaultsGroq(t *testing.T) { } } +func TestApplyProviderDefaultsCheaperInference(t *testing.T) { + config := wconfig.AIModeConfigType{ + Provider: uctypes.AIProvider_CheaperInference, + } + applyProviderDefaults(&config) + if config.APIType != uctypes.APIType_OpenAIChat { + t.Fatalf("expected API type %q, got %q", uctypes.APIType_OpenAIChat, config.APIType) + } + if config.Endpoint != CheaperInferenceChatEndpoint { + t.Fatalf("expected endpoint %q, got %q", CheaperInferenceChatEndpoint, config.Endpoint) + } + if config.APITokenSecretName != CheaperInferenceAPITokenSecretName { + t.Fatalf("expected API token secret name %q, got %q", CheaperInferenceAPITokenSecretName, config.APITokenSecretName) + } +} + func TestApplyProviderDefaultsKeepsProxyURL(t *testing.T) { config := wconfig.AIModeConfigType{ Provider: uctypes.AIProvider_OpenAI, diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go index 67118b1670..a9786763cb 100644 --- a/pkg/wconfig/settingsconfig.go +++ b/pkg/wconfig/settingsconfig.go @@ -289,7 +289,7 @@ type AIModeConfigType struct { DisplayOrder float64 `json:"display:order,omitempty"` DisplayIcon string `json:"display:icon,omitempty"` DisplayDescription string `json:"display:description,omitempty"` - Provider string `json:"ai:provider,omitempty" jsonschema:"enum=wave,enum=google,enum=groq,enum=openrouter,enum=nanogpt,enum=openai,enum=azure,enum=azure-legacy,enum=custom"` + Provider string `json:"ai:provider,omitempty" jsonschema:"enum=wave,enum=google,enum=groq,enum=openrouter,enum=nanogpt,enum=cheaperinference,enum=openai,enum=azure,enum=azure-legacy,enum=custom"` APIType string `json:"ai:apitype,omitempty" jsonschema:"enum=google-gemini,enum=openai-responses,enum=openai-chat"` Model string `json:"ai:model,omitempty"` ThinkingLevel string `json:"ai:thinkinglevel,omitempty" jsonschema:"enum=low,enum=medium,enum=high"` diff --git a/schema/waveai.json b/schema/waveai.json index 7279777a4c..e74d4809ab 100644 --- a/schema/waveai.json +++ b/schema/waveai.json @@ -23,6 +23,7 @@ "groq", "openrouter", "nanogpt", + "cheaperinference", "openai", "azure", "azure-legacy",