Use the active model context limit for provider compaction

This commit is contained in:
Ryan Ward
2026-10-20 18:27:34 +00:00
parent 75b9334a0b
commit 0383166f4e
3 changed files with 62 additions and 2 deletions
+3 -2
View File
@@ -6935,8 +6935,9 @@ impl BlocklistAIController {
} }
let active_context_limit = active_run let active_context_limit = active_run
.response_config .coordinator
.max_context_tokens .current_context_limit()
.or(active_run.response_config.max_context_tokens)
.unwrap_or_else(|| { .unwrap_or_else(|| {
let preferences = LLMPreferences::as_ref(ctx); let preferences = LLMPreferences::as_ref(ctx);
configured_llm_context_limit( configured_llm_context_limit(
@@ -251,6 +251,15 @@ impl ProviderRunCoordinator {
self.profiles.get(profile).map(|profile| &profile.request) self.profiles.get(profile).map(|profile| &profile.request)
} }
/// The pending model profile owns the context budget, including after a
/// preflight overflow has returned the run to its compaction boundary.
pub(crate) fn current_context_limit(&self) -> Option<u32> {
self.profiles
.get(self.run.profile().as_str())
.and_then(|profile| profile.max_context_tokens)
.or(self.max_context_tokens)
}
/// Includes the current transcript, fixed request context, tools, and output reservation. /// Includes the current transcript, fixed request context, tools, and output reservation.
/// Read at the model boundary so newly committed tool output is included. /// Read at the model boundary so newly committed tool output is included.
pub(crate) fn estimated_context_tokens(&self) -> Option<(u32, u32)> { pub(crate) fn estimated_context_tokens(&self) -> Option<(u32, u32)> {
@@ -1558,6 +1558,56 @@ fn context_estimate_tracks_live_transcript_and_reserves_fixed_context() {
assert_eq!(fixed_before, fixed_after); assert_eq!(fixed_before, fixed_after);
} }
#[tokio::test]
async fn compaction_boundary_keeps_the_monitor_context_limit() {
let base_runtime = Arc::new(ScriptedRuntime::new(vec![]));
let cli_runtime = Arc::new(ScriptedRuntime::new(vec![]));
let run = ProviderRun::new(
"monitor-compaction-budget",
vec![ConversationMessage {
role: MessageRole::User,
content: MessageContent::Text("history".repeat(5_000)),
}],
CLI_MONITOR_PROVIDER_PROFILE,
ProviderRunLimits::default(),
);
let mut profiles = BTreeMap::new();
profiles.insert(
BASE_PROVIDER_PROFILE.to_string(),
ProviderRunProfile::new(base_runtime.clone(), request()),
);
profiles.insert(
CLI_MONITOR_PROVIDER_PROFILE.to_string(),
ProviderRunProfile::new(cli_runtime.clone(), request())
.with_max_context_tokens(Some(8_000)),
);
let mut coordinator = ProviderRunCoordinator::new(run, profiles).unwrap();
coordinator.set_max_context_tokens(Some(100_000));
let (_sender, control) = turn_control();
let block = coordinator
.drive_until_blocked(control, |_| Ok(()))
.await
.unwrap();
assert_eq!(block, ProviderRunBlock::ContextWindowExceeded);
assert_eq!(coordinator.run().state(), &ProviderRunState::ReadyToCallModel);
assert_eq!(coordinator.current_context_limit(), Some(8_000));
assert!(base_runtime.requests().is_empty());
assert!(cli_runtime.requests().is_empty());
let work_id = coordinator.run().ready_work_id().unwrap();
coordinator
.run_mut()
.continue_ready_with_observation(
&work_id,
MessageContent::Text("Command finished".to_string()),
BASE_PROVIDER_PROFILE,
)
.unwrap();
assert_eq!(coordinator.current_context_limit(), Some(100_000));
}
#[tokio::test] #[tokio::test]
async fn monitor_request_uses_its_profile_context_limit() { async fn monitor_request_uses_its_profile_context_limit() {
let base_runtime = Arc::new(ScriptedRuntime::new(vec![answer_turn()])); let base_runtime = Arc::new(ScriptedRuntime::new(vec![answer_turn()]));