[codex] add configurable token budget compaction reminder (#29255)

## Why

The token-budget feature reports coarse remaining-context milestones,
but it does not give the model a configurable wrap-up prompt before
automatic compaction. A strict threshold-crossing check can also miss
resumed or reconfigured windows that are already inside the threshold.

## What changed

- Add structured `[features.token_budget]` configuration for an absolute
`reminder_threshold_tokens` and bounded `reminder_message_template`;
`{n_remaining}` is expanded when the reminder is delivered.
- Compute remaining tokens against the next effective auto-compaction
boundary, including scoped `body_after_prefix` accounting and the full
context-window limit.
- Make reminder delivery level-triggered before and after sampling, with
one-shot state owned by `AutoCompactWindow` and re-armed on compaction,
`new_context`, restore, or history replacement.
- Leave the existing initial full-window token-budget context, 25/50/75%
notices, and token-budget tools unchanged.
- Persist the resolved feature configuration in the session config lock
and regenerate the config schema.

## Validation

- `just test -p codex-core token_budget`
- `just test -p codex-core
token_budget_reminder_emits_after_crossing_compaction_threshold`
- `just test -p codex-core auto_compact_window`
- `just test -p codex-core
lock_contains_prompts_and_materializes_features`
- `just test -p codex-features`
- `just test -p codex-config`
This commit is contained in:
pakrym-oai
2026-06-20 19:13:42 -07:00
committed by GitHub
parent b6d6be2a84
commit 6df037d47f
15 changed files with 418 additions and 27 deletions
+1
View File
@@ -73,6 +73,7 @@ pub(crate) use rollout_budget::RolloutBudgetContext;
pub(crate) use subagent_notification::SubagentNotification;
pub(crate) use token_budget_context::TokenBudgetContext;
pub(crate) use token_budget_context::TokenBudgetRemainingContext;
pub(crate) use token_budget_context::TokenBudgetReminder;
pub(crate) use turn_aborted::TurnAborted;
pub(crate) use user_instructions::UserInstructions;
pub(crate) use user_shell_command::UserShellCommand;
@@ -99,3 +99,34 @@ impl ContextualUserFragment for TokenBudgetRemainingContext {
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct TokenBudgetReminder {
message: String,
}
impl TokenBudgetReminder {
pub(crate) fn new(message_template: &str, n_remaining: i64) -> Self {
Self {
message: message_template.replace("{n_remaining}", &n_remaining.to_string()),
}
}
}
impl ContextualUserFragment for TokenBudgetReminder {
fn role(&self) -> &'static str {
"developer"
}
fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers()
}
fn type_markers() -> (&'static str, &'static str) {
("<token_budget>\n", "\n</token_budget>")
}
fn body(&self) -> String {
self.message.clone()
}
}