agent_engine/runtime/openai/catalog/
xai.rs1use super::{
10 CatalogModel, CatalogProviderKind, CatalogSource, Modality, PricingSummary, ReasoningSupport,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct XaiModelDescriptor {
15 pub id: &'static str,
16 pub label: &'static str,
17 pub context_tokens: Option<u64>,
18 pub reasoning: bool,
19}
20
21pub const XAI_TEXT_MODELS: &[XaiModelDescriptor] = &[
22 XaiModelDescriptor {
23 id: "grok-4.3",
24 label: "Grok 4.3",
25 context_tokens: None,
26 reasoning: true,
27 },
28 XaiModelDescriptor {
29 id: "grok-4.3-latest",
30 label: "Grok 4.3 (latest alias)",
31 context_tokens: None,
32 reasoning: true,
33 },
34 XaiModelDescriptor {
35 id: "grok-latest",
36 label: "Grok (latest alias)",
37 context_tokens: None,
38 reasoning: true,
39 },
40 XaiModelDescriptor {
41 id: "grok-4.20-0309-reasoning",
42 label: "Grok 4.20 Reasoning",
43 context_tokens: None,
44 reasoning: true,
45 },
46 XaiModelDescriptor {
47 id: "grok-4.20-0309-non-reasoning",
48 label: "Grok 4.20 Non-Reasoning",
49 context_tokens: None,
50 reasoning: false,
51 },
52 XaiModelDescriptor {
53 id: "grok-4.20-multi-agent-0309",
54 label: "Grok 4.20 Multi-Agent",
55 context_tokens: None,
56 reasoning: true,
57 },
58 XaiModelDescriptor {
59 id: "grok-4.5",
60 label: "Grok 4.5",
61 context_tokens: None,
62 reasoning: true,
63 },
64 XaiModelDescriptor {
65 id: "grok-4.5-latest",
66 label: "Grok 4.5 (latest alias)",
67 context_tokens: None,
68 reasoning: true,
69 },
70];
71
72pub fn xai_model(id: &str) -> Option<&'static XaiModelDescriptor> {
73 XAI_TEXT_MODELS.iter().find(|model| model.id == id)
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum XaiReasoningCapability {
86 Effort {
89 supported: &'static [agent_core::reasoning::ReasoningLevel],
90 default_level: Option<agent_core::reasoning::ReasoningLevel>,
91 can_disable: bool,
94 },
95 IntrinsicReasoning,
97 NonReasoning,
99}
100
101pub fn xai_static_capability(model_id: &str) -> Option<XaiReasoningCapability> {
104 use agent_core::reasoning::ReasoningLevel::*;
105 match model_id {
106 "grok-4.5" | "grok-4.5-latest" => Some(XaiReasoningCapability::Effort {
107 supported: &[Low, Medium, High],
108 default_level: Some(High),
109 can_disable: false,
110 }),
111 "grok-4.20-multi-agent-0309" => Some(XaiReasoningCapability::Effort {
112 supported: &[Low, Medium, High, XHigh],
113 default_level: None,
115 can_disable: false,
116 }),
117 "grok-4.3" | "grok-4.3-latest" | "grok-latest" | "grok-4.20-0309-reasoning" => {
118 Some(XaiReasoningCapability::IntrinsicReasoning)
119 }
120 "grok-4.20-0309-non-reasoning" => Some(XaiReasoningCapability::NonReasoning),
121 _ => None,
122 }
123}
124
125pub fn xai_static_catalog_models() -> Vec<CatalogModel> {
126 XAI_TEXT_MODELS
127 .iter()
128 .map(|descriptor| CatalogModel {
129 provider_key: "xai-auth".into(),
130 provider_name: "xAI (Grok)".into(),
131 provider_kind: CatalogProviderKind::Generic {
132 key: "xai-auth".into(),
133 },
134 id: descriptor.id.into(),
135 label: Some(descriptor.label.into()),
136 context_tokens: descriptor.context_tokens,
137 max_output_tokens: None,
138 input_modalities: vec![Modality::Text],
139 pricing: PricingSummary::default(),
140 reasoning: if descriptor.reasoning {
141 ReasoningSupport::GenericOpenAi
142 } else {
143 ReasoningSupport::None
144 },
145 source: CatalogSource::StaticFallback,
146 })
147 .collect()
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn documented_selectable_public_responses_text_ids_are_exposed() {
156 assert_eq!(
157 XAI_TEXT_MODELS.iter().map(|m| m.id).collect::<Vec<_>>(),
158 vec![
159 "grok-4.3",
160 "grok-4.3-latest",
161 "grok-latest",
162 "grok-4.20-0309-reasoning",
163 "grok-4.20-0309-non-reasoning",
164 "grok-4.20-multi-agent-0309",
165 "grok-4.5",
166 "grok-4.5-latest",
167 ]
168 );
169 }
170
171 #[test]
172 fn reasoning_metadata_is_limited_to_documented_reasoning_models() {
173 let reasoning_ids = xai_static_catalog_models()
174 .into_iter()
175 .filter(|model| model.reasoning != ReasoningSupport::None)
176 .map(|model| model.id)
177 .collect::<Vec<_>>();
178 assert_eq!(
179 reasoning_ids,
180 vec![
181 "grok-4.3",
182 "grok-4.3-latest",
183 "grok-latest",
184 "grok-4.20-0309-reasoning",
185 "grok-4.20-multi-agent-0309",
186 "grok-4.5",
187 "grok-4.5-latest",
188 ]
189 );
190 }
191
192 #[test]
195 fn grok_45_family_effort_capability_is_exact() {
196 use agent_core::reasoning::ReasoningLevel::*;
197 for id in ["grok-4.5", "grok-4.5-latest"] {
198 match xai_static_capability(id) {
199 Some(XaiReasoningCapability::Effort {
200 supported,
201 default_level,
202 can_disable,
203 }) => {
204 assert_eq!(supported, &[Low, Medium, High], "{id}");
205 assert_eq!(default_level, Some(High), "{id}");
206 assert!(!can_disable, "{id}: reasoning cannot be disabled");
207 }
208 other => panic!("{id}: expected Effort capability, got {other:?}"),
209 }
210 }
211 }
212
213 #[test]
214 fn multi_agent_supports_xhigh_but_45_does_not() {
215 use agent_core::reasoning::ReasoningLevel::*;
216 match xai_static_capability("grok-4.20-multi-agent-0309") {
217 Some(XaiReasoningCapability::Effort {
218 supported,
219 default_level,
220 can_disable,
221 }) => {
222 assert_eq!(supported, &[Low, Medium, High, XHigh]);
223 assert_eq!(default_level, None, "no documented default");
224 assert!(!can_disable);
225 }
226 other => panic!("expected Effort capability, got {other:?}"),
227 }
228 if let Some(XaiReasoningCapability::Effort { supported, .. }) =
230 xai_static_capability("grok-4.5")
231 {
232 assert!(!supported.contains(&XHigh));
233 }
234 }
235
236 #[test]
237 fn intrinsic_reasoning_models_have_no_named_effort() {
238 for id in [
239 "grok-4.3",
240 "grok-4.3-latest",
241 "grok-latest",
242 "grok-4.20-0309-reasoning",
243 ] {
244 assert_eq!(
245 xai_static_capability(id),
246 Some(XaiReasoningCapability::IntrinsicReasoning),
247 "{id}"
248 );
249 }
250 }
251
252 #[test]
253 fn non_reasoning_model_is_marked_non_reasoning() {
254 assert_eq!(
255 xai_static_capability("grok-4.20-0309-non-reasoning"),
256 Some(XaiReasoningCapability::NonReasoning)
257 );
258 }
259
260 #[test]
261 fn unknown_exact_ids_fail_closed() {
262 for id in ["grok-5", "grok-4.50", "grok-4.5x", "", "gpt-5.5"] {
263 assert_eq!(xai_static_capability(id), None, "{id}");
264 }
265 }
266
267 #[test]
268 fn catalog_is_text_only_and_excludes_unconfirmed_code_model() {
269 let models = xai_static_catalog_models();
270 assert!(models
271 .iter()
272 .all(|m| m.input_modalities == vec![Modality::Text]));
273 assert!(!models.iter().any(|m| m.id == "grok-build-0.1"));
274 assert!(!models.iter().any(|m| m.id == "grok-build-latest"));
275 assert!(!models.iter().any(|m| ["image", "video", "voice"]
276 .iter()
277 .any(|kind| m.id.contains(kind))));
278 }
279}