[codex] Support model-defined reasoning efforts (#26444)

## Summary
- accept non-empty model-defined reasoning effort values while
preserving built-in effort behavior
- propagate the non-Copy effort type through core, app-server, TUI,
telemetry, and persistence call sites
- preserve string wire encoding and expose an open-string schema for
clients
- update model selection and shortcut behavior for model-advertised
effort values

## Root cause
`ReasoningEffort` gained a string-backed custom variant, so it could no
longer implement `Copy` or rely on derived closed-enum serialization.
Existing consumers still moved effort values from shared references and
assumed a fixed built-in value set.

## Validation
- `just fmt`
- Local tests and compilation were not run per request; relying on CI.
This commit is contained in:
Ahmed Ibrahim
2026-06-04 13:36:24 -07:00
committed by GitHub
parent 4a70e0ac1b
commit 8ac304c299
97 changed files with 685 additions and 581 deletions
+4 -4
View File
@@ -721,7 +721,7 @@ impl ModelClient {
) -> Option<Reasoning> {
if model_info.supports_reasoning_summaries {
Some(Reasoning {
effort: effort.or(model_info.default_reasoning_level),
effort: effort.or_else(|| model_info.default_reasoning_level.clone()),
summary: if summary == ReasoningSummaryConfig::None {
None
} else {
@@ -1267,7 +1267,7 @@ impl ModelClientSession {
&client_setup.api_provider,
prompt,
model_info,
effort,
effort.clone(),
summary,
service_tier.clone(),
)?;
@@ -1376,7 +1376,7 @@ impl ModelClientSession {
&client_setup.api_provider,
prompt,
model_info,
effort,
effort.clone(),
summary,
service_tier.clone(),
)?;
@@ -1595,7 +1595,7 @@ impl ModelClientSession {
prompt,
model_info,
session_telemetry,
effort,
effort.clone(),
summary,
service_tier.clone(),
turn_metadata_header,
+1 -1
View File
@@ -573,7 +573,7 @@ async fn drain_to_completed(
prompt,
&turn_context.model_info,
&turn_context.session_telemetry,
turn_context.reasoning_effort,
turn_context.reasoning_effort.clone(),
turn_context.reasoning_summary,
turn_context.config.service_tier.clone(),
turn_metadata_header,
+1 -1
View File
@@ -242,7 +242,7 @@ async fn run_remote_compact_task_inner_impl(
&prompt,
&turn_context.model_info,
CompactConversationRequestSettings {
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: turn_context.reasoning_summary,
service_tier: if sess.services.auth_manager.auth_mode() == Some(AuthMode::ApiKey) {
None
+1 -1
View File
@@ -339,7 +339,7 @@ async fn run_remote_compaction_request_v2(
prompt,
&turn_context.model_info,
&turn_context.session_telemetry,
turn_context.reasoning_effort,
turn_context.reasoning_effort.clone(),
turn_context.reasoning_summary,
turn_context.config.service_tier.clone(),
turn_metadata_header,
+1 -1
View File
@@ -225,7 +225,7 @@ impl ConfigDocument {
);
mutated |= self.write_optional_value(
&["model_reasoning_effort"],
effort.map(|effort| value(effort.to_string())),
effort.as_ref().map(|effort| value(effort.to_string())),
);
mutated
}),
+4 -3
View File
@@ -702,7 +702,7 @@ pub(super) async fn run_guardian_review_session(
.supported_reasoning_efforts
.iter()
.any(|effort| effort.effort == codex_protocol::openai_models::ReasoningEffort::Low),
Some(preset.default_reasoning_effort),
Some(preset.default_reasoning_effort.clone()),
);
(review_model_id.to_string(), reasoning_effort)
} else {
@@ -712,7 +712,8 @@ pub(super) async fn run_guardian_review_session(
.iter()
.any(|preset| preset.effort == codex_protocol::openai_models::ReasoningEffort::Low),
turn.reasoning_effort
.or(turn.model_info.default_reasoning_level),
.clone()
.or_else(|| turn.model_info.default_reasoning_level.clone()),
);
(
model_override
@@ -725,7 +726,7 @@ pub(super) async fn run_guardian_review_session(
turn.config.as_ref(),
live_network_config.clone(),
guardian_model.as_str(),
guardian_reasoning_effort,
guardian_reasoning_effort.clone(),
);
let guardian_config = match guardian_config {
Ok(config) => config,
+6 -5
View File
@@ -167,7 +167,7 @@ impl GuardianReviewSessionReuseKey {
model_context_window: spawn_config.model_context_window,
model_auto_compact_token_limit: spawn_config.model_auto_compact_token_limit,
model_auto_compact_token_limit_scope: spawn_config.model_auto_compact_token_limit_scope,
model_reasoning_effort: spawn_config.model_reasoning_effort,
model_reasoning_effort: spawn_config.model_reasoning_effort.clone(),
model_reasoning_summary: spawn_config.model_reasoning_summary,
permissions: spawn_config.permissions.clone(),
developer_instructions: spawn_config.developer_instructions.clone(),
@@ -658,7 +658,8 @@ async fn run_review_on_session(
let guardian_reasoning_effort = if model_info.supports_reasoning_summaries {
params
.reasoning_effort
.or(model_info.default_reasoning_level)
.clone()
.or_else(|| model_info.default_reasoning_level.clone())
} else {
None
};
@@ -742,7 +743,7 @@ async fn run_review_on_session(
mode: codex_protocol::config_types::ModeKind::Default,
settings: codex_protocol::config_types::Settings {
model: params.model.clone(),
reasoning_effort: params.reasoning_effort,
reasoning_effort: params.reasoning_effort.clone(),
developer_instructions: None,
},
}),
@@ -1107,7 +1108,7 @@ mod tests {
async fn test_review_params() -> GuardianReviewSessionParams {
let (session, turn) = crate::session::tests::make_session_and_context().await;
let model = turn.model_info.slug.clone();
let reasoning_effort = turn.reasoning_effort;
let reasoning_effort = turn.reasoning_effort.clone();
let reasoning_summary = turn.reasoning_summary;
let personality = turn.personality;
#[allow(deprecated)]
@@ -1116,7 +1117,7 @@ mod tests {
turn.config.as_ref(),
/*live_network_config*/ None,
model.as_str(),
reasoning_effort,
reasoning_effort.clone(),
)
.expect("guardian config");
+1 -1
View File
@@ -129,7 +129,7 @@ fn save_config_resolved_fields(
) -> anyhow::Result<()> {
lock_config.web_search = Some(config.web_search_mode.value());
lock_config.model_provider = Some(config.model_provider_id.clone());
lock_config.plan_mode_reasoning_effort = config.plan_mode_reasoning_effort;
lock_config.plan_mode_reasoning_effort = config.plan_mode_reasoning_effort.clone();
lock_config.model_verbosity = config.model_verbosity;
lock_config.include_permissions_instructions = Some(config.include_permissions_instructions);
lock_config.include_apps_instructions = Some(config.include_apps_instructions);
+1 -1
View File
@@ -579,7 +579,7 @@ impl Codex {
mode: ModeKind::Default,
settings: Settings {
model: model.clone(),
reasoning_effort: config.model_reasoning_effort,
reasoning_effort: config.model_reasoning_effort.clone(),
developer_instructions: None,
},
};
+1 -1
View File
@@ -74,7 +74,7 @@ pub(super) async fn spawn_review_thread(
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;
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);
@@ -74,7 +74,7 @@ async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previ
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let rollout_items = vec![RolloutItem::TurnContext(previous_context_item)];
@@ -113,7 +113,7 @@ async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lif
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let turn_id = previous_context_item
@@ -963,7 +963,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
@@ -1042,7 +1042,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
}))
.expect("serialize expected reference context item")
@@ -1071,7 +1071,7 @@ async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_tu
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
@@ -1190,7 +1190,7 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
@@ -1308,7 +1308,7 @@ async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clea
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
@@ -1467,7 +1467,7 @@ async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clear
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let previous_turn_id = previous_context_item
+10 -10
View File
@@ -2559,7 +2559,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
multi_agent_version: None,
realtime_active: Some(turn_context.realtime_active),
effort: turn_context.reasoning_effort,
effort: turn_context.reasoning_effort.clone(),
summary: codex_protocol::config_types::ReasoningSummary::Auto,
};
let turn_id = previous_context_item
@@ -3146,7 +3146,7 @@ async fn set_rate_limits_retains_previous_credits() {
let model = get_model_offline_for_tests(config.model.as_deref());
let model_info =
construct_model_info_offline_for_tests(model.as_str(), &config.to_models_manager_config());
let reasoning_effort = config.model_reasoning_effort;
let reasoning_effort = config.model_reasoning_effort.clone();
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
settings: Settings {
@@ -3254,7 +3254,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
let model = get_model_offline_for_tests(config.model.as_deref());
let model_info =
construct_model_info_offline_for_tests(model.as_str(), &config.to_models_manager_config());
let reasoning_effort = config.model_reasoning_effort;
let reasoning_effort = config.model_reasoning_effort.clone();
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
settings: Settings {
@@ -3785,7 +3785,7 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
let model = get_model_offline_for_tests(config.model.as_deref());
let model_info =
construct_model_info_offline_for_tests(model.as_str(), &config.to_models_manager_config());
let reasoning_effort = config.model_reasoning_effort;
let reasoning_effort = config.model_reasoning_effort.clone();
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
settings: Settings {
@@ -4614,7 +4614,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_packaged_zsh() {
mode: ModeKind::Default,
settings: Settings {
model,
reasoning_effort: config.model_reasoning_effort,
reasoning_effort: config.model_reasoning_effort.clone(),
developer_instructions: None,
},
};
@@ -4716,7 +4716,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
let model = get_model_offline_for_tests(config.model.as_deref());
let model_info =
construct_model_info_offline_for_tests(model.as_str(), &config.to_models_manager_config());
let reasoning_effort = config.model_reasoning_effort;
let reasoning_effort = config.model_reasoning_effort.clone();
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
settings: Settings {
@@ -4959,7 +4959,7 @@ async fn make_session_with_config_and_rx(
mode: ModeKind::Default,
settings: Settings {
model,
reasoning_effort: config.model_reasoning_effort,
reasoning_effort: config.model_reasoning_effort.clone(),
developer_instructions: None,
},
};
@@ -5064,7 +5064,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
mode: ModeKind::Default,
settings: Settings {
model,
reasoning_effort: config.model_reasoning_effort,
reasoning_effort: config.model_reasoning_effort.clone(),
developer_instructions: None,
},
};
@@ -5999,7 +5999,7 @@ async fn user_turn_updates_approvals_reviewer() {
mode: codex_protocol::config_types::ModeKind::Default,
settings: codex_protocol::config_types::Settings {
model: turn_context.model_info.slug.clone(),
reasoning_effort: config.model_reasoning_effort,
reasoning_effort: config.model_reasoning_effort.clone(),
developer_instructions: None,
},
}),
@@ -6806,7 +6806,7 @@ where
let model = get_model_offline_for_tests(config.model.as_deref());
let model_info =
construct_model_info_offline_for_tests(model.as_str(), &config.to_models_manager_config());
let reasoning_effort = config.model_reasoning_effort;
let reasoning_effort = config.model_reasoning_effort.clone();
let collaboration_mode = CollaborationMode {
mode: ModeKind::Default,
settings: Settings {
+2 -2
View File
@@ -698,7 +698,7 @@ async fn track_turn_resolved_config_analytics(
permission_profile: turn_context.permission_profile(),
#[allow(deprecated)]
permission_profile_cwd: turn_context.cwd.to_path_buf(),
reasoning_effort: turn_context.reasoning_effort,
reasoning_effort: turn_context.reasoning_effort.clone(),
reasoning_summary: Some(turn_context.reasoning_summary),
service_tier: turn_context
.config
@@ -1799,7 +1799,7 @@ async fn try_run_sampling_request(
prompt,
&turn_context.model_info,
&turn_context.session_telemetry,
turn_context.reasoning_effort,
turn_context.reasoning_effort.clone(),
turn_context.reasoning_summary,
turn_context.config.service_tier.clone(),
turn_metadata_header,
+12 -10
View File
@@ -136,7 +136,8 @@ impl TurnContext {
pub(crate) fn effective_reasoning_effort(&self) -> Option<ReasoningEffortConfig> {
if self.model_info.supports_reasoning_summaries {
self.reasoning_effort
.or(self.model_info.default_reasoning_level)
.clone()
.or_else(|| self.model_info.default_reasoning_level.clone())
} else {
None
}
@@ -196,28 +197,29 @@ impl TurnContext {
let supported_reasoning_levels = model_info
.supported_reasoning_levels
.iter()
.map(|preset| preset.effort)
.map(|preset| preset.effort.clone())
.collect::<Vec<_>>();
let reasoning_effort = if let Some(current_reasoning_effort) = self.reasoning_effort {
let reasoning_effort = if let Some(current_reasoning_effort) = self.reasoning_effort.clone()
{
if supported_reasoning_levels.contains(&current_reasoning_effort) {
Some(current_reasoning_effort)
} else {
supported_reasoning_levels
.get(supported_reasoning_levels.len().saturating_sub(1) / 2)
.copied()
.or(model_info.default_reasoning_level)
.cloned()
.or_else(|| model_info.default_reasoning_level.clone())
}
} else {
supported_reasoning_levels
.get(supported_reasoning_levels.len().saturating_sub(1) / 2)
.copied()
.or(model_info.default_reasoning_level)
.cloned()
.or_else(|| model_info.default_reasoning_level.clone())
};
config.model_reasoning_effort = reasoning_effort;
config.model_reasoning_effort = reasoning_effort.clone();
let collaboration_mode = self.collaboration_mode.with_updates(
Some(model.clone()),
Some(reasoning_effort),
Some(reasoning_effort.clone()),
/*developer_instructions*/ None,
);
let features = self.features.clone();
@@ -363,7 +365,7 @@ impl TurnContext {
collaboration_mode: Some(self.collaboration_mode.clone()),
multi_agent_version: Some(self.multi_agent_version),
realtime_active: Some(self.realtime_active),
effort: self.reasoning_effort,
effort: self.reasoning_effort.clone(),
summary: ReasoningSummaryConfig::Auto,
}
}
+1 -1
View File
@@ -271,7 +271,7 @@ async fn schedule_startup_prewarm_inner(
&startup_prompt,
&startup_turn_context.model_info,
&startup_turn_context.session_telemetry,
startup_turn_context.reasoning_effort,
startup_turn_context.reasoning_effort.clone(),
startup_turn_context.reasoning_summary,
startup_turn_context.config.service_tier.clone(),
startup_turn_metadata_header.as_deref(),
@@ -83,7 +83,7 @@ async fn handle_spawn_agent(
sender_thread_id: session.thread_id,
prompt: prompt.clone(),
model: args.model.clone().unwrap_or_default(),
reasoning_effort: args.reasoning_effort.unwrap_or_default(),
reasoning_effort: args.reasoning_effort.clone().unwrap_or_default(),
}
.into(),
)
@@ -94,14 +94,18 @@ async fn handle_spawn_agent(
config.service_tier = Some(service_tier.clone());
}
if args.fork_context {
reject_full_fork_spawn_overrides(role_name, args.model.as_deref(), args.reasoning_effort)?;
reject_full_fork_spawn_overrides(
role_name,
args.model.as_deref(),
args.reasoning_effort.clone(),
)?;
} else {
apply_requested_spawn_agent_model_overrides(
&session,
turn.as_ref(),
&mut config,
args.model.as_deref(),
args.reasoning_effort,
args.reasoning_effort.clone(),
)
.await?;
apply_role_to_config(&mut config, role_name)
@@ -174,7 +178,7 @@ async fn handle_spawn_agent(
.unwrap_or_else(|| args.model.clone().unwrap_or_default());
let effective_reasoning_effort = agent_snapshot
.as_ref()
.and_then(|snapshot| snapshot.reasoning_effort)
.and_then(|snapshot| snapshot.reasoning_effort.clone())
.unwrap_or(args.reasoning_effort.unwrap_or_default());
let nickname = new_agent_nickname.clone();
session
@@ -224,7 +224,8 @@ fn build_agent_shared_config(turn: &TurnContext) -> Result<Config, FunctionCallE
config.model_provider = turn.provider.info().clone();
config.model_reasoning_effort = turn
.reasoning_effort
.or(turn.model_info.default_reasoning_level);
.clone()
.or_else(|| turn.model_info.default_reasoning_level.clone());
config.model_reasoning_summary = Some(turn.reasoning_summary);
config.developer_instructions = turn.developer_instructions.clone();
config.compact_prompt = turn.compact_prompt.clone();
@@ -304,7 +305,7 @@ pub(crate) async fn apply_requested_spawn_agent_model_overrides(
validate_spawn_agent_reasoning_effort(
&selected_model_name,
&selected_model_info.supported_reasoning_levels,
reasoning_effort,
&reasoning_effort,
)?;
config.model_reasoning_effort = Some(reasoning_effort);
} else {
@@ -318,7 +319,7 @@ pub(crate) async fn apply_requested_spawn_agent_model_overrides(
validate_spawn_agent_reasoning_effort(
&turn.model_info.slug,
&turn.model_info.supported_reasoning_levels,
reasoning_effort,
&reasoning_effort,
)?;
config.model_reasoning_effort = Some(reasoning_effort);
}
@@ -404,11 +405,11 @@ fn find_spawn_agent_model_name(
fn validate_spawn_agent_reasoning_effort(
model: &str,
supported_reasoning_levels: &[ReasoningEffortPreset],
requested_reasoning_effort: ReasoningEffort,
requested_reasoning_effort: &ReasoningEffort,
) -> Result<(), FunctionCallError> {
if supported_reasoning_levels
.iter()
.any(|preset| preset.effort == requested_reasoning_effort)
.any(|preset| &preset.effort == requested_reasoning_effort)
{
return Ok(());
}
@@ -17,6 +17,7 @@ const SPAWN_AGENT_MODEL_OVERRIDE_DESCRIPTION: &str =
const SPAWN_AGENT_SERVICE_TIER_OVERRIDE_DESCRIPTION: &str =
"Service tier override for the new agent. Omit unless explicitly requested.";
const MAX_MODEL_OVERRIDES_IN_SPAWN_AGENT_DESCRIPTION: usize = 5;
const MAX_REASONING_EFFORT_CHARS_IN_SPAWN_AGENT_DESCRIPTION: usize = 64;
#[derive(Debug, Clone, Default)]
pub struct SpawnAgentToolOptions {
@@ -762,13 +763,20 @@ fn spawn_agent_models_description(models: &[ModelPreset]) -> String {
let model_descriptions = visible_models
.into_iter()
.map(|model| {
let default_reasoning_effort = model.default_reasoning_effort;
let default_reasoning_effort = &model.default_reasoning_effort;
let efforts = model
.supported_reasoning_efforts
.iter()
.map(|preset| {
let effort = preset.effort;
if effort == default_reasoning_effort {
let effort = preset.effort.as_str();
let effort = match effort
.char_indices()
.nth(MAX_REASONING_EFFORT_CHARS_IN_SPAWN_AGENT_DESCRIPTION)
{
Some((index, _)) => &effort[..index],
None => effort,
};
if &preset.effort == default_reasoning_effort {
format!("{effort} (default)")
} else {
effort.to_string()
@@ -186,6 +186,27 @@ fn spawn_agent_tool_caps_visible_model_summaries() {
assert!(!description.contains("`sixth-model`"));
}
#[test]
fn spawn_agent_tool_caps_reasoning_effort_value_length() {
let mut model = model_preset("visible", /*show_in_picker*/ true);
let custom_effort = ReasoningEffort::Custom(
"é".repeat(MAX_REASONING_EFFORT_CHARS_IN_SPAWN_AGENT_DESCRIPTION + 1),
);
model.default_reasoning_effort = custom_effort.clone();
model.supported_reasoning_efforts = vec![ReasoningEffortPreset {
effort: custom_effort,
description: "Model-defined".to_string(),
}];
assert_eq!(
spawn_agent_models_description(&[model]),
format!(
"Available model overrides (optional; inherited parent model is preferred):\n- `visible-model`: visible description Reasoning efforts: {} (default). Service tiers: priority.",
"é".repeat(MAX_REASONING_EFFORT_CHARS_IN_SPAWN_AGENT_DESCRIPTION)
)
);
}
#[test]
fn spawn_agent_tool_hides_service_tier_with_spawn_metadata() {
let tool = create_spawn_agent_tool_v2(SpawnAgentToolOptions {
@@ -4374,7 +4374,7 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
expected.base_instructions = Some(base_instructions.text);
expected.model = Some(turn.model_info.slug.clone());
expected.model_provider = turn.provider.info().clone();
expected.model_reasoning_effort = turn.reasoning_effort;
expected.model_reasoning_effort = turn.reasoning_effort.clone();
expected.model_reasoning_summary = Some(turn.reasoning_summary);
expected.developer_instructions = turn.developer_instructions.clone();
expected.compact_prompt = turn.compact_prompt.clone();
@@ -4431,7 +4431,7 @@ async fn build_agent_resume_config_clears_base_instructions() {
expected.base_instructions = None;
expected.model = Some(turn.model_info.slug.clone());
expected.model_provider = turn.provider.info().clone();
expected.model_reasoning_effort = turn.reasoning_effort;
expected.model_reasoning_effort = turn.reasoning_effort.clone();
expected.model_reasoning_summary = Some(turn.reasoning_summary);
expected.developer_instructions = turn.developer_instructions.clone();
expected.compact_prompt = turn.compact_prompt.clone();
@@ -75,7 +75,7 @@ async fn handle_spawn_agent(
sender_thread_id: session.thread_id,
prompt: prompt.clone(),
model: args.model.clone().unwrap_or_default(),
reasoning_effort: args.reasoning_effort.unwrap_or_default(),
reasoning_effort: args.reasoning_effort.clone().unwrap_or_default(),
}
.into(),
)
@@ -86,14 +86,18 @@ async fn handle_spawn_agent(
config.service_tier = Some(service_tier.clone());
}
if matches!(fork_mode, Some(SpawnAgentForkMode::FullHistory)) {
reject_full_fork_spawn_overrides(role_name, args.model.as_deref(), args.reasoning_effort)?;
reject_full_fork_spawn_overrides(
role_name,
args.model.as_deref(),
args.reasoning_effort.clone(),
)?;
} else {
apply_requested_spawn_agent_model_overrides(
&session,
turn.as_ref(),
&mut config,
args.model.as_deref(),
args.reasoning_effort,
args.reasoning_effort.clone(),
)
.await?;
apply_role_to_config(&mut config, role_name)
@@ -188,7 +192,7 @@ async fn handle_spawn_agent(
.unwrap_or_else(|| args.model.clone().unwrap_or_default());
let effective_reasoning_effort = agent_snapshot
.as_ref()
.and_then(|snapshot| snapshot.reasoning_effort)
.and_then(|snapshot| snapshot.reasoning_effort.clone())
.unwrap_or(args.reasoning_effort.unwrap_or_default());
let nickname = new_agent_nickname.clone();
session