1#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct ProviderId(String);
7
8impl ProviderId {
9 pub const OPENAI: &'static str = "openai";
11 pub const ANTHROPIC: &'static str = "anthropic";
12 pub const GOOGLE_GEMINI: &'static str = "google-gemini";
13 pub const OPENROUTER: &'static str = "openrouter";
14 pub const GITHUB_COPILOT: &'static str = "github-copilot";
15 pub const OPENCODE: &'static str = "opencode";
16 pub const OPENCODE_ZEN: &'static str = "opencode-zen";
17 pub const OPENCODE_GO: &'static str = "opencode-go";
18 pub const COMMANDCODE: &'static str = "commandcode";
19 pub const CHARM_HYPER: &'static str = "charm-hyper";
20 pub const GROQ: &'static str = "groq";
21 pub const XAI: &'static str = "xai";
22 pub const MIMO_ANTHROPIC_CN: &'static str = "mimo-anthropic-cn";
23 pub const MIMO_ANTHROPIC_SGP: &'static str = "mimo-anthropic-sgp";
24 pub const MIMO_ANTHROPIC_AMS: &'static str = "mimo-anthropic-ams";
25 pub const NVIDIA: &'static str = "nvidia";
26
27 pub fn from_config_id(id: &str) -> Self {
32 Self(id.to_string())
33 }
34
35 pub fn known(constant: &str) -> Self {
38 debug_assert!(
39 [
40 Self::OPENAI,
41 Self::ANTHROPIC,
42 Self::GOOGLE_GEMINI,
43 Self::OPENROUTER,
44 Self::GITHUB_COPILOT,
45 Self::OPENCODE,
46 Self::OPENCODE_ZEN,
47 Self::OPENCODE_GO,
48 Self::COMMANDCODE,
49 Self::CHARM_HYPER,
50 Self::GROQ,
51 Self::XAI,
52 Self::MIMO_ANTHROPIC_CN,
53 Self::MIMO_ANTHROPIC_SGP,
54 Self::MIMO_ANTHROPIC_AMS,
55 Self::NVIDIA,
56 ]
57 .contains(&constant),
58 "not a known provider constant: {constant}"
59 );
60 Self(constant.to_string())
61 }
62
63 pub fn as_str(&self) -> &str {
67 &self.0
68 }
69
70 pub fn is_opencode_family(&self) -> bool {
73 matches!(
74 self.0.as_str(),
75 Self::OPENCODE | Self::OPENCODE_ZEN | Self::OPENCODE_GO
76 )
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn from_config_id_stores_string_verbatim() {
86 assert_eq!(ProviderId::from_config_id("openai").as_str(), "openai");
87 assert_eq!(
88 ProviderId::from_config_id("google-gemini").as_str(),
89 "google-gemini"
90 );
91 assert_eq!(
92 ProviderId::from_config_id("custom-provider").as_str(),
93 "custom-provider"
94 );
95 }
96
97 #[test]
98 fn from_config_id_accepts_empty_string() {
99 assert_eq!(ProviderId::from_config_id("").as_str(), "");
100 }
101
102 #[test]
103 fn as_str_returns_inner_string() {
104 let id = ProviderId::from_config_id("anthropic");
105 assert_eq!(id.as_str(), "anthropic");
106 }
107
108 #[test]
109 fn known_accepts_all_predefined_constants() {
110 let constants = [
111 ProviderId::OPENAI,
112 ProviderId::ANTHROPIC,
113 ProviderId::GOOGLE_GEMINI,
114 ProviderId::OPENROUTER,
115 ProviderId::GITHUB_COPILOT,
116 ProviderId::OPENCODE,
117 ProviderId::OPENCODE_ZEN,
118 ProviderId::OPENCODE_GO,
119 ProviderId::COMMANDCODE,
120 ProviderId::GROQ,
121 ProviderId::XAI,
122 ProviderId::MIMO_ANTHROPIC_CN,
123 ProviderId::MIMO_ANTHROPIC_SGP,
124 ProviderId::MIMO_ANTHROPIC_AMS,
125 ProviderId::NVIDIA,
126 ];
127 for c in constants {
128 let id = ProviderId::known(c);
129 assert_eq!(id.as_str(), c);
130 }
131 }
132
133 #[test]
134 fn is_opencode_family_returns_true_for_opencode_variants() {
135 assert!(ProviderId::from_config_id("opencode").is_opencode_family());
136 assert!(ProviderId::from_config_id("opencode-zen").is_opencode_family());
137 assert!(ProviderId::from_config_id("opencode-go").is_opencode_family());
138 }
139
140 #[test]
141 fn is_opencode_family_returns_false_for_others() {
142 assert!(!ProviderId::from_config_id("openai").is_opencode_family());
143 assert!(!ProviderId::from_config_id("anthropic").is_opencode_family());
144 assert!(!ProviderId::from_config_id("commandcode").is_opencode_family());
145 assert!(!ProviderId::from_config_id("google-gemini").is_opencode_family());
146 assert!(!ProviderId::from_config_id("custom").is_opencode_family());
147 }
148
149 #[test]
150 fn known_equals_from_config_id_for_same_string() {
151 assert_eq!(
152 ProviderId::known(ProviderId::OPENAI),
153 ProviderId::from_config_id("openai")
154 );
155 assert_eq!(
156 ProviderId::known(ProviderId::ANTHROPIC),
157 ProviderId::from_config_id("anthropic")
158 );
159 }
160}