mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Add new context window tool (#27488)
## Why The token budget feature tells the model how much room remains in the current context window. When the model decides the current window is no longer useful, it needs a way to ask Codex to start over with a fresh context window without spending tokens on a compaction summary. This PR adds that model-requestable escape hatch on top of #27438. ## What changed - Added a direct-model-only `new_context` tool behind `Feature::TokenBudget`. - Stores the tool request on `AutoCompactWindow` and consumes it after sampling so the next follow-up request in the same turn starts in the new window. - Starts the new window as a no-summary compaction checkpoint that contains only fresh initial context, not preserved conversation history. - Keeps the new window aligned with token-budget startup context, including the `Current context window Z` message. - Added integration coverage and a snapshot showing the same-turn `new_context` flow into a fresh full-context follow-up request. ## Validation - `just test -p codex-core token_budget`
This commit is contained in:
@@ -3058,6 +3058,44 @@ impl Session {
|
||||
state.advance_auto_compact_window_id()
|
||||
}
|
||||
|
||||
pub(crate) async fn request_new_context_window(&self) {
|
||||
let mut state = self.state.lock().await;
|
||||
state.request_new_context_window();
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_start_new_context_window(
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
) -> Option<u64> {
|
||||
let window_id = {
|
||||
let mut state = self.state.lock().await;
|
||||
state.start_new_context_window_if_requested()
|
||||
};
|
||||
let window_id = window_id?;
|
||||
let context_items = self.build_initial_context(turn_context).await;
|
||||
let turn_context_item = turn_context.to_turn_context_item();
|
||||
let replacement_history = context_items;
|
||||
{
|
||||
let mut state = self.state.lock().await;
|
||||
state.replace_history(replacement_history.clone(), Some(turn_context_item.clone()));
|
||||
};
|
||||
self.persist_rollout_items(&[
|
||||
RolloutItem::Compacted(CompactedItem {
|
||||
message: String::new(),
|
||||
replacement_history: Some(replacement_history),
|
||||
window_id: Some(window_id),
|
||||
}),
|
||||
RolloutItem::TurnContext(turn_context_item),
|
||||
])
|
||||
.await;
|
||||
{
|
||||
let mut state = self.state.lock().await;
|
||||
state.queue_pending_session_start_source(codex_hooks::SessionStartSource::Compact);
|
||||
}
|
||||
self.recompute_token_usage(turn_context).await;
|
||||
Some(window_id)
|
||||
}
|
||||
|
||||
pub(crate) async fn reference_context_item(&self) -> Option<TurnContextItem> {
|
||||
let state = self.state.lock().await;
|
||||
state.reference_context_item()
|
||||
|
||||
@@ -285,6 +285,15 @@ pub(crate) async fn run_turn(
|
||||
)
|
||||
.await;
|
||||
|
||||
let started_new_context_window = sess
|
||||
.maybe_start_new_context_window(turn_context.as_ref())
|
||||
.await
|
||||
.is_some();
|
||||
if started_new_context_window && needs_follow_up {
|
||||
can_drain_pending_input = !model_needs_follow_up;
|
||||
continue;
|
||||
}
|
||||
|
||||
// as long as compaction works well in getting us way below the token limit, we shouldn't worry about being in an infinite loop.
|
||||
if token_limit_reached && needs_follow_up {
|
||||
if let Err(err) = run_auto_compact(
|
||||
|
||||
Reference in New Issue
Block a user