This commit is contained in:
Ahmed Ibrahim
2026-02-08 21:55:43 -08:00
parent 1bef42a91b
commit aa992daf3c
5 changed files with 41 additions and 9 deletions

View File

@@ -539,10 +539,7 @@ pub(crate) struct TurnContext {
}
impl TurnContext {
pub(crate) fn model_context_window(&self) -> Option<i64> {
let effective_context_window_percent = self.model_info.effective_context_window_percent;
self.model_info.context_window.map(|context_window| {
context_window.saturating_mul(effective_context_window_percent) / 100
})
effective_model_context_window(&self.model_info)
}
pub(crate) fn resolve_path(&self, path: Option<String>) -> PathBuf {
@@ -684,6 +681,13 @@ impl SessionConfiguration {
}
}
fn effective_model_context_window(model_info: &ModelInfo) -> Option<i64> {
let effective_context_window_percent = model_info.effective_context_window_percent;
model_info
.context_window
.map(|context_window| context_window.saturating_mul(effective_context_window_percent) / 100)
}
#[derive(Default, Clone)]
pub(crate) struct SessionSettingsUpdate {
pub(crate) cwd: Option<PathBuf>,
@@ -1044,10 +1048,14 @@ impl Session {
}
};
session_configuration.thread_name = thread_name.clone();
let model_info = models_manager
.get_model_info(session_configuration.collaboration_mode.model(), &config)
.await;
let state = SessionState::new(
session_configuration.clone(),
conversation_id.to_string(),
config.codex_home.clone(),
effective_model_context_window(&model_info),
);
let services = SessionServices {
@@ -2036,6 +2044,7 @@ impl Session {
let mut history = ContextManager::new(
Arc::new(self.conversation_id.to_string()),
Arc::new(turn_context.config.codex_home.clone()),
turn_context.model_context_window(),
);
for item in rollout_items {
match item {
@@ -5529,6 +5538,7 @@ mod tests {
session_configuration,
conversation_id.to_string(),
config.codex_home.clone(),
effective_model_context_window(&model_info),
);
let initial = RateLimitSnapshot {
primary: Some(RateLimitWindow {
@@ -5617,6 +5627,7 @@ mod tests {
session_configuration,
conversation_id.to_string(),
config.codex_home.clone(),
effective_model_context_window(&model_info),
);
let initial = RateLimitSnapshot {
primary: Some(RateLimitWindow {
@@ -5906,6 +5917,7 @@ mod tests {
session_configuration.clone(),
conversation_id.to_string(),
config.codex_home.clone(),
effective_model_context_window(&model_info),
);
mark_state_initial_context_seeded(&mut state);
let skills_manager = Arc::new(SkillsManager::new(config.codex_home.clone()));
@@ -6042,6 +6054,7 @@ mod tests {
session_configuration.clone(),
conversation_id.to_string(),
config.codex_home.clone(),
effective_model_context_window(&model_info),
);
mark_state_initial_context_seeded(&mut state);
let skills_manager = Arc::new(SkillsManager::new(config.codex_home.clone()));
@@ -6544,6 +6557,7 @@ mod tests {
let mut live_history = ContextManager::new(
Arc::new(session.conversation_id.to_string()),
Arc::new(turn_context.config.codex_home.clone()),
turn_context.model_context_window(),
);
let initial_context = session.build_initial_context(turn_context).await;

View File

@@ -92,8 +92,7 @@ impl ContextDiscoverable for Message {
};
let estimated_tokens = i64::try_from(approx_token_count(&user_text)).unwrap_or(i64::MAX);
let offload_threshold = context_window_tokens.saturating_mul(95) / 100;
if current_usage_tokens.saturating_add(estimated_tokens) <= offload_threshold {
if current_usage_tokens.saturating_add(estimated_tokens) <= context_window_tokens {
return ResponseItem::Message(self.clone());
}

View File

@@ -29,10 +29,14 @@ pub(crate) struct ContextManager {
}
impl ContextManager {
pub(crate) fn new(thread_id: Arc<String>, codex_home: Arc<PathBuf>) -> Self {
pub(crate) fn new(
thread_id: Arc<String>,
codex_home: Arc<PathBuf>,
model_context_window: Option<i64>,
) -> Self {
Self {
items: Vec::new(),
token_info: TokenUsageInfo::new_or_append(&None, &None, None),
token_info: TokenUsageInfo::new_or_append(&None, &None, model_context_window),
thread_id,
codex_home,
}

View File

@@ -39,6 +39,7 @@ fn create_history_with_items(items: Vec<ResponseItem>) -> ContextManager {
let mut h = ContextManager::new(
Arc::new("test-thread".to_string()),
Arc::new(PathBuf::from("/tmp/test-codex-home")),
None,
);
// Use a generous but fixed token budget; tests only rely on truncation
// behavior, not on a specific model's token limit.
@@ -139,6 +140,7 @@ fn filters_non_api_messages() {
let mut h = ContextManager::new(
Arc::new("test-thread".to_string()),
Arc::new(PathBuf::from("/tmp/test-codex-home")),
None,
);
let policy = TruncationPolicy::Tokens(10_000);
// System message is not API messages; Other is ignored.
@@ -622,6 +624,7 @@ fn record_items_truncates_function_call_output_content() {
let mut history = ContextManager::new(
Arc::new("test-thread".to_string()),
Arc::new(PathBuf::from("/tmp/test-codex-home")),
None,
);
// Any reasonably small token budget works; the test only cares that
// truncation happens and the marker is present.
@@ -664,6 +667,7 @@ fn record_items_truncates_custom_tool_call_output_content() {
let mut history = ContextManager::new(
Arc::new("test-thread".to_string()),
Arc::new(PathBuf::from("/tmp/test-codex-home")),
None,
);
let policy = TruncationPolicy::Tokens(1_000);
let line = "custom output that is very long\n";
@@ -700,6 +704,7 @@ fn record_items_respects_custom_token_limit() {
let mut history = ContextManager::new(
Arc::new("test-thread".to_string()),
Arc::new(PathBuf::from("/tmp/test-codex-home")),
None,
);
let policy = TruncationPolicy::Tokens(10);
let long_output = "tokenized content repeated many times ".repeat(200);
@@ -733,6 +738,7 @@ fn record_items_with_discoverability_offloads_large_user_message() {
let mut history = ContextManager::new(
Arc::new("thread-1".to_string()),
Arc::new(codex_home.path().to_path_buf()),
None,
);
let policy = TruncationPolicy::Tokens(10_000);
let large_text = "large user prompt ".repeat(200);
@@ -766,6 +772,7 @@ fn record_items_with_discoverability_keeps_small_user_message_in_history() {
let mut history = ContextManager::new(
Arc::new("thread-2".to_string()),
Arc::new(codex_home.path().to_path_buf()),
None,
);
let policy = TruncationPolicy::Tokens(10_000);
let item = user_input_text_msg("small prompt");
@@ -782,6 +789,7 @@ fn record_items_with_discoverability_does_not_change_non_user_messages() {
let mut history = ContextManager::new(
Arc::new("thread-3".to_string()),
Arc::new(codex_home.path().to_path_buf()),
None,
);
let policy = TruncationPolicy::Tokens(10_000);
let item = assistant_msg(&"assistant reply ".repeat(300));
@@ -798,6 +806,7 @@ fn record_items_with_discoverability_ignores_image_only_user_messages() {
let mut history = ContextManager::new(
Arc::new("thread-4".to_string()),
Arc::new(codex_home.path().to_path_buf()),
None,
);
let policy = TruncationPolicy::Tokens(10_000);
let item = ResponseItem::Message(codex_protocol::models::Message {
@@ -822,6 +831,7 @@ fn record_items_with_discoverability_offloads_once_above_ninety_five_percent_win
let mut history = ContextManager::new(
Arc::new("thread-95".to_string()),
Arc::new(codex_home.path().to_path_buf()),
None,
);
let policy = TruncationPolicy::Tokens(10_000);
let text = "near context threshold ".repeat(100);

View File

@@ -36,8 +36,13 @@ impl SessionState {
session_configuration: SessionConfiguration,
thread_id: String,
codex_home: PathBuf,
model_context_window: Option<i64>,
) -> Self {
let history = ContextManager::new(Arc::new(thread_id), Arc::new(codex_home));
let history = ContextManager::new(
Arc::new(thread_id),
Arc::new(codex_home),
model_context_window,
);
Self {
session_configuration,
history,