mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Snapshot resolved settings for each model step (#40651)
## Why Thread settings can change while a turn is running, and delegated review or compaction steps can select a different model. Each request needs a consistent set of settings resolved against the model that will execute it. ## What changed - Capture immutable resolved settings for each model step, including model metadata, reasoning options, service tier, approvals, and personality. - Keep in-flight steps on their captured settings while applying thread updates to subsequent work. - Resolve inherited reasoning summaries and filter service tiers against the selected model and feature configuration for review and compaction steps. ## Testing Added coverage for settings updates during paused turns, model changes, previous-model compaction, review-model defaults, and service-tier filtering. GitOrigin-RevId: fca4b3b305379f1bf26a5cac75ee0dd1747ac1f6
This commit is contained in:
1 parent
ba6cf9c692
commit
68301fa45f
68 files changed
+1393
-516
No files matched your search
@@ -1,4 +1,6 @@
|
||||
use super::step_settings::ResolvedStepSettings;
|
||||
use super::*;
|
||||
use arc_swap::ArcSwap;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// Spawn a review thread using the given prompt.
|
||||
@@ -12,7 +14,7 @@ pub(super) async fn spawn_review_thread(
|
||||
let model = config
|
||||
.review_model
|
||||
.clone()
|
||||
.unwrap_or_else(|| parent_turn_context.model_info.slug.clone());
|
||||
.unwrap_or_else(|| parent_turn_context.model_info().slug.clone());
|
||||
let available_models = sess
|
||||
.services
|
||||
.models_manager
|
||||
@@ -43,15 +45,16 @@ pub(super) async fn spawn_review_thread(
|
||||
let provider = parent_turn_context.provider.clone();
|
||||
let auth_manager = parent_turn_context.auth_manager.clone();
|
||||
let model_info = review_model_info.clone();
|
||||
let mut selected = parent_turn_context.initial_settings.selected().clone();
|
||||
let mut reasoning_effort = selected.collaboration_mode.reasoning_effort();
|
||||
|
||||
// Build per‑turn client with the requested model/family.
|
||||
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();
|
||||
if let Some(current_effort) = per_turn_config.model_reasoning_effort.as_ref()
|
||||
&& review_model_info.slug != parent_turn_context.model_info.slug
|
||||
if let Some(current_effort) = 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
|
||||
@@ -59,7 +62,7 @@ pub(super) async fn spawn_review_thread(
|
||||
.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
|
||||
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());
|
||||
@@ -74,17 +77,8 @@ pub(super) async fn spawn_review_thread(
|
||||
);
|
||||
}
|
||||
|
||||
let session_telemetry = parent_turn_context
|
||||
.session_telemetry
|
||||
.clone()
|
||||
.with_model(model.as_str(), review_model_info.slug.as_str());
|
||||
let auth_manager_for_context = auth_manager.clone();
|
||||
let provider_for_context = provider.clone();
|
||||
let session_telemetry_for_context = session_telemetry.clone();
|
||||
let reasoning_effort = per_turn_config.model_reasoning_effort.clone();
|
||||
let reasoning_summary = per_turn_config
|
||||
.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, service_tier) = {
|
||||
let state = sess.state.lock().await;
|
||||
@@ -99,12 +93,25 @@ pub(super) async fn spawn_review_thread(
|
||||
.or_else(|| config.service_tier.clone()),
|
||||
)
|
||||
};
|
||||
per_turn_config.service_tier = service_tier;
|
||||
|
||||
let auto_review_enabled = crate::guardian::routes_approval_policy_to_guardian(
|
||||
per_turn_config.permissions.approval_policy.value(),
|
||||
per_turn_config.approvals_reviewer,
|
||||
);
|
||||
// The original config may retain a requested tier unsupported by the parent
|
||||
// model. Resolve it against the review model and the shared feature gate.
|
||||
selected.collaboration_mode.settings.model = model.clone();
|
||||
selected.collaboration_mode.settings.reasoning_effort = reasoning_effort.clone();
|
||||
selected.service_tier = service_tier;
|
||||
let step_settings = Arc::new(ResolvedStepSettings::new(
|
||||
Arc::new(selected),
|
||||
Arc::new(model_info.clone()),
|
||||
review_features.enabled(Feature::FastMode),
|
||||
));
|
||||
per_turn_config.model = Some(model);
|
||||
per_turn_config.model_reasoning_effort = reasoning_effort;
|
||||
per_turn_config.service_tier = step_settings.service_tier.clone();
|
||||
let session_telemetry_for_context =
|
||||
step_settings.telemetry(&parent_turn_context.session_telemetry);
|
||||
let per_turn_config = Arc::new(per_turn_config);
|
||||
let review_turn_id = sub_id.to_string();
|
||||
let turn_metadata_state = Arc::new(TurnMetadataState::new(
|
||||
@@ -139,11 +146,10 @@ pub(super) async fn spawn_review_thread(
|
||||
code_mode_available: parent_turn_context.code_mode_available,
|
||||
config: per_turn_config,
|
||||
auth_manager: auth_manager_for_context,
|
||||
model_info: Arc::new(model_info.clone()),
|
||||
initial_settings: Arc::clone(&step_settings),
|
||||
current_settings: ArcSwap::from(step_settings),
|
||||
session_telemetry: session_telemetry_for_context,
|
||||
provider: provider_for_context,
|
||||
reasoning_effort,
|
||||
reasoning_summary,
|
||||
session_source,
|
||||
history_mode: parent_turn_context.history_mode,
|
||||
parent_thread_id: parent_turn_context.parent_thread_id,
|
||||
@@ -155,12 +161,7 @@ pub(super) async fn spawn_review_thread(
|
||||
timezone: parent_turn_context.timezone.clone(),
|
||||
app_server_client_name: parent_turn_context.app_server_client_name.clone(),
|
||||
developer_instructions: None,
|
||||
mode: parent_turn_context.mode,
|
||||
collaboration_mode_developer_instructions: parent_turn_context
|
||||
.collaboration_mode_developer_instructions
|
||||
.clone(),
|
||||
multi_agent_version: MultiAgentVersion::Disabled,
|
||||
personality: parent_turn_context.personality,
|
||||
network: parent_turn_context.network.clone(),
|
||||
windows_sandbox_level: parent_turn_context.windows_sandbox_level,
|
||||
#[allow(deprecated)]
|
||||
@@ -191,7 +192,8 @@ pub(super) async fn spawn_review_thread(
|
||||
// TODO(ccunningham): Review turns currently rely on `spawn_task` for TurnComplete but do not
|
||||
// emit a parent TurnStarted. Consider giving review a full parent turn lifecycle
|
||||
// (TurnStarted + TurnComplete) for consistency with other standalone tasks.
|
||||
sess.spawn_task(tc.clone(), input, ReviewTask::new()).await;
|
||||
sess.spawn_task(Arc::clone(&tc), input, ReviewTask::new())
|
||||
.await;
|
||||
|
||||
// Announce entering review mode so UIs can switch modes.
|
||||
let item = TurnItem::EnteredReviewMode(EnteredReviewModeItem {
|
||||
|
||||
Reference in new issue
Block a user