feat(providers): add OVHcloud AI Endpoints as native provider

Route OVHcloud through OpenAiProvider (with proper tool_call_id
serialization) instead of OpenAiCompatibleProvider, fixing tool-call
round-trips against vLLM-based endpoints.

- Add base_url field and with_base_url() constructor to OpenAiProvider
- Replace all hardcoded api.openai.com URLs with self.base_url
- Pass api_url through for the openai provider arm
- Register ovhcloud/ovh provider with env var OVH_AI_ENDPOINTS_ACCESS_TOKEN
This commit is contained in:
Lucien Loiseau 2026-02-18 12:39:28 +01:00 committed by Chummy
parent 80b60d7b70
commit 6062888d1b
2 changed files with 28 additions and 4 deletions

View file

@ -324,6 +324,7 @@ fn resolve_provider_credential(name: &str, credential_override: Option<&str>) ->
"opencode" | "opencode-zen" => vec!["OPENCODE_API_KEY"],
"vercel" | "vercel-ai" => vec!["VERCEL_API_KEY"],
"cloudflare" | "cloudflare-ai" => vec!["CLOUDFLARE_API_KEY"],
"ovhcloud" | "ovh" => vec!["OVH_AI_ENDPOINTS_ACCESS_TOKEN"],
"astrai" => vec!["ASTRAI_API_KEY"],
_ => vec![],
};
@ -405,7 +406,7 @@ pub fn create_provider_with_url(
// ── Primary providers (custom implementations) ───────
"openrouter" => Ok(Box::new(openrouter::OpenRouterProvider::new(key))),
"anthropic" => Ok(Box::new(anthropic::AnthropicProvider::new(key))),
"openai" => Ok(Box::new(openai::OpenAiProvider::new(key))),
"openai" => Ok(Box::new(openai::OpenAiProvider::with_base_url(api_url, key))),
// Ollama uses api_url for custom base URL (e.g. remote Ollama instance)
"ollama" => Ok(Box::new(ollama::OllamaProvider::new(api_url, key))),
"gemini" | "google" | "google-gemini" => {
@ -527,6 +528,12 @@ pub fn create_provider_with_url(
"Astrai", "https://as-trai.com/v1", key, AuthStyle::Bearer,
))),
// ── Cloud AI endpoints ───────────────────────────────
"ovhcloud" | "ovh" => Ok(Box::new(openai::OpenAiProvider::with_base_url(
Some("https://oai.endpoints.kepler.ai.cloud.ovh.net/v1"),
key,
))),
// ── Bring Your Own Provider (custom URL) ───────────
// Format: "custom:https://your-api.com" or "custom:http://localhost:1234"
name if name.starts_with("custom:") => {
@ -900,6 +907,12 @@ pub fn list_providers() -> Vec<ProviderInfo> {
aliases: &["nvidia-nim", "build.nvidia.com"],
local: false,
},
ProviderInfo {
name: "ovhcloud",
display_name: "OVHcloud AI Endpoints",
aliases: &["ovh"],
local: false,
},
]
}
@ -1413,6 +1426,7 @@ mod tests {
"copilot",
"nvidia",
"astrai",
"ovhcloud",
];
for name in providers {
assert!(