vtcode_config/constants/models/
anthropic.rs1pub const DEFAULT_MODEL: &str = "claude-sonnet-5";
3pub const SUPPORTED_MODELS: &[&str] = &[
4 "claude-sonnet-5-5", "claude-sonnet-5", "claude-haiku-5-5", "claude-fable-5", "claude-fable-5-1", "claude-opus-5", "claude-opus-5-5", ];
12
13pub const CLAUDE_OPUS_5: &str = "claude-opus-5";
15pub const CLAUDE_OPUS_5_5: &str = "claude-opus-5-5";
16pub const CLAUDE_SONNET_5: &str = "claude-sonnet-5";
17pub const CLAUDE_SONNET_5_5: &str = "claude-sonnet-5-5";
18pub const CLAUDE_HAIKU_5_5: &str = "claude-haiku-5-5";
19pub const CLAUDE_FABLE_5: &str = "claude-fable-5";
20pub const CLAUDE_FABLE_5_1: &str = "claude-fable-5-1";
21
22pub const REASONING_MODELS: &[&str] = &[
24 CLAUDE_SONNET_5_5,
25 CLAUDE_SONNET_5,
26 CLAUDE_HAIKU_5_5,
27 CLAUDE_FABLE_5,
28 CLAUDE_FABLE_5_1,
29 CLAUDE_OPUS_5,
30 CLAUDE_OPUS_5_5,
31];
32
33const ADVISOR_MIN_MODEL: &str = CLAUDE_SONNET_5;
35
36pub fn normalize_model_id(model: &str) -> &str {
38 if let Some(idx) = model.rfind('-') {
39 let suffix = &model[idx + 1..];
40 if suffix.len() == 8 && suffix.chars().all(|c| c.is_ascii_digit()) {
41 return &model[..idx];
42 }
43 }
44 model
45}
46
47fn advisor_tier(model: &str) -> Option<u8> {
56 match normalize_model_id(model) {
57 CLAUDE_HAIKU_5_5 => Some(2),
58 CLAUDE_SONNET_5 => Some(3),
59 CLAUDE_SONNET_5_5 => Some(4),
60 CLAUDE_OPUS_5 => Some(6),
61 CLAUDE_OPUS_5_5 => Some(7),
62 CLAUDE_FABLE_5 => Some(8),
63 CLAUDE_FABLE_5_1 => Some(8),
64 _ => None,
65 }
66}
67
68pub fn validate_advisor_pair(executor: &str, advisor: &str) -> Result<(), String> {
74 let executor_base = normalize_model_id(executor);
75 let advisor_base = normalize_model_id(advisor);
76
77 if advisor_base == CLAUDE_FABLE_5 && executor_base != CLAUDE_FABLE_5 {
79 return Err(format!("advisor model {advisor} may only advise {CLAUDE_FABLE_5}"));
80 }
81 if advisor_base == CLAUDE_FABLE_5_1 && executor_base != CLAUDE_FABLE_5_1 {
82 return Err(format!("advisor model {advisor} may only advise {CLAUDE_FABLE_5_1}"));
83 }
84
85 let Some(executor_tier) = advisor_tier(executor_base) else {
86 return Err(format!("executor model {executor} is not a supported advisor executor"));
87 };
88 let Some(chosen_advisor_tier) = advisor_tier(advisor_base) else {
89 return Err(format!("advisor model {advisor} is not a supported advisor model"));
90 };
91
92 if chosen_advisor_tier < advisor_tier(ADVISOR_MIN_MODEL).unwrap_or(3) {
93 return Err(format!(
94 "advisor model {advisor} is less capable than the minimum allowed advisor ({ADVISOR_MIN_MODEL})"
95 ));
96 }
97
98 if chosen_advisor_tier < executor_tier {
99 return Err(format!("advisor model {advisor} must be at least as capable as the executor model {executor}"));
100 }
101
102 Ok(())
103}
104
105pub fn default_advisor_model(executor: &str) -> &'static str {
110 match normalize_model_id(executor) {
111 CLAUDE_HAIKU_5_5 => CLAUDE_OPUS_5,
112 CLAUDE_SONNET_5 => CLAUDE_OPUS_5,
113 CLAUDE_SONNET_5_5 => CLAUDE_OPUS_5,
114 CLAUDE_OPUS_5 => CLAUDE_OPUS_5,
115 CLAUDE_OPUS_5_5 => CLAUDE_OPUS_5_5,
116 CLAUDE_FABLE_5 => CLAUDE_FABLE_5,
117 CLAUDE_FABLE_5_1 => CLAUDE_FABLE_5_1,
118 _ => CLAUDE_OPUS_5,
119 }
120}