mirror of
https://github.com/openai/codex.git
synced 2026-11-13 06:45:07 +00:00
Roll over Guardian context before follow-up reviews (#41215)
## Why Long-lived Guardian sessions can exhaust the review model's context window. After a rollover, a transcript delta is insufficient because the new window no longer contains the original transcript or persistent review instructions. ## What changed - Compact an exhausted Guardian session before submitting the next review while respecting the review model's token-budget configuration. - Detect whether the full transcript remains in the reviewer history. If it does not, reset transcript and Node REPL evidence cursors so the next review replays the complete transcript and associated image evidence. - Restore the follow-up reminder and Node REPL policy when compaction removes them. ## Testing - Cover rollover both when the reviewer window is already exhausted and when a follow-up reminder crosses the limit. - Verify that multimodal reviews preserve the fallback buffer and replay browser evidence after rollover. GitOrigin-RevId: f2a02a84e1f25d15c6e2b8eddb93e2d1805449f5
This commit is contained in:
1 parent
f6494dc8f5
commit
bae69125df
5 files changed
+405
-88
No files matched your search
@@ -1,6 +1,8 @@
|
||||
use super::session::Session;
|
||||
use super::turn_context::TurnContext;
|
||||
use crate::config::Config;
|
||||
use codex_protocol::config_types::AutoCompactTokenLimitScope;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ContextWindowTokenStatus {
|
||||
@@ -23,25 +25,47 @@ fn tokens_remaining(limit: Option<i64>, used: i64) -> Option<i64> {
|
||||
pub(crate) async fn context_window_token_status(
|
||||
sess: &Session,
|
||||
turn_context: &TurnContext,
|
||||
) -> ContextWindowTokenStatus {
|
||||
context_window_token_status_with_config(
|
||||
sess,
|
||||
turn_context.config.as_ref(),
|
||||
turn_context.model_info().as_ref(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn context_window_token_status_for_model(
|
||||
sess: &Session,
|
||||
config: &Config,
|
||||
model_info: &ModelInfo,
|
||||
) -> ContextWindowTokenStatus {
|
||||
let mut config = config.clone();
|
||||
super::token_budget::apply_model_defaults(&mut config, model_info);
|
||||
context_window_token_status_with_config(sess, &config, model_info).await
|
||||
}
|
||||
|
||||
async fn context_window_token_status_with_config(
|
||||
sess: &Session,
|
||||
config: &Config,
|
||||
model_info: &ModelInfo,
|
||||
) -> ContextWindowTokenStatus {
|
||||
let active_context_tokens = sess.get_total_token_usage().await;
|
||||
|
||||
// Count either the full active context or only the tokens added after the initial prefix.
|
||||
let (auto_compact_scope_tokens, auto_compact_scope_limit, auto_compact_window_prefill_tokens) =
|
||||
match turn_context.config.model_auto_compact_token_limit_scope {
|
||||
match config.model_auto_compact_token_limit_scope {
|
||||
AutoCompactTokenLimitScope::Total => (
|
||||
active_context_tokens,
|
||||
turn_context.model_info().auto_compact_token_limit(),
|
||||
model_info.auto_compact_token_limit(),
|
||||
None,
|
||||
),
|
||||
AutoCompactTokenLimitScope::BodyAfterPrefix => {
|
||||
let window = sess.auto_compact_window_snapshot().await;
|
||||
let baseline = window.prefill_input_tokens.unwrap_or(active_context_tokens);
|
||||
|
||||
let scope_limit = turn_context
|
||||
.config
|
||||
let scope_limit = config
|
||||
.model_auto_compact_token_limit
|
||||
.or_else(|| turn_context.model_info().auto_compact_token_limit());
|
||||
.or_else(|| model_info.auto_compact_token_limit());
|
||||
(
|
||||
active_context_tokens.saturating_sub(baseline),
|
||||
scope_limit,
|
||||
@@ -51,7 +75,9 @@ pub(crate) async fn context_window_token_status(
|
||||
};
|
||||
|
||||
// The model's full context window is a hard cap, independent of the auto-compaction scope.
|
||||
let full_context_window_limit = turn_context.model_context_window();
|
||||
let full_context_window_limit = model_info.resolved_context_window().map(|context_window| {
|
||||
context_window.saturating_mul(model_info.effective_context_window_percent) / 100
|
||||
});
|
||||
|
||||
// Report remaining tokens against the base (unbuffered) window, capped by the full context.
|
||||
let base_window_tokens_remaining = [
|
||||
@@ -63,8 +89,7 @@ pub(crate) async fn context_window_token_status(
|
||||
.min();
|
||||
|
||||
// Only reserve the fallback buffer when there is a fallback prompt to use it.
|
||||
let auto_compact_fallback_buffer_tokens = turn_context
|
||||
.config
|
||||
let auto_compact_fallback_buffer_tokens = config
|
||||
.token_budget
|
||||
.as_ref()
|
||||
.map_or(0, crate::config::TokenBudgetConfig::fallback_buffer_tokens);
|
||||
|
||||
Reference in new issue
Block a user