codetether_agent/provider/
parse.rs1pub fn parse_model_string(s: &str) -> (Option<&str>, &str) {
26 let mut parts = s.split('/');
27 let Some(first) = parts.next() else {
28 return (None, s);
29 };
30
31 let remainder_start = first.len();
32 if remainder_start >= s.len() {
33 return (None, s);
34 }
35
36 let remainder = &s[remainder_start + 1..];
37 (Some(first), remainder)
38}
39
40pub(crate) fn normalize_minimax_anthropic_base_url(base_url: &str) -> String {
45 let trimmed = base_url.trim().trim_end_matches('/');
46 if trimmed.eq_ignore_ascii_case("https://api.minimax.io/v1") {
47 "https://api.minimax.io/anthropic".to_string()
48 } else {
49 trimmed.to_string()
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn parses_provider_model() {
59 assert_eq!(
60 parse_model_string("openai/gpt-4o"),
61 (Some("openai"), "gpt-4o")
62 );
63 }
64
65 #[test]
66 fn parses_bare_model() {
67 assert_eq!(parse_model_string("gpt-4o"), (None, "gpt-4o"));
68 }
69
70 #[test]
71 fn parses_nested_provider() {
72 assert_eq!(
73 parse_model_string("openrouter/openai/gpt-5-codex"),
74 (Some("openrouter"), "openai/gpt-5-codex")
75 );
76 }
77
78 #[test]
79 fn normalizes_minimax_url() {
80 assert_eq!(
81 normalize_minimax_anthropic_base_url("https://api.minimax.io/v1"),
82 "https://api.minimax.io/anthropic"
83 );
84 assert_eq!(
85 normalize_minimax_anthropic_base_url("https://custom.host/custom"),
86 "https://custom.host/custom"
87 );
88 }
89}