use codewhale_config::route::RouteLimits;
use crate::config::{ApiProvider, provider_capability};
use crate::context_budget::ContextBudget;
use crate::models::{DEFAULT_COMPACTION_TOKEN_THRESHOLD, context_window_for_model};
pub(crate) const TURN_MAX_OUTPUT_TOKENS: u32 = 262_144;
const API_MAX_OUTPUT_TOKENS: u32 = 65_536;
const INTERNAL_BUDGET_LARGE_WINDOW_THRESHOLD: u32 = 500_000;
#[must_use]
pub(crate) fn known_route_limits(limits: RouteLimits) -> Option<RouteLimits> {
limits.has_known_limit().then_some(limits)
}
#[must_use]
pub(crate) fn route_context_window_tokens(
provider: ApiProvider,
model: &str,
route_limits: Option<RouteLimits>,
) -> u32 {
route_limits
.and_then(|limits| limits.context_tokens)
.and_then(|tokens| u32::try_from(tokens).ok())
.filter(|tokens| *tokens > 0)
.unwrap_or_else(|| provider_capability(provider, model).context_window)
}
#[must_use]
pub(crate) fn route_output_limit_tokens(route_limits: Option<RouteLimits>) -> Option<u32> {
route_limits
.and_then(|limits| limits.output_tokens)
.and_then(|tokens| u32::try_from(tokens).ok())
.filter(|tokens| *tokens > 0)
}
#[must_use]
pub(crate) fn effective_max_output_tokens(model: &str) -> u32 {
if let Ok(raw) = std::env::var("CODEWHALE_MAX_OUTPUT_TOKENS")
.or_else(|_| std::env::var("DEEPSEEK_MAX_OUTPUT_TOKENS"))
&& let Ok(tokens) = raw.trim().parse::<u32>()
&& tokens > 0
{
return tokens;
}
let window = context_window_for_model(model).unwrap_or(128_000);
if window >= INTERNAL_BUDGET_LARGE_WINDOW_THRESHOLD {
API_MAX_OUTPUT_TOKENS
} else {
(window / 2).min(API_MAX_OUTPUT_TOKENS)
}
}
const UNCATALOGUED_COMPAT_MAX_OUTPUT_TOKENS: u32 = 8_192;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum OutputCeilingSource {
Documented(u32),
RouteDeclaredUnknown,
Uncatalogued(u32),
}
impl OutputCeilingSource {
#[must_use]
pub(crate) const fn clamp_tokens(self) -> Option<u32> {
match self {
Self::Documented(tokens) | Self::Uncatalogued(tokens) => Some(tokens),
Self::RouteDeclaredUnknown => None,
}
}
}
#[must_use]
fn route_declares_unknown_output_ceiling(provider: ApiProvider, model: &str) -> bool {
match provider {
ApiProvider::Ollama | ApiProvider::Sglang | ApiProvider::Vllm => true,
ApiProvider::Moonshot => crate::config::is_kimi_code_membership_model(model),
_ => false,
}
}
#[must_use]
pub(crate) fn output_ceiling_source(provider: ApiProvider, model: &str) -> OutputCeilingSource {
provider_capability(provider, model).max_output.map_or_else(
|| {
if route_declares_unknown_output_ceiling(provider, model) {
OutputCeilingSource::RouteDeclaredUnknown
} else {
OutputCeilingSource::Uncatalogued(UNCATALOGUED_COMPAT_MAX_OUTPUT_TOKENS)
}
},
OutputCeilingSource::Documented,
)
}
#[must_use]
pub(crate) fn effective_max_output_tokens_for_route(
provider: ApiProvider,
model: &str,
route_limits: Option<RouteLimits>,
) -> u32 {
let requested_cap = effective_max_output_tokens(model);
let compatibility_cap = output_ceiling_source(provider, model).clamp_tokens();
let route_cap = route_output_limit_tokens(route_limits);
let cap = compatibility_cap.map_or(requested_cap, |compat| requested_cap.min(compat));
let cap = route_cap.map_or(cap, |route_cap| cap.min(route_cap));
let Some(window) = route_limits
.and_then(|limits| limits.context_tokens)
.and_then(|tokens| u32::try_from(tokens).ok())
.filter(|tokens| *tokens > 0)
else {
return cap;
};
u32::try_from(ContextBudget::new(u64::from(window), 0, u64::from(cap)).output_cap_tokens)
.unwrap_or(cap)
.max(1)
}
#[must_use]
pub(crate) fn route_output_reservation_for_window(
provider: ApiProvider,
model: &str,
window_tokens: u32,
route_limits: Option<RouteLimits>,
) -> u32 {
if window_tokens >= INTERNAL_BUDGET_LARGE_WINDOW_THRESHOLD {
route_output_limit_tokens(route_limits).map_or(TURN_MAX_OUTPUT_TOKENS, |route_cap| {
route_cap.min(TURN_MAX_OUTPUT_TOKENS)
})
} else {
effective_max_output_tokens_for_route(provider, model, route_limits)
}
}
#[must_use]
pub(crate) fn route_context_budget(
provider: ApiProvider,
model: &str,
route_limits: Option<RouteLimits>,
input_tokens: usize,
) -> Option<ContextBudget> {
let window = route_context_window_tokens(provider, model, route_limits);
let output_cap = route_output_reservation_for_window(provider, model, window, route_limits);
Some(ContextBudget::new(
u64::from(window),
u64::try_from(input_tokens).ok()?,
u64::from(output_cap),
))
}
#[must_use]
pub(crate) fn compaction_threshold_for_route_at_percent(
provider: ApiProvider,
model: &str,
route_limits: Option<RouteLimits>,
percent: f64,
) -> usize {
route_context_budget(provider, model, route_limits, 0)
.and_then(|budget| {
usize::try_from(budget.compaction_trigger_for_percent(percent.clamp(10.0, 100.0))).ok()
})
.unwrap_or(DEFAULT_COMPACTION_TOKEN_THRESHOLD)
}
#[must_use]
pub(crate) fn auto_compact_default_for_route(
provider: ApiProvider,
model: &str,
route_limits: Option<RouteLimits>,
) -> bool {
route_context_window_tokens(provider, model, route_limits) > 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn uncatalogued_remote_model_keeps_a_conservative_ceiling() {
let source = output_ceiling_source(ApiProvider::Openai, "totally-unknown-alias-v9");
assert_eq!(
source,
OutputCeilingSource::Uncatalogued(UNCATALOGUED_COMPAT_MAX_OUTPUT_TOKENS)
);
assert_eq!(
source.clamp_tokens(),
Some(UNCATALOGUED_COMPAT_MAX_OUTPUT_TOKENS)
);
assert!(
effective_max_output_tokens_for_route(
ApiProvider::Openai,
"totally-unknown-alias-v9",
None
) <= UNCATALOGUED_COMPAT_MAX_OUTPUT_TOKENS
);
}
#[test]
fn route_declared_unknown_ceilings_are_not_clamped() {
for (provider, model) in [
(ApiProvider::Moonshot, "kimi-for-coding"),
(ApiProvider::Moonshot, "kimi-for-coding-highspeed"),
(ApiProvider::Ollama, "some-local-build"),
] {
assert_eq!(
output_ceiling_source(provider, model),
OutputCeilingSource::RouteDeclaredUnknown,
"{provider:?}/{model} must declare its unknown ceiling"
);
assert_eq!(output_ceiling_source(provider, model).clamp_tokens(), None);
}
assert_eq!(
output_ceiling_source(ApiProvider::Moonshot, "k3"),
OutputCeilingSource::Documented(131_072)
);
}
#[test]
fn codex_missing_route_metadata_uses_provider_context_floor() {
assert_eq!(
route_context_window_tokens(ApiProvider::OpenaiCodex, "gpt-5.5", None),
128_000
);
assert_eq!(
compaction_threshold_for_route_at_percent(
ApiProvider::OpenaiCodex,
"gpt-5.5",
None,
80.0,
),
98_304
);
assert!(auto_compact_default_for_route(
ApiProvider::OpenaiCodex,
"gpt-5.5",
None,
));
}
#[test]
fn v4_trigger_is_anchored_to_spendable_input() {
let budget = route_context_budget(ApiProvider::Deepseek, "deepseek-v4-pro", None, 0)
.expect("V4 route budget");
assert_eq!(budget.window_tokens, 1_000_000);
assert_eq!(budget.output_cap_tokens, u64::from(TURN_MAX_OUTPUT_TOKENS));
assert_eq!(budget.input_budget_ceiling, 736_832);
assert_eq!(
compaction_threshold_for_route_at_percent(
ApiProvider::Deepseek,
"deepseek-v4-pro",
None,
80.0,
),
589_466
);
}
#[test]
fn kimi_k3_defaults_auto_compaction_on() {
assert!(auto_compact_default_for_route(
ApiProvider::Moonshot,
"kimi-k3",
None,
));
}
#[test]
fn kimi_catalog_output_ceiling_preserves_input_budget() {
let _lock = crate::test_support::lock_test_env();
let _max_output = crate::test_support::EnvVarGuard::remove("DEEPSEEK_MAX_OUTPUT_TOKENS");
let limits = RouteLimits {
context_tokens: Some(262_144),
output_tokens: Some(262_144),
..RouteLimits::default()
};
let budget = route_context_budget(ApiProvider::Moonshot, "kimi-k2.7-code", Some(limits), 0)
.expect("Kimi route budget");
let trigger = compaction_threshold_for_route_at_percent(
ApiProvider::Moonshot,
"kimi-k2.7-code",
Some(limits),
80.0,
);
assert_eq!(budget.output_cap_tokens, 32_768);
assert_eq!(budget.input_budget_ceiling, 228_352);
assert_eq!(trigger, 182_682);
assert!(trigger as u64 <= budget.input_budget_ceiling);
assert!(
trigger < 209_715,
"must fire before the old window-relative trigger"
);
}
#[test]
fn explicit_route_output_limit_beats_unknown_model_name_fallback() {
let _lock = crate::test_support::lock_test_env();
let _max_output =
crate::test_support::EnvVarGuard::set("CODEWHALE_MAX_OUTPUT_TOKENS", "65536");
let limits = RouteLimits {
context_tokens: Some(262_144),
output_tokens: Some(24_576),
..RouteLimits::default()
};
assert_eq!(
effective_max_output_tokens_for_route(
ApiProvider::Vllm,
"arbitrary-local-wire-alias",
Some(limits),
),
24_576
);
assert_eq!(
effective_max_output_tokens_for_route(
ApiProvider::Vllm,
"arbitrary-local-wire-alias",
None,
),
65_536,
"an unknown compatibility cap must not clamp; only the requested cap applies"
);
assert_eq!(
effective_max_output_tokens_for_route(
ApiProvider::Vllm,
"kimi-k2.7-code",
Some(RouteLimits {
output_tokens: Some(262_144),
..RouteLimits::default()
}),
),
32_768,
"known model caps must remain authoritative on self-hosted routes"
);
}
#[test]
fn kimi_membership_unknown_output_cap_does_not_clamp_to_4k() {
let _lock = crate::test_support::lock_test_env();
let _codewhale = crate::test_support::EnvVarGuard::remove("CODEWHALE_MAX_OUTPUT_TOKENS");
let _deepseek = crate::test_support::EnvVarGuard::remove("DEEPSEEK_MAX_OUTPUT_TOKENS");
for model in ["kimi-for-coding", "kimi-for-coding-highspeed"] {
assert_eq!(
provider_capability(ApiProvider::Moonshot, model).max_output,
None,
"{model}: membership output ceiling must stay unknown, not a placeholder"
);
let cap = effective_max_output_tokens_for_route(ApiProvider::Moonshot, model, None);
assert_eq!(
cap,
effective_max_output_tokens(model),
"{model}: unknown compatibility cap must leave the requested cap intact"
);
assert_ne!(cap, 4_096, "{model}: must not inherit the old 4K fallback");
assert_ne!(cap, u32::MAX);
assert_ne!(cap, 32_768);
}
}
#[test]
fn kimi_membership_route_limit_still_caps_output() {
let _lock = crate::test_support::lock_test_env();
let _codewhale = crate::test_support::EnvVarGuard::remove("CODEWHALE_MAX_OUTPUT_TOKENS");
let _deepseek = crate::test_support::EnvVarGuard::remove("DEEPSEEK_MAX_OUTPUT_TOKENS");
let limits = RouteLimits {
context_tokens: Some(262_144),
output_tokens: Some(16_384),
..RouteLimits::default()
};
assert_eq!(
effective_max_output_tokens_for_route(
ApiProvider::Moonshot,
"kimi-for-coding",
Some(limits),
),
16_384
);
}
#[test]
fn known_glm_and_minimax_output_caps_remain_authoritative() {
let _lock = crate::test_support::lock_test_env();
let _codewhale = crate::test_support::EnvVarGuard::remove("CODEWHALE_MAX_OUTPUT_TOKENS");
let _deepseek = crate::test_support::EnvVarGuard::remove("DEEPSEEK_MAX_OUTPUT_TOKENS");
let glm = provider_capability(ApiProvider::Zai, "glm-5.2");
assert_eq!(glm.max_output, Some(131_072));
let minimax = provider_capability(ApiProvider::Minimax, "minimax-m3");
assert_eq!(minimax.max_output, Some(524_288));
assert_eq!(
effective_max_output_tokens_for_route(ApiProvider::Moonshot, "kimi-k2.7-code", None),
32_768,
);
}
}