[codex] configure rollout budget reminder thresholds (#29423)

## Summary

Instead of:

    reminder_interval_tokens = 65_536

allow users to configure explicit remaining-token reminder thresholds:

reminder_at_remaining_tokens = [65_536, 32_768, 16_384, 8_192, 4_096,
2_048, 1_024, 512]

## Validation

- CARGO_INCREMENTAL=0 just test -p codex-core rollout_budget: 9 passed
- just fix -p codex-core
- just fmt
This commit is contained in:
rka-oai
2026-06-22 13:25:48 -07:00
committed by GitHub
Unverified
parent 5a67d898a5
commit bd5bd953fb
8 changed files with 60 additions and 41 deletions
+2 -2
View File
@@ -552,7 +552,7 @@ async fn load_config_resolves_rollout_budget() -> std::io::Result<()> {
[features.rollout_budget]
enabled = true
limit_tokens = 100000
reminder_interval_tokens = 10000
reminder_at_remaining_tokens = [50000, 25000, 10000]
sampling_token_weight = 1.0
prefill_token_weight = 0.1
"#,
@@ -571,7 +571,7 @@ prefill_token_weight = 0.1
config.rollout_budget,
Some(RolloutBudgetConfig {
limit_tokens: 100_000,
reminder_interval_tokens: 10_000,
reminder_at_remaining_tokens: vec![50_000, 25_000, 10_000],
sampling_token_weight: 1.0,
prefill_token_weight: 0.1,
})
+18 -8
View File
@@ -1098,10 +1098,10 @@ impl Default for TokenBudgetConfig {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct RolloutBudgetConfig {
pub limit_tokens: i64,
pub reminder_interval_tokens: i64,
pub reminder_at_remaining_tokens: Vec<i64>,
pub sampling_token_weight: f64,
pub prefill_token_weight: f64,
}
@@ -2606,13 +2606,23 @@ fn resolve_rollout_budget_config(
"features.rollout_budget.limit_tokens must be positive",
));
}
let reminder_interval_tokens = config
.reminder_interval_tokens
.unwrap_or_else(|| (limit_tokens / 10).max(1));
if reminder_interval_tokens <= 0 {
let reminder_at_remaining_tokens =
config
.reminder_at_remaining_tokens
.clone()
.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"features.rollout_budget.reminder_at_remaining_tokens is required when rollout_budget is enabled",
)
})?;
if reminder_at_remaining_tokens
.iter()
.any(|&tokens| tokens <= 0 || tokens >= limit_tokens)
{
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"features.rollout_budget.reminder_interval_tokens must be positive",
"features.rollout_budget.reminder_at_remaining_tokens must contain only positive values below limit_tokens",
));
}
let sampling_token_weight = config.sampling_token_weight.unwrap_or(1.0);
@@ -2630,7 +2640,7 @@ fn resolve_rollout_budget_config(
}
Ok(Some(RolloutBudgetConfig {
limit_tokens,
reminder_interval_tokens,
reminder_at_remaining_tokens,
sampling_token_weight,
prefill_token_weight,
}))
+9 -5
View File
@@ -57,18 +57,22 @@ impl RolloutBudget {
window_id: &str,
) -> Option<RolloutBudgetReminder> {
let state = self.lock()?;
let reminder_index = (state.weighted_tokens_used
/ state.config.reminder_interval_tokens as f64)
let remaining_tokens = (state.config.limit_tokens as f64 - state.weighted_tokens_used)
.max(0.0)
.floor() as i64;
let reminder_index = state
.config
.reminder_at_remaining_tokens
.iter()
.filter(|&&threshold| remaining_tokens <= threshold)
.count() as i64;
if state.deliveries.get(&thread_id).is_some_and(|delivery| {
delivery.window_id.as_str() == window_id && delivery.reminder_index >= reminder_index
}) {
return None;
}
Some(RolloutBudgetReminder {
remaining_tokens: (state.config.limit_tokens as f64 - state.weighted_tokens_used)
.max(0.0)
.floor() as i64,
remaining_tokens,
reminder_index,
})
}
+2 -2
View File
@@ -255,7 +255,7 @@ mod tests {
.expect("token_budget should be enableable in tests");
config.rollout_budget = Some(crate::config::RolloutBudgetConfig {
limit_tokens: 100_000,
reminder_interval_tokens: 10_000,
reminder_at_remaining_tokens: vec![50_000, 25_000, 10_000],
sampling_token_weight: 1.0,
prefill_token_weight: 0.25,
});
@@ -348,7 +348,7 @@ mod tests {
Some(FeatureToml::Config(RolloutBudgetConfigToml {
enabled: Some(true),
limit_tokens: Some(100_000),
reminder_interval_tokens: Some(10_000),
reminder_at_remaining_tokens: Some(vec![50_000, 25_000, 10_000]),
sampling_token_weight: Some(1.0),
prefill_token_weight: Some(0.25),
}))
+1 -1
View File
@@ -1024,7 +1024,7 @@ impl ThreadManager {
}
fn agent_control_for_config(&self, config: &Config) -> AgentControl {
AgentControl::new(Arc::downgrade(&self.state), config.rollout_budget)
AgentControl::new(Arc::downgrade(&self.state), config.rollout_budget.clone())
}
#[cfg(test)]