From 47a56efba6d6c7afa15999b2e332d1405d3a7a4e Mon Sep 17 00:00:00 2001 From: aiapienthusiast <327629069+aiapienthusiast@users.noreply.github.com> Date: Thu, 17 Sep 2026 16:18:22 +0400 Subject: [PATCH] fix(provider): add Cheaper Inference as a built-in provider Cheaper Inference is an OpenAI-compatible gateway, so the entry declares "response_type": "OpenAI" and reuses the existing OpenAI request path. Models are discovered from the provider's /models endpoint rather than pinned, as in #3623. - provider.json: the cheaper_inference entry (api key var, chat-completions URL, models URL, api_key auth) - provider.rs: ProviderId::CHEAPER_INFERENCE, built_in_providers(), the FromStr arm and a display_name arm for "Cheaper Inference", plus three tests - provider_repo.rs: test_cheaper_inference_config, which pins the Models::Url variant - README.md: the env-var block, next to the other providers cargo test --lib -p forge_domain: 618 passed, 0 failed. cargo test --lib -p forge_repo: 334 passed, 0 failed, 1 ignored (pre-existing). Both on stable 1.95, because the pinned 1.97 toolchain cannot be downloaded here; the added code adds no imports and is wrapped to 80 columns, but please re-run cargo fmt on the pinned toolchain. --- README.md | 10 +++++++ crates/forge_domain/src/provider.rs | 29 +++++++++++++++++++ crates/forge_repo/src/provider/provider.json | 9 ++++++ .../forge_repo/src/provider/provider_repo.rs | 26 +++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/README.md b/README.md index 1e7e66626d..45119c3cf0 100644 --- a/README.md +++ b/README.md @@ -590,6 +590,16 @@ ORCAROUTER_API_KEY= +
+Cheaper Inference + +```bash +# .env +CHEAPERINFERENCE_API_KEY= +``` + +
+
Meta diff --git a/crates/forge_domain/src/provider.rs b/crates/forge_domain/src/provider.rs index 0cdff67c96..8fc4b58301 100644 --- a/crates/forge_domain/src/provider.rs +++ b/crates/forge_domain/src/provider.rs @@ -88,6 +88,7 @@ impl ProviderId { pub const KIMI_CODING: ProviderId = ProviderId(Cow::Borrowed("kimi_coding")); pub const MOONSHOT: ProviderId = ProviderId(Cow::Borrowed("moonshot")); pub const ALIBABA_TOKEN_PLAN: ProviderId = ProviderId(Cow::Borrowed("alibaba_token_plan")); + pub const CHEAPER_INFERENCE: ProviderId = ProviderId(Cow::Borrowed("cheaper_inference")); /// Returns all built-in provider IDs /// @@ -135,6 +136,7 @@ impl ProviderId { ProviderId::KIMI_CODING, ProviderId::MOONSHOT, ProviderId::ALIBABA_TOKEN_PLAN, + ProviderId::CHEAPER_INFERENCE, ] } @@ -173,6 +175,7 @@ impl ProviderId { "neuralwatt" => "Neuralwatt".to_string(), "orca_router" => "OrcaRouter".to_string(), "meta" => "Meta".to_string(), + "cheaper_inference" => "Cheaper Inference".to_string(), _ => { // For other providers, use UpperCamelCase conversion use convert_case::{Case, Casing}; @@ -235,6 +238,7 @@ impl std::str::FromStr for ProviderId { "kimi_coding" => ProviderId::KIMI_CODING, "moonshot" => ProviderId::MOONSHOT, "alibaba_token_plan" => ProviderId::ALIBABA_TOKEN_PLAN, + "cheaper_inference" => ProviderId::CHEAPER_INFERENCE, // For custom providers, use Cow::Owned to avoid memory leaks custom => ProviderId(Cow::Owned(custom.to_string())), }; @@ -614,6 +618,10 @@ mod tests { assert_eq!(ProviderId::AMBIENT.to_string(), "Ambient"); assert_eq!(ProviderId::ORCA_ROUTER.to_string(), "OrcaRouter"); assert_eq!(ProviderId::META.to_string(), "Meta"); + assert_eq!( + ProviderId::CHEAPER_INFERENCE.to_string(), + "Cheaper Inference" + ); } #[test] @@ -657,6 +665,7 @@ mod tests { assert!(built_in.contains(&ProviderId::AMBIENT)); assert!(built_in.contains(&ProviderId::ORCA_ROUTER)); assert!(built_in.contains(&ProviderId::META)); + assert!(built_in.contains(&ProviderId::CHEAPER_INFERENCE)); } #[test] @@ -792,6 +801,26 @@ mod tests { assert!(built_in.contains(&ProviderId::META)); } + #[test] + fn test_cheaper_inference_from_str() { + let actual = ProviderId::from_str("cheaper_inference").unwrap(); + let expected = ProviderId::CHEAPER_INFERENCE; + assert_eq!(actual, expected); + } + + #[test] + fn test_cheaper_inference_display_name() { + let actual = ProviderId::CHEAPER_INFERENCE.to_string(); + let expected = "Cheaper Inference".to_string(); + assert_eq!(actual, expected); + } + + #[test] + fn test_cheaper_inference_in_built_in_providers() { + let built_in = ProviderId::built_in_providers(); + assert!(built_in.contains(&ProviderId::CHEAPER_INFERENCE)); + } + #[test] fn test_moonshot_display_name() { let actual = ProviderId::MOONSHOT.to_string(); diff --git a/crates/forge_repo/src/provider/provider.json b/crates/forge_repo/src/provider/provider.json index 27da81ff9a..947a5b2a33 100644 --- a/crates/forge_repo/src/provider/provider.json +++ b/crates/forge_repo/src/provider/provider.json @@ -4468,5 +4468,14 @@ } ], "auth_methods": ["api_key"] + }, + { + "id": "cheaper_inference", + "api_key_vars": "CHEAPERINFERENCE_API_KEY", + "url_param_vars": [], + "response_type": "OpenAI", + "url": "https://api.cheaperinference.com/v1/chat/completions", + "models": "https://api.cheaperinference.com/v1/models", + "auth_methods": ["api_key"] } ] diff --git a/crates/forge_repo/src/provider/provider_repo.rs b/crates/forge_repo/src/provider/provider_repo.rs index 7f4329315a..f73edd8774 100644 --- a/crates/forge_repo/src/provider/provider_repo.rs +++ b/crates/forge_repo/src/provider/provider_repo.rs @@ -971,6 +971,32 @@ mod tests { } } + #[test] + fn test_cheaper_inference_config() { + let configs = get_provider_configs(); + let config = configs + .iter() + .find(|c| c.id == ProviderId::CHEAPER_INFERENCE) + .unwrap(); + assert_eq!(config.id, ProviderId::CHEAPER_INFERENCE); + assert_eq!( + config.api_key_vars, + Some("CHEAPERINFERENCE_API_KEY".to_string()) + ); + assert!(config.url_param_vars.is_empty()); + assert_eq!(config.response_type, Some(ProviderResponse::OpenAI)); + assert_eq!( + config.url.as_str(), + "https://api.cheaperinference.com/v1/chat/completions" + ); + match config.models.as_ref().expect("models should be present") { + Models::Url(model_url) => { + assert_eq!(model_url, "https://api.cheaperinference.com/v1/models"); + } + other => panic!("expected URL-driven models, got {other:?}"), + } + } + #[test] fn test_meta_config() { let configs = get_provider_configs();