claude_codex/providers/cursor/
model.rs1pub const CURSOR_LEGACY_MODELS: &[&str] = &[
12 "cursor",
13 "cursor-agent",
14 "cursor-composer",
15 "cursor-composer-fast",
16 "cursor-plan",
17 "cursor-ask",
18 "composer-2.5",
19 "composer-2.5-fast",
20];
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum CursorAgentMode {
25 Agent,
26 Plan,
27 Ask,
28}
29
30impl CursorAgentMode {
31 pub fn as_str(&self) -> &'static str {
32 match self {
33 CursorAgentMode::Agent => "AGENT_MODE_AGENT",
34 CursorAgentMode::Plan => "AGENT_MODE_PLAN",
35 CursorAgentMode::Ask => "AGENT_MODE_ASK",
36 }
37 }
38}
39
40pub fn resolve_cursor_model(model: &str) -> Result<CursorModelResolution, String> {
44 let model = model.trim();
45
46 if let Some(rest) = model.strip_prefix("cursor-agent:") {
48 return Ok(CursorModelResolution {
49 model_id: rest.to_string(),
50 mode: CursorAgentMode::Agent,
51 });
52 }
53 if let Some(rest) = model.strip_prefix("cursor-plan:") {
54 return Ok(CursorModelResolution {
55 model_id: rest.to_string(),
56 mode: CursorAgentMode::Plan,
57 });
58 }
59 if let Some(rest) = model.strip_prefix("cursor-ask:") {
60 return Ok(CursorModelResolution {
61 model_id: rest.to_string(),
62 mode: CursorAgentMode::Ask,
63 });
64 }
65 if let Some(rest) = model.strip_prefix("cursor:") {
66 return Ok(CursorModelResolution {
67 model_id: rest.to_string(),
68 mode: CursorAgentMode::Agent,
69 });
70 }
71
72 match model {
74 "cursor" | "cursor-agent" | "cursor-composer" | "cursor-composer-fast" => {
75 Ok(CursorModelResolution {
76 model_id: model.to_string(),
77 mode: CursorAgentMode::Agent,
78 })
79 }
80 "cursor-plan" | "composer-2.5" => Ok(CursorModelResolution {
81 model_id: model.to_string(),
82 mode: CursorAgentMode::Plan,
83 }),
84 "cursor-ask" | "composer-2.5-fast" => Ok(CursorModelResolution {
85 model_id: model.to_string(),
86 mode: CursorAgentMode::Ask,
87 }),
88 _ => Err(format!(
89 "unknown cursor model: {model}. Supported: cursor:<id>, cursor-plan:<id>, cursor-ask:<id>, cursor-agent"
90 )),
91 }
92}
93
94#[derive(Debug, Clone)]
95pub struct CursorModelResolution {
96 pub model_id: String,
97 pub mode: CursorAgentMode,
98}
99
100pub fn cursor_supported_models() -> Vec<String> {
102 let mut out: Vec<String> = CURSOR_LEGACY_MODELS
103 .iter()
104 .map(|s| (*s).to_string())
105 .collect();
106 out.sort_unstable();
107 out
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn resolve_legacy_cursor() {
116 let r = resolve_cursor_model("cursor").unwrap();
117 assert_eq!(r.model_id, "cursor");
118 assert_eq!(r.mode, CursorAgentMode::Agent);
119 }
120
121 #[test]
122 fn resolve_legacy_cursor_agent() {
123 let r = resolve_cursor_model("cursor-agent").unwrap();
124 assert_eq!(r.mode, CursorAgentMode::Agent);
125 }
126
127 #[test]
128 fn resolve_legacy_cursor_plan() {
129 let r = resolve_cursor_model("cursor-plan").unwrap();
130 assert_eq!(r.mode, CursorAgentMode::Plan);
131 }
132
133 #[test]
134 fn resolve_legacy_cursor_ask() {
135 let r = resolve_cursor_model("cursor-ask").unwrap();
136 assert_eq!(r.mode, CursorAgentMode::Ask);
137 }
138
139 #[test]
140 fn resolve_prefixed_cursor() {
141 let r = resolve_cursor_model("cursor:gpt-5.5").unwrap();
142 assert_eq!(r.model_id, "gpt-5.5");
143 assert_eq!(r.mode, CursorAgentMode::Agent);
144 }
145
146 #[test]
147 fn resolve_prefixed_cursor_plan() {
148 let r = resolve_cursor_model("cursor-plan:gpt-5.5").unwrap();
149 assert_eq!(r.model_id, "gpt-5.5");
150 assert_eq!(r.mode, CursorAgentMode::Plan);
151 }
152
153 #[test]
154 fn resolve_prefixed_cursor_ask() {
155 let r = resolve_cursor_model("cursor-ask:gpt-5.5").unwrap();
156 assert_eq!(r.model_id, "gpt-5.5");
157 assert_eq!(r.mode, CursorAgentMode::Ask);
158 }
159
160 #[test]
161 fn resolve_prefixed_cursor_agent() {
162 let r = resolve_cursor_model("cursor-agent:gpt-5.5").unwrap();
163 assert_eq!(r.model_id, "gpt-5.5");
164 assert_eq!(r.mode, CursorAgentMode::Agent);
165 }
166
167 #[test]
168 fn resolve_unknown_model_errors() {
169 let r = resolve_cursor_model("unknown-model");
170 assert!(r.is_err());
171 }
172
173 #[test]
174 fn resolve_composer_models() {
175 let r = resolve_cursor_model("composer-2.5").unwrap();
176 assert_eq!(r.mode, CursorAgentMode::Plan);
177
178 let r = resolve_cursor_model("composer-2.5-fast").unwrap();
179 assert_eq!(r.mode, CursorAgentMode::Ask);
180 }
181
182 #[test]
183 fn supported_models_includes_all_legacy() {
184 let models = cursor_supported_models();
185 for m in CURSOR_LEGACY_MODELS {
186 assert!(models.contains(&m.to_string()), "missing {m}");
187 }
188 }
189}