1use super::*;
2
3pub(super) fn default_model_for_backend(backend: BackendKind) -> String {
4 match backend {
5 BackendKind::DeepSeekChat => "deepseek-v4-pro".to_string(),
6 BackendKind::OpenAiResponses => "gpt-5.5".to_string(),
7 BackendKind::ChatGptCodexResponses => "gpt-5.5".to_string(),
8 BackendKind::FireworksChat => "gpt-5.5".to_string(),
9 BackendKind::Auto => unreachable!("auto backend does not have a default model"),
10 }
11}
12
13pub(super) fn default_reasoning_effort(backend: BackendKind) -> Option<ReasoningEffort> {
14 match backend {
15 BackendKind::OpenAiResponses | BackendKind::ChatGptCodexResponses => {
16 Some(ReasoningEffort::Xhigh)
17 }
18 BackendKind::DeepSeekChat => None,
19 BackendKind::FireworksChat => None,
20 BackendKind::Auto => None,
21 }
22}
23
24pub(super) fn default_base_url_for_backend_hint(backend: BackendKind) -> &'static str {
25 match backend {
26 BackendKind::DeepSeekChat => "https://api.deepseek.com",
27 BackendKind::ChatGptCodexResponses => "https://chatgpt.com/backend-api",
28 BackendKind::Auto | BackendKind::FireworksChat | BackendKind::OpenAiResponses => {
29 "https://api.openai.com/v1"
30 }
31 }
32}
33
34pub(super) fn api_key_for_backend(
35 backend: BackendKind,
36 configured_env: Option<&str>,
37 configured_api_key: Option<&str>,
38) -> Result<String> {
39 match backend {
40 BackendKind::ChatGptCodexResponses => Ok(String::new()),
41 BackendKind::Auto
42 | BackendKind::DeepSeekChat
43 | BackendKind::FireworksChat
44 | BackendKind::OpenAiResponses => {
45 if let Ok(api_key) = std::env::var("OPENAI_API_KEY") {
46 return Ok(api_key);
47 }
48 if let Some(env_name) = configured_env.filter(|name| *name != "OPENAI_API_KEY") {
49 if let Ok(api_key) = std::env::var(env_name) {
50 return Ok(api_key);
51 }
52 }
53 if let Some(api_key) = configured_api_key.filter(|value| !value.trim().is_empty()) {
54 return Ok(api_key.to_string());
55 }
56 if let Some(env_name) = configured_env.filter(|name| *name != "OPENAI_API_KEY") {
57 return Err(anyhow!(
58 "OPENAI_API_KEY environment variable is not set, configured api_key_env '{}' is not set, and no config model.api_key is present",
59 env_name
60 ));
61 }
62 Err(anyhow!("OPENAI_API_KEY environment variable is not set"))
63 }
64 }
65}
66
67pub fn detect_backend(base_url: &str) -> Result<BackendKind> {
68 let parsed = Url::parse(base_url)
69 .map_err(|error| anyhow!("failed to parse OPENAI_BASE_URL '{}': {}", base_url, error))?;
70 let host = parsed
71 .host_str()
72 .ok_or_else(|| anyhow!("OPENAI_BASE_URL '{}' does not include a host", base_url))?;
73
74 if host.contains("fireworks.ai") {
75 return Ok(BackendKind::FireworksChat);
76 }
77 if host == "api.deepseek.com" {
78 return Ok(BackendKind::DeepSeekChat);
79 }
80 if host == "api.openai.com" {
81 return Ok(BackendKind::OpenAiResponses);
82 }
83 if host == "chatgpt.com" && parsed.path().contains("/backend-api") {
84 return Ok(BackendKind::ChatGptCodexResponses);
85 }
86
87 Err(anyhow!(
88 "could not infer backend from '{}'; pass --backend deepseek-chat, --backend fireworks-chat, --backend openai-responses, or --backend chatgpt-codex-responses",
89 base_url
90 ))
91}