Skip to main content

claude_codex/providers/kimi/translate/
model_allowlist.rs

1use std::collections::HashMap;
2
3pub const KIMI_DEFAULT_MODEL: &str = "kimi-for-coding";
4
5static ALIAS_TARGETS: once_cell::sync::Lazy<HashMap<&'static str, &'static str>> =
6    once_cell::sync::Lazy::new(|| {
7        let mut m = HashMap::new();
8        m.insert("haiku", KIMI_DEFAULT_MODEL);
9        m.insert("claude-haiku-4-5", KIMI_DEFAULT_MODEL);
10        m.insert("claude-haiku-4-5-20251001", KIMI_DEFAULT_MODEL);
11        m.insert("sonnet", KIMI_DEFAULT_MODEL);
12        m.insert("claude-sonnet-4-6", KIMI_DEFAULT_MODEL);
13        m.insert("claude-sonnet-5", KIMI_DEFAULT_MODEL);
14        m.insert("opus", KIMI_DEFAULT_MODEL);
15        m.insert("claude-opus-4-7", KIMI_DEFAULT_MODEL);
16        m.insert("claude-opus-4-8", KIMI_DEFAULT_MODEL);
17        m.insert("claude-opus-5", KIMI_DEFAULT_MODEL);
18        m.insert("fable", KIMI_DEFAULT_MODEL);
19        m.insert("claude-fable-5", KIMI_DEFAULT_MODEL);
20        m.insert("kimi-for-coding", KIMI_DEFAULT_MODEL);
21        m.insert("kimi-k3", "k3");
22        m.insert("k3", "k3");
23        m
24    });
25
26const ALLOWED_MODELS: &[&str] = &["kimi-for-coding", "k3"];
27
28pub fn resolve_model(model: &str) -> String {
29    ALIAS_TARGETS
30        .get(model)
31        .copied()
32        .unwrap_or(KIMI_DEFAULT_MODEL)
33        .to_string()
34}
35
36pub fn is_k3(model: &str) -> bool {
37    model == "k3"
38}
39
40pub fn assert_allowed_model(model: &str) -> Result<(), ModelNotAllowedError> {
41    if ALLOWED_MODELS.contains(&model) {
42        Ok(())
43    } else {
44        Err(ModelNotAllowedError {
45            model: model.to_string(),
46        })
47    }
48}
49
50#[derive(Debug)]
51pub struct ModelNotAllowedError {
52    pub model: String,
53}
54
55impl std::fmt::Display for ModelNotAllowedError {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        write!(f, "Model not allowed: {}", self.model)
58    }
59}
60
61impl std::error::Error for ModelNotAllowedError {}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn resolve_haiku_to_default() {
69        assert_eq!(resolve_model("haiku"), KIMI_DEFAULT_MODEL);
70    }
71
72    #[test]
73    fn resolve_opus_4_8_to_default() {
74        assert_eq!(resolve_model("claude-opus-4-8"), KIMI_DEFAULT_MODEL);
75    }
76
77    #[test]
78    fn resolve_claude_5_aliases_to_default() {
79        for model in [
80            "claude-sonnet-5",
81            "claude-opus-5",
82            "fable",
83            "claude-fable-5",
84        ] {
85            assert_eq!(resolve_model(model), KIMI_DEFAULT_MODEL);
86        }
87    }
88
89    #[test]
90    fn resolve_unknown_to_default() {
91        assert_eq!(resolve_model("unknown-model"), KIMI_DEFAULT_MODEL);
92    }
93
94    #[test]
95    fn resolve_kimi_for_coding() {
96        assert_eq!(resolve_model("kimi-for-coding"), KIMI_DEFAULT_MODEL);
97    }
98
99    #[test]
100    fn resolve_kimi_k3_to_k3() {
101        assert_eq!(resolve_model("kimi-k3"), "k3");
102    }
103
104    #[test]
105    fn resolve_k3_to_k3() {
106        assert_eq!(resolve_model("k3"), "k3");
107    }
108
109    #[test]
110    fn k3_detected() {
111        assert!(is_k3("k3"));
112        assert!(!is_k3("kimi-for-coding"));
113    }
114
115    #[test]
116    fn assert_allowed_accepts_default() {
117        assert!(assert_allowed_model(KIMI_DEFAULT_MODEL).is_ok());
118    }
119
120    #[test]
121    fn assert_allowed_accepts_k3() {
122        assert!(assert_allowed_model("k3").is_ok());
123    }
124
125    #[test]
126    fn assert_allowed_rejects_other() {
127        assert!(assert_allowed_model("kimi-k2.6").is_err());
128    }
129}