use super::identity::Vendor;
pub(crate) fn serves_zai(base_url: &str) -> bool {
matches!(Vendor::from_base_url(base_url), Some(Vendor::Zai))
}
pub(crate) fn tool_stream_for(base_url: &str, stream: bool) -> Option<bool> {
(stream && serves_zai(base_url)).then_some(true)
}
pub(crate) fn glm_version(model: &str) -> Option<(u32, u32)> {
let bare = super::qwen::bare_model_id(model);
let rest = bare.strip_prefix("glm-")?;
let num: String = rest
.chars()
.take_while(|c| c.is_ascii_digit() || *c == '.')
.collect();
let mut parts = num.split('.');
let major = parts.next()?.parse().ok()?;
let minor = parts.next().and_then(|m| m.parse().ok()).unwrap_or(0);
Some((major, minor))
}
fn thinking_always_on(version: (u32, u32)) -> bool {
version >= (5, 3)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct GlmThinking {
pub enabled: bool,
pub off_ignored: bool,
}
impl GlmThinking {
pub(crate) fn to_json(&self) -> serde_json::Value {
if self.enabled {
serde_json::json!({ "type": "enabled", "clear_thinking": false })
} else {
serde_json::json!({ "type": "disabled" })
}
}
}
pub(crate) fn thinking_for(
base_url: &str,
model: &str,
configured_enable_thinking: Option<bool>,
) -> Option<GlmThinking> {
if !serves_zai(base_url) {
return None;
}
let version = glm_version(model)?;
if version < (5, 0) {
return None;
}
let wants_off = configured_enable_thinking == Some(false);
if wants_off && !thinking_always_on(version) {
return Some(GlmThinking {
enabled: false,
off_ignored: false,
});
}
Some(GlmThinking {
enabled: true,
off_ignored: wants_off,
})
}
const WIRE_EFFORTS: [&str; 3] = ["low", "high", "max"];
const DEFAULT_EFFORT: &str = "max";
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct GlmEffort {
pub effort: &'static str,
pub note: Option<String>,
}
pub(crate) fn effort_for(
base_url: &str,
model: &str,
configured: Option<&str>,
) -> Option<GlmEffort> {
if !serves_zai(base_url) || !thinking_always_on(glm_version(model)?) {
return None;
}
let raw = configured?.trim();
if raw.is_empty() {
return None;
}
let lowered = raw.to_ascii_lowercase();
if let Some(rung) = WIRE_EFFORTS.iter().find(|r| **r == lowered) {
return Some(GlmEffort {
effort: rung,
note: None,
});
}
let (effort, why) = match lowered.as_str() {
"xhigh" | "highest" => ("max", "the deepest rung GLM-5.3 has is `max`"),
"medium" => (
"high",
"GLM-5.3 has no `medium`; `high` is the nearest rung",
),
"minimal" | "none" | "off" | "disabled" | "false" => (
"low",
"GLM-5.3 and later cannot turn thinking off; `low` is the shallowest rung",
),
_ => (
DEFAULT_EFFORT,
"not a GLM-5.3 rung (`low`, `high`, `max`); the endpoint falls back to `max`",
),
};
Some(GlmEffort {
effort,
note: Some(format!(
"reasoning_effort = \"{raw}\" sent as \"{effort}\" for {model}: {why}"
)),
})
}