[codex] Use ToolMode as resolved runtime value

This commit is contained in:
Ahmed Ibrahim
2026-05-29 00:18:53 -07:00
parent 7c264fbbd2
commit b138a8a992
5 changed files with 26 additions and 52 deletions

View File

@@ -60,7 +60,7 @@ pub use codex_mcp::SandboxState;
mod mcp_openai_file;
mod mcp_tool_call;
pub(crate) mod mention_syntax;
mod model_runtime;
mod tool_mode;
pub(crate) mod utils;
pub use mention_syntax::PLUGIN_TEXT_MENTION_SIGIL;
pub use mention_syntax::TOOL_MENTION_SIGIL;

View File

@@ -1,4 +1,5 @@
use super::*;
use crate::tool_mode::resolve_tool_mode;
use std::sync::atomic::AtomicBool;
/// Spawn a review thread using the given prompt.
@@ -47,7 +48,7 @@ pub(super) async fn spawn_review_thread(
let mut per_turn_config = (*config).clone();
per_turn_config.model = Some(model.clone());
per_turn_config.features = review_features.clone();
let model_runtime_modes = ModelRuntimeModes::resolve(&model_info, &per_turn_config.features);
let tool_mode = resolve_tool_mode(&model_info, &per_turn_config.features);
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!(
@@ -97,7 +98,7 @@ pub(super) async fn spawn_review_thread(
config: per_turn_config,
auth_manager: auth_manager_for_context,
model_info: model_info.clone(),
model_runtime_modes,
tool_mode,
session_telemetry: session_telemetry_for_context,
provider: provider_for_context,
reasoning_effort,

View File

@@ -2,11 +2,12 @@ use super::*;
use crate::SkillLoadOutcome;
use crate::config::GhostSnapshotConfig;
use crate::environment_selection::ResolvedTurnEnvironments;
use crate::model_runtime::ModelRuntimeModes;
use crate::tool_mode::resolve_tool_mode;
use codex_model_provider::SharedModelProvider;
use codex_model_provider::create_model_provider;
use codex_protocol::SessionId;
use codex_protocol::models::AdditionalPermissionProfile;
use codex_protocol::openai_models::ToolMode;
use codex_protocol::protocol::ThreadSource;
use codex_protocol::protocol::TurnEnvironmentSelection;
use codex_sandboxing::compatibility_sandbox_policy_for_permission_profile;
@@ -56,7 +57,7 @@ pub struct TurnContext {
pub config: Arc<Config>,
pub(crate) auth_manager: Option<Arc<AuthManager>>,
pub(crate) model_info: ModelInfo,
pub(crate) model_runtime_modes: ModelRuntimeModes,
pub(crate) tool_mode: ToolMode,
pub(crate) session_telemetry: SessionTelemetry,
pub(crate) provider: SharedModelProvider,
pub(crate) reasoning_effort: Option<ReasoningEffortConfig>,
@@ -165,11 +166,11 @@ impl TurnContext {
}
pub(crate) fn code_mode_enabled(&self) -> bool {
self.model_runtime_modes.code_mode_enabled()
matches!(self.tool_mode, ToolMode::CodeMode | ToolMode::CodeModeOnly)
}
pub(crate) fn code_mode_only_enabled(&self) -> bool {
self.model_runtime_modes.code_mode_only_enabled()
self.tool_mode == ToolMode::CodeModeOnly
}
pub(crate) async fn with_model(
@@ -182,7 +183,7 @@ impl TurnContext {
let model_info = models_manager
.get_model_info(model.as_str(), &config.to_models_manager_config())
.await;
let model_runtime_modes = ModelRuntimeModes::resolve(&model_info, &config.features);
let tool_mode = resolve_tool_mode(&model_info, &config.features);
let truncation_policy = model_info.truncation_policy.into();
let supported_reasoning_levels = model_info
.supported_reasoning_levels
@@ -223,7 +224,7 @@ impl TurnContext {
config: Arc::new(config),
auth_manager: self.auth_manager.clone(),
model_info: model_info.clone(),
model_runtime_modes,
tool_mode,
session_telemetry: self
.session_telemetry
.clone()
@@ -487,8 +488,7 @@ impl Session {
);
let mut per_turn_config = per_turn_config;
let model_runtime_modes =
ModelRuntimeModes::resolve(&model_info, &per_turn_config.features);
let tool_mode = resolve_tool_mode(&model_info, &per_turn_config.features);
per_turn_config.service_tier = get_service_tier(
per_turn_config.service_tier,
per_turn_config.features.enabled(Feature::FastMode),
@@ -515,7 +515,7 @@ impl Session {
config: per_turn_config.clone(),
auth_manager: auth_manager_for_context,
model_info: model_info.clone(),
model_runtime_modes,
tool_mode,
session_telemetry: session_telemetry_for_context,
provider: provider_for_context,
reasoning_effort,

View File

@@ -3,27 +3,10 @@ use codex_features::Feature;
use codex_protocol::openai_models::ModelInfo;
use codex_protocol::openai_models::ToolMode;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ModelRuntimeModes {
tool_mode: ToolMode,
}
impl ModelRuntimeModes {
pub(crate) fn resolve(model_info: &ModelInfo, features: &ManagedFeatures) -> Self {
Self {
tool_mode: model_info
.tool_mode
.unwrap_or_else(|| tool_mode_from_features(features)),
}
}
pub(crate) fn code_mode_enabled(self) -> bool {
matches!(self.tool_mode, ToolMode::CodeMode | ToolMode::CodeModeOnly)
}
pub(crate) fn code_mode_only_enabled(self) -> bool {
self.tool_mode == ToolMode::CodeModeOnly
}
pub(crate) fn resolve_tool_mode(model_info: &ModelInfo, features: &ManagedFeatures) -> ToolMode {
model_info
.tool_mode
.unwrap_or_else(|| tool_mode_from_features(features))
}
fn tool_mode_from_features(features: &ManagedFeatures) -> ToolMode {
@@ -57,31 +40,21 @@ mod tests {
#[test]
fn omitted_selector_follows_feature_flags() {
let modes = ModelRuntimeModes::resolve(
let tool_mode = resolve_tool_mode(
&model_info(/*tool_mode*/ None),
&features(&[Feature::CodeModeOnly]),
);
assert_eq!(
modes,
ModelRuntimeModes {
tool_mode: ToolMode::CodeModeOnly,
}
);
assert_eq!(tool_mode, ToolMode::CodeModeOnly);
}
#[test]
fn explicit_selector_overrides_feature_flags() {
let modes = ModelRuntimeModes::resolve(
let tool_mode = resolve_tool_mode(
&model_info(Some(ToolMode::Direct)),
&features(&[Feature::CodeModeOnly]),
);
assert_eq!(
modes,
ModelRuntimeModes {
tool_mode: ToolMode::Direct,
}
);
assert_eq!(tool_mode, ToolMode::Direct);
}
}

View File

@@ -30,9 +30,9 @@ use codex_tools::ToolSpec;
use pretty_assertions::assert_eq;
use serde_json::json;
use crate::model_runtime::ModelRuntimeModes;
use crate::session::tests::make_session_and_context;
use crate::session::turn_context::TurnContext;
use crate::tool_mode::resolve_tool_mode;
use crate::tools::handlers::multi_agents_spec::MULTI_AGENT_V1_NAMESPACE;
use crate::tools::router::ToolRouter;
use crate::tools::router::ToolRouterParams;
@@ -217,7 +217,7 @@ fn set_feature(turn: &mut TurnContext, feature: Feature, enabled: bool) {
.expect("test feature should be disableable in config");
}
turn.config = Arc::new(config);
resolve_model_runtime_modes(turn);
resolve_tool_mode_for_turn(turn);
}
fn set_features(turn: &mut TurnContext, features: &[Feature]) {
@@ -232,8 +232,8 @@ fn update_config(turn: &mut TurnContext, update: impl FnOnce(&mut crate::config:
turn.config = Arc::new(config);
}
fn resolve_model_runtime_modes(turn: &mut TurnContext) {
turn.model_runtime_modes = ModelRuntimeModes::resolve(&turn.model_info, &turn.config.features);
fn resolve_tool_mode_for_turn(turn: &mut TurnContext) {
turn.tool_mode = resolve_tool_mode(&turn.model_info, &turn.config.features);
}
fn set_web_search_mode(turn: &mut TurnContext, mode: WebSearchMode) {
@@ -809,7 +809,7 @@ async fn tool_mode_selector_overrides_feature_flags() {
let direct = probe(|turn| {
set_features(turn, &[Feature::CodeMode, Feature::CodeModeOnly]);
turn.model_info.tool_mode = Some(ToolMode::Direct);
resolve_model_runtime_modes(turn);
resolve_tool_mode_for_turn(turn);
})
.await;
direct.assert_visible_lacks(&[