use super::OpenAiClient;
use super::gateway_tests::{JSON, ONE_CHUNK, Route, SSE, Seen, muted, run, stub, turn};
use crate::entities::sampling::{ReasoningEffort, SamplingConfig};
use crate::shared::api::contract::EngineBackend;
use crate::shared::api::sse_stub::{self, BAD_REQUEST, Canned};
const GROK_4_3: &str = r#"{"id":"grok-4.3","aliases":["grok-4.3-latest"],"context_length":1000000,
"capabilities":{"reasoning_effort":["none","low","medium","high","xhigh"],"default_reasoning_effort":"low"}}"#;
const GROK_4_7: &str = r#"{"id":"grok-4.7","aliases":[],"context_length":500000,
"capabilities":{"reasoning_effort":["low","medium","high","xhigh"],"default_reasoning_effort":"high"}}"#;
const GROK_BUILD: &str =
r#"{"id":"grok-build-0.1","aliases":["grok-code-fast-1"],"context_length":256000}"#;
const NO_PARAMETER: &str = r#"{"code":"invalid-argument","error":"Model grok-build-0.1 does not support parameter reasoningEffort."}"#;
const INVALID_EFFORT: &str = r#"{"code":"invalid-argument","error":"Invalid reasoning effort."}"#;
const CHAT: Route = ("/v1/chat/completions", "200 OK", SSE, ONE_CHUNK);
fn xai(url: String, model: &str) -> OpenAiClient {
OpenAiClient::new(url)
.with_api_key(Some("k".into()))
.with_model(Some(model.into()))
.for_xai()
}
fn at(effort: ReasoningEffort) -> SamplingConfig {
SamplingConfig {
reasoning_effort: Some(effort),
..Default::default()
}
}
fn efforts(seen: &[Seen]) -> Vec<Option<String>> {
seen.iter()
.filter(|s| s.path() == "/v1/chat/completions")
.map(|s| s.json()["reasoning_effort"].as_str().map(str::to_string))
.collect()
}
fn asked_about_the_model(seen: &[Seen]) -> Vec<&str> {
seen.iter()
.map(Seen::path)
.filter(|path| *path != "/v1/chat/completions")
.collect()
}
fn words(sent: &[Option<String>]) -> Vec<&str> {
sent.iter()
.map(|e| e.as_deref().unwrap_or("-"))
.collect::<Vec<_>>()
}
#[tokio::test]
async fn a_listed_effort_goes_as_it_is_and_any_other_as_the_nearest_listed() {
const ROUTES: &[Route] = &[("/v1/models/grok-4.3", "200 OK", JSON, GROK_4_3), CHAT];
let (url, server) = stub(6, ROUTES);
let client = xai(url, "grok-4.3");
run(&client, muted()).await;
for effort in [
ReasoningEffort::Max,
ReasoningEffort::Minimal,
ReasoningEffort::High,
] {
run(&client, turn(at(effort))).await;
}
run(&client, turn(SamplingConfig::default())).await;
let seen = server.join().unwrap();
assert_eq!(asked_about_the_model(&seen), ["/v1/models/grok-4.3"]);
assert_eq!(
words(&efforts(&seen)),
["none", "xhigh", "low", "high", "-"]
);
assert_eq!(client.learned("none"), None, "a listed value is no lesson");
assert_eq!(client.learned("max"), Some(Some("xhigh")));
assert_eq!(client.learned("minimal"), Some(Some("low")));
}
#[tokio::test]
async fn a_muted_turn_asks_for_the_lowest_listed_where_none_is_not() {
const ROUTES: &[Route] = &[("/v1/models/grok-4.7", "200 OK", JSON, GROK_4_7), CHAT];
let (url, server) = stub(5, ROUTES);
let client = xai(url, "grok-4.7");
run(&client, muted()).await;
for sampling in [
at(ReasoningEffort::None),
SamplingConfig {
thinking: Some(false),
..Default::default()
},
SamplingConfig {
reasoning_budget: Some(0),
..Default::default()
},
] {
run(&client, turn(sampling)).await;
}
let seen = server.join().unwrap();
assert_eq!(words(&efforts(&seen)), ["low", "low", "low", "low"]);
assert_eq!(client.learned("none"), Some(Some("low")));
}
#[tokio::test]
async fn with_no_entry_the_measured_answers_stand() {
const ROUTES: &[Route] = &[CHAT];
let (url, server) = stub(5, ROUTES);
let client = xai(url, "grok-x");
run(&client, muted()).await;
for effort in [
ReasoningEffort::Max,
ReasoningEffort::Minimal,
ReasoningEffort::XHigh,
] {
run(&client, turn(at(effort))).await;
}
let seen = server.join().unwrap();
assert_eq!(asked_about_the_model(&seen), ["/v1/models/grok-x"]);
assert_eq!(words(&efforts(&seen)), ["-", "xhigh", "minimal", "xhigh"]);
assert_eq!(client.learned("none"), None);
assert_eq!(client.learned("max"), None);
}
#[tokio::test]
async fn an_entry_that_is_unavailable_is_asked_again() {
const ROUTES: &[Route] = &[
(
"/v1/models/grok-4.3",
"503 Service Unavailable",
JSON,
r#"{"error":"try later"}"#,
),
CHAT,
];
let (url, server) = stub(4, ROUTES);
let client = xai(url, "grok-4.3");
run(&client, muted()).await;
run(&client, muted()).await;
let seen = server.join().unwrap();
assert_eq!(
asked_about_the_model(&seen),
["/v1/models/grok-4.3", "/v1/models/grok-4.3"]
);
assert_eq!(words(&efforts(&seen)), ["-", "-"]);
}
#[tokio::test]
async fn an_alias_is_answered_by_the_models_own_route() {
const ROUTES: &[Route] = &[("/v1/models/grok-latest", "200 OK", JSON, GROK_4_7)];
let (url, server) = stub(1, ROUTES);
let client = xai(url, "grok-latest");
let caps = client.model_capabilities().await.expect("an entry");
assert_eq!(caps.context_length, Some(500_000));
assert!(client.model_capabilities().await.is_some());
assert_eq!(
asked_about_the_model(&server.join().unwrap()),
["/v1/models/grok-latest"]
);
}
#[tokio::test]
async fn a_client_not_told_it_is_xai_asks_as_chosen() {
const ROUTES: &[Route] = &[CHAT];
let (url, server) = stub(1, ROUTES);
let client = OpenAiClient::new(url)
.with_api_key(Some("k".into()))
.with_model(Some("grok-4.7".into()));
run(&client, turn(at(ReasoningEffort::Max))).await;
let seen = server.join().unwrap();
assert!(asked_about_the_model(&seen).is_empty(), "{seen:?}");
assert_eq!(words(&efforts(&seen)), ["max"]);
}
const SSE_OK: Canned = ("200 OK", SSE, ONE_CHUNK);
fn effort_in(body: &str) -> Option<String> {
let json: serde_json::Value =
serde_json::from_str(body).unwrap_or_else(|e| panic!("{e}: {body:?}"));
json["reasoning_effort"].as_str().map(str::to_string)
}
#[tokio::test]
async fn a_model_that_refuses_the_parameter_is_asked_without_it() {
const ANSWERS: &[Canned] = &[
("200 OK", JSON, GROK_BUILD),
(BAD_REQUEST, JSON, NO_PARAMETER),
SSE_OK,
SSE_OK,
SSE_OK,
];
let (url, server) = sse_stub::serve_in_turn(ANSWERS);
let client = xai(url, "grok-build-0.1");
run(&client, turn(at(ReasoningEffort::High))).await;
assert_eq!(client.learned("high"), Some(None));
run(&client, turn(at(ReasoningEffort::High))).await;
run(&client, muted()).await;
let bodies = server.join().unwrap();
let sent: Vec<Option<String>> = bodies[1..].iter().map(|b| effort_in(b)).collect();
assert_eq!(
words(&sent),
["high", "-", "-", "-"],
"the refused turn, the same turn again, the next turn, a muted one"
);
}
#[tokio::test]
async fn a_parameter_refused_twice_is_the_turns_error_and_no_lesson() {
const ANSWERS: &[Canned] = &[
("200 OK", JSON, GROK_BUILD),
(BAD_REQUEST, JSON, NO_PARAMETER),
(BAD_REQUEST, JSON, NO_PARAMETER),
];
let (url, server) = sse_stub::serve_in_turn(ANSWERS);
let client = xai(url, "grok-build-0.1");
let refused = client
.chat_stream(turn(at(ReasoningEffort::High)), Default::default())
.await
.err()
.expect("the second refusal surfaces");
assert!(refused.to_string().contains("reasoningEffort"), "{refused}");
assert_eq!(client.learned("high"), None);
assert_eq!(server.join().unwrap().len(), 3);
}
#[tokio::test]
async fn a_refused_value_is_reported_as_it_came() {
const ANSWERS: &[Canned] = &[
("200 OK", JSON, GROK_BUILD),
(BAD_REQUEST, JSON, INVALID_EFFORT),
];
let (url, server) = sse_stub::serve_in_turn(ANSWERS);
let client = xai(url, "grok-build-0.1");
let refused = client
.chat_stream(turn(at(ReasoningEffort::High)), Default::default())
.await
.err()
.expect("a refusal");
assert!(
refused.to_string().contains("Invalid reasoning effort"),
"a second request would have met a closed port instead: {refused}"
);
assert_eq!(server.join().unwrap().len(), 2);
}