mirror of
https://github.com/openai/codex.git
synced 2026-06-02 19:31:59 +00:00
[codex] Inline tool mode resolution
This commit is contained in:
@@ -60,7 +60,6 @@ pub use codex_mcp::SandboxState;
|
||||
mod mcp_openai_file;
|
||||
mod mcp_tool_call;
|
||||
pub(crate) mod mention_syntax;
|
||||
mod tool_mode;
|
||||
pub(crate) mod utils;
|
||||
pub use mention_syntax::PLUGIN_TEXT_MENTION_SIGIL;
|
||||
pub use mention_syntax::TOOL_MENTION_SIGIL;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use super::*;
|
||||
use crate::tool_mode::resolve_tool_mode;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// Spawn a review thread using the given prompt.
|
||||
@@ -48,7 +47,15 @@ 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 tool_mode = resolve_tool_mode(&model_info, &per_turn_config.features);
|
||||
let tool_mode = model_info.tool_mode.unwrap_or_else(|| {
|
||||
if per_turn_config.features.enabled(Feature::CodeModeOnly) {
|
||||
ToolMode::CodeModeOnly
|
||||
} else if per_turn_config.features.enabled(Feature::CodeMode) {
|
||||
ToolMode::CodeMode
|
||||
} else {
|
||||
ToolMode::Direct
|
||||
}
|
||||
});
|
||||
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!(
|
||||
|
||||
@@ -2,7 +2,6 @@ use super::*;
|
||||
use crate::SkillLoadOutcome;
|
||||
use crate::config::GhostSnapshotConfig;
|
||||
use crate::environment_selection::ResolvedTurnEnvironments;
|
||||
use crate::tool_mode::resolve_tool_mode;
|
||||
use codex_model_provider::SharedModelProvider;
|
||||
use codex_model_provider::create_model_provider;
|
||||
use codex_protocol::SessionId;
|
||||
@@ -165,14 +164,6 @@ impl TurnContext {
|
||||
self.goal_tools_supported && self.features.get().enabled(Feature::Goals)
|
||||
}
|
||||
|
||||
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) async fn with_model(
|
||||
&self,
|
||||
model: String,
|
||||
@@ -183,7 +174,15 @@ impl TurnContext {
|
||||
let model_info = models_manager
|
||||
.get_model_info(model.as_str(), &config.to_models_manager_config())
|
||||
.await;
|
||||
let tool_mode = resolve_tool_mode(&model_info, &config.features);
|
||||
let tool_mode = model_info.tool_mode.unwrap_or_else(|| {
|
||||
if config.features.enabled(Feature::CodeModeOnly) {
|
||||
ToolMode::CodeModeOnly
|
||||
} else if config.features.enabled(Feature::CodeMode) {
|
||||
ToolMode::CodeMode
|
||||
} else {
|
||||
ToolMode::Direct
|
||||
}
|
||||
});
|
||||
let truncation_policy = model_info.truncation_policy.into();
|
||||
let supported_reasoning_levels = model_info
|
||||
.supported_reasoning_levels
|
||||
@@ -488,7 +487,15 @@ impl Session {
|
||||
);
|
||||
|
||||
let mut per_turn_config = per_turn_config;
|
||||
let tool_mode = resolve_tool_mode(&model_info, &per_turn_config.features);
|
||||
let tool_mode = model_info.tool_mode.unwrap_or_else(|| {
|
||||
if per_turn_config.features.enabled(Feature::CodeModeOnly) {
|
||||
ToolMode::CodeModeOnly
|
||||
} else if per_turn_config.features.enabled(Feature::CodeMode) {
|
||||
ToolMode::CodeMode
|
||||
} else {
|
||||
ToolMode::Direct
|
||||
}
|
||||
});
|
||||
per_turn_config.service_tier = get_service_tier(
|
||||
per_turn_config.service_tier,
|
||||
per_turn_config.features.enabled(Feature::FastMode),
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
use crate::config::ManagedFeatures;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_protocol::openai_models::ToolMode;
|
||||
|
||||
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 {
|
||||
if features.enabled(Feature::CodeModeOnly) {
|
||||
ToolMode::CodeModeOnly
|
||||
} else if features.enabled(Feature::CodeMode) {
|
||||
ToolMode::CodeMode
|
||||
} else {
|
||||
ToolMode::Direct
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codex_features::Features;
|
||||
|
||||
fn features(enabled: &[Feature]) -> ManagedFeatures {
|
||||
let mut features = Features::default();
|
||||
for feature in enabled {
|
||||
features.enable(*feature);
|
||||
}
|
||||
features.into()
|
||||
}
|
||||
|
||||
fn model_info(tool_mode: Option<ToolMode>) -> ModelInfo {
|
||||
let mut model_info = codex_models_manager::model_info::model_info_from_slug("test-model");
|
||||
model_info.tool_mode = tool_mode;
|
||||
model_info
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn omitted_selector_follows_feature_flags() {
|
||||
let tool_mode = resolve_tool_mode(
|
||||
&model_info(/*tool_mode*/ None),
|
||||
&features(&[Feature::CodeModeOnly]),
|
||||
);
|
||||
|
||||
assert_eq!(tool_mode, ToolMode::CodeModeOnly);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_selector_overrides_feature_flags() {
|
||||
let tool_mode = resolve_tool_mode(
|
||||
&model_info(Some(ToolMode::Direct)),
|
||||
&features(&[Feature::CodeModeOnly]),
|
||||
);
|
||||
|
||||
assert_eq!(tool_mode, ToolMode::Direct);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ use crate::tools::parallel::ToolCallRuntime;
|
||||
use crate::tools::router::ToolCall;
|
||||
use crate::tools::router::ToolCallSource;
|
||||
use crate::unified_exec::resolve_max_tokens;
|
||||
use codex_protocol::openai_models::ToolMode;
|
||||
use codex_tools::ToolName;
|
||||
use codex_utils_output_truncation::TruncationPolicy;
|
||||
use codex_utils_output_truncation::formatted_truncate_text_content_items_with_policy;
|
||||
@@ -90,7 +91,7 @@ impl CodeModeService {
|
||||
router: Arc<ToolRouter>,
|
||||
tracker: SharedTurnDiffTracker,
|
||||
) -> Option<codex_code_mode::CodeModeTurnWorker> {
|
||||
if !turn.code_mode_enabled() {
|
||||
if !matches!(turn.tool_mode, ToolMode::CodeMode | ToolMode::CodeModeOnly) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ use codex_mcp::ToolInfo;
|
||||
use codex_protocol::dynamic_tools::DynamicToolSpec;
|
||||
use codex_protocol::openai_models::ConfigShellToolType;
|
||||
use codex_protocol::openai_models::InputModality;
|
||||
use codex_protocol::openai_models::ToolMode;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_tools::DiscoverableTool;
|
||||
@@ -230,8 +231,10 @@ fn spec_for_model_request(
|
||||
exposure: ToolExposure,
|
||||
spec: ToolSpec,
|
||||
) -> ToolSpec {
|
||||
if code_mode_enabled(turn_context)
|
||||
&& exposure != ToolExposure::DirectModelOnly
|
||||
if matches!(
|
||||
turn_context.tool_mode,
|
||||
ToolMode::CodeMode | ToolMode::CodeModeOnly
|
||||
) && exposure != ToolExposure::DirectModelOnly
|
||||
&& codex_code_mode::is_code_mode_nested_tool(spec.name())
|
||||
{
|
||||
codex_tools::augment_tool_spec_for_code_mode(spec)
|
||||
@@ -282,14 +285,6 @@ fn namespace_tools_enabled(turn_context: &TurnContext) -> bool {
|
||||
turn_context.provider.capabilities().namespace_tools
|
||||
}
|
||||
|
||||
fn code_mode_enabled(turn_context: &TurnContext) -> bool {
|
||||
turn_context.code_mode_enabled()
|
||||
}
|
||||
|
||||
fn code_mode_only_enabled(turn_context: &TurnContext) -> bool {
|
||||
turn_context.code_mode_only_enabled()
|
||||
}
|
||||
|
||||
fn multi_agent_v2_enabled(turn_context: &TurnContext) -> bool {
|
||||
turn_context.features.get().enabled(Feature::MultiAgentV2)
|
||||
}
|
||||
@@ -398,7 +393,7 @@ fn is_hidden_by_code_mode_only(
|
||||
tool_name: &ToolName,
|
||||
exposure: ToolExposure,
|
||||
) -> bool {
|
||||
code_mode_only_enabled(turn_context)
|
||||
turn_context.tool_mode == ToolMode::CodeModeOnly
|
||||
&& exposure != ToolExposure::DirectModelOnly
|
||||
&& codex_code_mode::is_code_mode_nested_tool(&codex_tools::code_mode_name_for_tool_name(
|
||||
tool_name,
|
||||
@@ -410,7 +405,10 @@ fn build_code_mode_executors(
|
||||
executors: &[Arc<dyn CoreToolRuntime>],
|
||||
deferred_tools_available: bool,
|
||||
) -> Vec<Arc<dyn CoreToolRuntime>> {
|
||||
if !code_mode_enabled(turn_context) {
|
||||
if !matches!(
|
||||
turn_context.tool_mode,
|
||||
ToolMode::CodeMode | ToolMode::CodeModeOnly
|
||||
) {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
@@ -444,7 +442,7 @@ fn build_code_mode_executors(
|
||||
create_code_mode_tool(
|
||||
&enabled_tools,
|
||||
&namespace_descriptions,
|
||||
code_mode_only_enabled(turn_context),
|
||||
turn_context.tool_mode == ToolMode::CodeModeOnly,
|
||||
deferred_tools_available,
|
||||
),
|
||||
code_mode_nested_tool_specs,
|
||||
@@ -847,7 +845,10 @@ fn append_extension_tool_executors(
|
||||
.iter()
|
||||
.map(|executor| executor.tool_name())
|
||||
.collect::<HashSet<_>>();
|
||||
if code_mode_enabled(turn_context) {
|
||||
if matches!(
|
||||
turn_context.tool_mode,
|
||||
ToolMode::CodeMode | ToolMode::CodeModeOnly
|
||||
) {
|
||||
reserved_tool_names.insert(ToolName::plain(codex_code_mode::PUBLIC_TOOL_NAME));
|
||||
reserved_tool_names.insert(ToolName::plain(codex_code_mode::WAIT_TOOL_NAME));
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ use serde_json::json;
|
||||
|
||||
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 +216,15 @@ fn set_feature(turn: &mut TurnContext, feature: Feature, enabled: bool) {
|
||||
.expect("test feature should be disableable in config");
|
||||
}
|
||||
turn.config = Arc::new(config);
|
||||
resolve_tool_mode_for_turn(turn);
|
||||
turn.tool_mode = turn.model_info.tool_mode.unwrap_or_else(|| {
|
||||
if turn.config.features.enabled(Feature::CodeModeOnly) {
|
||||
ToolMode::CodeModeOnly
|
||||
} else if turn.config.features.enabled(Feature::CodeMode) {
|
||||
ToolMode::CodeMode
|
||||
} else {
|
||||
ToolMode::Direct
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn set_features(turn: &mut TurnContext, features: &[Feature]) {
|
||||
@@ -232,10 +239,6 @@ fn update_config(turn: &mut TurnContext, update: impl FnOnce(&mut crate::config:
|
||||
turn.config = Arc::new(config);
|
||||
}
|
||||
|
||||
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) {
|
||||
update_config(turn, |config| {
|
||||
config
|
||||
@@ -809,7 +812,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_tool_mode_for_turn(turn);
|
||||
turn.tool_mode = ToolMode::Direct;
|
||||
})
|
||||
.await;
|
||||
direct.assert_visible_lacks(&[
|
||||
|
||||
Reference in New Issue
Block a user