1use serde::{Deserialize, Serialize};
8
9use crate::provider;
10
11#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
12#[serde(rename_all = "kebab-case")]
13pub enum ProviderKind {
14 #[default]
15 #[serde(
16 alias = "deepseek-cn",
17 alias = "deepseek_china",
18 alias = "deepseekcn",
19 alias = "deepseek-china"
20 )]
21 Deepseek,
22 #[serde(
23 alias = "deepseek-anthropic",
24 alias = "deepseek_anthropic",
25 alias = "deepseek-claude",
26 alias = "deepseek_claude"
27 )]
28 DeepseekAnthropic,
29 NvidiaNim,
30 #[serde(alias = "open-ai")]
31 Openai,
32 Atlascloud,
33 #[serde(
34 alias = "wanjie",
35 alias = "wanjie_ark",
36 alias = "ark-wanjie",
37 alias = "ark_wanjie",
38 alias = "wanjie-maas",
39 alias = "wanjie_maas"
40 )]
41 WanjieArk,
42 #[serde(alias = "volcengine-ark", alias = "volcengine_ark", alias = "ark")]
43 Volcengine,
44 Openrouter,
45 #[serde(alias = "orca_router", alias = "orca")]
46 Orcarouter,
47 #[serde(alias = "mimo", alias = "xiaomi", alias = "xiaomi_mimo")]
48 XiaomiMimo,
49 #[serde(alias = "novita-ai", alias = "novita_ai")]
50 Novita,
51 #[serde(alias = "fireworks-ai", alias = "fireworks_ai")]
52 Fireworks,
53 #[serde(alias = "silicon-flow", alias = "silicon_flow")]
54 Siliconflow,
55 #[serde(alias = "arcee-ai", alias = "arcee_ai")]
56 Arcee,
57 #[serde(alias = "siliconflow-cn", alias = "siliconflow-CN")]
58 SiliconflowCN,
59 #[serde(alias = "moonshot-ai", alias = "moonshotai", alias = "moonshot_ai")]
60 Moonshot,
61 Sglang,
62 Vllm,
63 Ollama,
64 #[serde(alias = "ollama_cloud")]
65 OllamaCloud,
66 #[serde(alias = "hugging-face", alias = "hugging_face", alias = "hf")]
67 Huggingface,
68 #[serde(alias = "together-ai", alias = "together_ai", alias = "togetherai")]
69 Together,
70 #[serde(alias = "baidu-qianfan", alias = "baidu_qianfan", alias = "baidu")]
71 Qianfan,
72 #[serde(
73 alias = "openai-codex",
74 alias = "openai_codex",
75 alias = "codex",
76 alias = "chatgpt",
77 alias = "chatgpt-codex",
78 alias = "chatgpt_codex"
79 )]
80 OpenaiCodex,
81 #[serde(alias = "claude")]
82 Anthropic,
83 #[serde(alias = "open-model", alias = "open_model")]
84 Openmodel,
85 #[serde(
86 alias = "z-ai",
87 alias = "z_ai",
88 alias = "z.ai",
89 alias = "zhipu",
90 alias = "zhipuai",
91 alias = "bigmodel",
92 alias = "big-model"
93 )]
94 Zai,
95 #[serde(
96 alias = "step-fun",
97 alias = "step_fun",
98 alias = "stepfun",
99 alias = "stepflash",
100 alias = "step-flash",
101 alias = "step_flash"
102 )]
103 Stepfun,
104 #[serde(alias = "mini-max", alias = "mini_max", alias = "minimax")]
105 Minimax,
106 #[serde(
107 alias = "minimax_anthropic",
108 alias = "mini-max-anthropic",
109 alias = "mini_max_anthropic"
110 )]
111 MinimaxAnthropic,
112 #[serde(alias = "deep-infra", alias = "deep_infra")]
113 Deepinfra,
114 #[serde(alias = "sakana-ai", alias = "sakana_ai", alias = "fugu")]
115 Sakana,
116 #[serde(alias = "long-cat", alias = "meituan-longcat", alias = "meituan")]
117 LongCat,
118 #[serde(alias = "opencode_go", alias = "opencodego")]
119 OpencodeGo,
120 #[serde(
121 alias = "opencode_zen",
122 alias = "opencodezen",
123 alias = "zen",
124 alias = "opencode"
125 )]
126 OpencodeZen,
127 #[serde(
128 alias = "meta-ai",
129 alias = "meta_ai",
130 alias = "meta-model-api",
131 alias = "meta_model_api",
132 alias = "muse",
133 alias = "muse-spark"
134 )]
135 Meta,
136 #[serde(alias = "x-ai", alias = "x_ai", alias = "grok")]
137 Xai,
138 #[serde(
140 alias = "mistral-ai",
141 alias = "mistral_ai",
142 alias = "mistralai",
143 alias = "la-plateforme",
144 alias = "la_plateforme"
145 )]
146 Mistral,
147 #[serde(
153 alias = "telecom-js",
154 alias = "telecom_js",
155 alias = "telecomjs-cn",
156 alias = "tokenhub"
157 )]
158 Telecomjs,
159 #[serde(
166 alias = "modelstudio-token-plan",
167 alias = "modelstudio_token_plan",
168 alias = "alibaba-token-plan",
169 alias = "dashscope-token-plan"
170 )]
171 ModelstudioTokenPlan,
172 #[serde(
174 alias = "modelstudio-token-plan-anthropic",
175 alias = "modelstudio_token_plan_anthropic",
176 alias = "alibaba-token-plan-anthropic"
177 )]
178 ModelstudioTokenPlanAnthropic,
179 #[serde(
181 alias = "modelstudio-coding-plan",
182 alias = "modelstudio_coding_plan",
183 alias = "alibaba-coding-plan",
184 alias = "dashscope-coding-plan"
185 )]
186 ModelstudioCodingPlan,
187 #[serde(
189 alias = "modelstudio-coding-plan-anthropic",
190 alias = "modelstudio_coding_plan_anthropic",
191 alias = "alibaba-coding-plan-anthropic"
192 )]
193 ModelstudioCodingPlanAnthropic,
194 #[serde(alias = "agy")]
198 Antigravity,
199 #[serde(
203 alias = "google-gemini",
204 alias = "google_gemini",
205 alias = "gemini",
206 alias = "google-ai",
207 alias = "google_ai",
208 alias = "ai-studio",
209 alias = "aistudio"
210 )]
211 Google,
212 #[serde(alias = "eden-ai", alias = "eden_ai", alias = "edenai")]
217 Edenai,
218 Custom,
226}
227
228impl ProviderKind {
229 pub const ALL: [Self; 42] = [
236 Self::Deepseek,
237 Self::NvidiaNim,
238 Self::Openai,
239 Self::Atlascloud,
240 Self::WanjieArk,
241 Self::Volcengine,
242 Self::Openrouter,
243 Self::Orcarouter,
244 Self::XiaomiMimo,
245 Self::Novita,
246 Self::Fireworks,
247 Self::Siliconflow,
248 Self::Arcee,
249 Self::SiliconflowCN,
250 Self::Moonshot,
251 Self::Sglang,
252 Self::Vllm,
253 Self::Ollama,
254 Self::OllamaCloud,
255 Self::Huggingface,
256 Self::Together,
257 Self::Qianfan,
258 Self::OpenaiCodex,
259 Self::Anthropic,
260 Self::Openmodel,
261 Self::Zai,
262 Self::Stepfun,
263 Self::Minimax,
264 Self::Deepinfra,
265 Self::Sakana,
266 Self::LongCat,
267 Self::OpencodeGo,
268 Self::OpencodeZen,
269 Self::Meta,
270 Self::Xai,
271 Self::Mistral,
272 Self::Telecomjs,
273 Self::ModelstudioTokenPlan,
274 Self::Google,
275 Self::Antigravity,
276 Self::Edenai,
277 Self::Custom,
278 ];
279
280 #[must_use]
281 pub fn all() -> &'static [Self] {
282 &Self::ALL
283 }
284
285 #[must_use]
286 pub fn names_hint() -> String {
287 Self::all()
288 .iter()
289 .map(|provider| provider.as_str())
290 .collect::<Vec<_>>()
291 .join(", ")
292 }
293
294 #[must_use]
295 pub fn as_str(self) -> &'static str {
296 self.provider().id()
297 }
298
299 #[must_use]
300 pub fn parse(value: &str) -> Option<Self> {
301 let trimmed = value.trim();
302 provider::all_providers()
303 .iter()
304 .find(|p| {
305 trimmed.eq_ignore_ascii_case(p.id())
306 || p.aliases().iter().any(|a| trimmed.eq_ignore_ascii_case(a))
307 })
308 .map(|p| p.kind())
309 }
310
311 #[must_use]
330 pub fn parse_config_identity(value: &str) -> Option<Self> {
331 let trimmed = value.trim();
332 provider::all_providers()
333 .iter()
334 .find(|p| {
335 trimmed.eq_ignore_ascii_case(p.id())
336 || trimmed.eq_ignore_ascii_case(p.provider_config_key())
337 })
338 .map(|p| p.kind())
339 .or_else(|| Self::parse(trimmed))
340 }
341
342 #[must_use]
343 pub fn is_siliconflow(self) -> bool {
344 matches!(self, Self::Siliconflow | Self::SiliconflowCN)
345 }
346
347 #[must_use]
361 pub fn secret_store_slot(self) -> &'static str {
362 match self {
363 Self::SiliconflowCN => "siliconflow",
364 Self::ModelstudioTokenPlan
365 | Self::ModelstudioTokenPlanAnthropic
366 | Self::ModelstudioCodingPlan
367 | Self::ModelstudioCodingPlanAnthropic => "modelstudio-token-plan",
368 _ => self.as_str(),
369 }
370 }
371
372 #[must_use]
377 pub fn provider(self) -> &'static dyn provider::Provider {
378 provider::provider_for_kind(self)
379 }
380}