Use current session settings for review threads (#36941)

## Why

Reviews may use a different model from their parent turn. They need current
thread settings without inheriting defaults resolved for the parent model.

## What changed

- Build review configuration from the parent turn context while preserving
  explicitly configured token-budget overrides.
- Use the review model's token-budget defaults and select a supported reasoning
  effort when switching models.
- Carry the session's resolved service tier and current environment,
  permissions, and approval settings into the review thread.

## Testing

Expanded review coverage for updated thread settings, model-specific
token-budget defaults, service tiers, and reasoning effort selection.

GitOrigin-RevId: cefa0f22cd9b9e28047d94e1d2d49ff83eded43e
This commit is contained in:
jif
2026-08-04 18:09:58 +00:00
committed by copyberry
parent 2b1357c27c
commit d1fb77d692
3 changed files with 177 additions and 31 deletions
+2 -1
View File
@@ -636,6 +636,7 @@ impl Session {
let model_info = models_manager
.get_model_info(model.as_str(), &config.to_models_manager_config())
.await;
let configured_config = Arc::clone(&config);
if config.config_lock_export_dir.is_some()
&& config.config_lock_save_fields_resolved_from_model_catalog
{
@@ -767,7 +768,7 @@ impl Session {
// This task will run until Op::Shutdown is received.
let session_for_loop = Arc::clone(&session);
let session_loop_handle = tokio::spawn(async move {
submission_loop(session_for_loop, config, rx_sub)
submission_loop(session_for_loop, configured_config, rx_sub)
.instrument(info_span!("session_loop", thread_id = %thread_id))
.await;
});
+24 -7
View File
@@ -45,14 +45,25 @@ pub(super) async fn spawn_review_thread(
let model_info = review_model_info.clone();
// Build per‑turn client with the requested model/family.
let mut per_turn_config = (*config).clone();
let mut per_turn_config = (*parent_turn_context.config).clone();
// Preserve configured overrides without carrying over the parent model's defaults.
per_turn_config.token_budget = config.token_budget.clone();
per_turn_config.model = Some(model.clone());
per_turn_config.features = review_features.clone();
per_turn_config.permissions = parent_turn_context.config.permissions.clone();
per_turn_config.approvals_reviewer = parent_turn_context.config.approvals_reviewer;
per_turn_config.codex_linux_sandbox_exe =
parent_turn_context.config.codex_linux_sandbox_exe.clone();
per_turn_config.compact_prompt = parent_turn_context.config.compact_prompt.clone();
if let Some(current_effort) = per_turn_config.model_reasoning_effort.as_ref()
&& review_model_info.slug != parent_turn_context.model_info.slug
&& !review_model_info.used_fallback_model_metadata
&& !review_model_info
.supported_reasoning_levels
.iter()
.any(|preset| &preset.effort == current_effort)
{
let supported_reasoning_levels = &review_model_info.supported_reasoning_levels;
per_turn_config.model_reasoning_effort = supported_reasoning_levels
.get(supported_reasoning_levels.len().saturating_sub(1) / 2)
.map(|preset| preset.effort.clone())
.or_else(|| review_model_info.default_reasoning_level.clone());
}
if let Err(err) = per_turn_config.web_search_mode.set(review_web_search_mode) {
let fallback_value = per_turn_config.web_search_mode.value();
tracing::warn!(
@@ -75,13 +86,19 @@ pub(super) async fn spawn_review_thread(
.model_reasoning_summary
.unwrap_or(model_info.default_reasoning_summary);
let session_source = parent_turn_context.session_source.clone();
let (forked_from_thread_id, thread_source) = {
let (forked_from_thread_id, thread_source, service_tier) = {
let state = sess.state.lock().await;
(
state.session_configuration.forked_from_thread_id,
state.session_configuration.thread_source.clone(),
state
.session_configuration
.service_tier
.clone()
.or_else(|| config.service_tier.clone()),
)
};
per_turn_config.service_tier = service_tier;
let per_turn_config = Arc::new(per_turn_config);
let review_turn_id = sub_id.to_string();