Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ Example with notification opt-out:
- `model/list` — list available models (set `includeHidden: true` to include entries with `hidden: true`), with reasoning effort options, `additionalSpeedTiers`, optional legacy `upgrade` model ids, optional `upgradeInfo` metadata (`model`, `upgradeCopy`, `modelLink`, `migrationMarkdown`), and optional `availabilityNux` metadata.
- `modelProvider/capabilities/read` — read provider-level capabilities for the currently configured model provider.
- `experimentalFeature/list` — list feature flags with stage metadata (`beta`, `underDevelopment`, `stable`, etc.), enabled/default-enabled state, and cursor pagination. Pass `threadId` when showing feature state for an existing loaded thread so `enabled` is computed from that thread's refreshed config, including project-local config for the thread's cwd; if omitted, the server uses its default config resolution context. For non-beta flags, `displayName`/`description`/`announcement` are `null`.
- `experimentalFeature/enablement/set` — patch the in-memory process-wide runtime feature enablement for the currently supported feature keys (`apps`, `memories`, `plugins`, `tool_search`, `tool_suggest`, `tool_call_mcp_elicitation`). For each feature, precedence is: cloud requirements > --enable <feature_name> > config.toml > experimentalFeature/enablement/set (new) > code default.
- `experimentalFeature/enablement/set` — patch the in-memory process-wide runtime feature enablement for the currently supported feature keys (`apps`, `memories`, `plugins`, `tool_suggest`, `tool_call_mcp_elicitation`). For each feature, precedence is: cloud requirements > --enable <feature_name> > config.toml > experimentalFeature/enablement/set (new) > code default.
- `environment/add` — experimental; add or replace a named remote environment by `environmentId` and `execServerUrl` for later selection by `thread/start` or `turn/start`; returns `{}` and does not change the default environment.
- `collaborationMode/list` — list available collaboration mode presets (experimental, no pagination). Built-in presets do not select a model; the Plan preset selects medium reasoning effort. This response omits built-in developer instructions; clients should either pass `settings.developer_instructions: null` when setting a mode to use Codex's built-in instructions, or provide their own instructions explicitly.
- `skills/list` — list skills for one or more `cwd` values (optional `forceReload`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ const SUPPORTED_EXPERIMENTAL_FEATURE_ENABLEMENT: &[&str] = &[
"mentions_v2",
"plugins",
"remote_control",
"tool_search",
"tool_suggest",
"tool_call_mcp_elicitation",
];
Expand Down
11 changes: 1 addition & 10 deletions codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,6 @@ async fn experimental_feature_enablement_set_only_updates_named_features() -> Re
BTreeMap::from([
("memories".to_string(), true),
("plugins".to_string(), true),
("tool_search".to_string(), true),
("tool_suggest".to_string(), true),
("tool_call_mcp_elicitation".to_string(), false),
]),
Expand All @@ -353,7 +352,6 @@ async fn experimental_feature_enablement_set_only_updates_named_features() -> Re
enablement: BTreeMap::from([
("memories".to_string(), true),
("plugins".to_string(), true),
("tool_search".to_string(), true),
("tool_suggest".to_string(), true),
("tool_call_mcp_elicitation".to_string(), false),
]),
Expand Down Expand Up @@ -383,13 +381,6 @@ async fn experimental_feature_enablement_set_only_updates_named_features() -> Re
.and_then(|features| features.get("plugins")),
Some(&json!(true))
);
assert_eq!(
config
.additional
.get("features")
.and_then(|features| features.get("tool_search")),
Some(&json!(true))
);
assert_eq!(
config
.additional
Expand Down Expand Up @@ -483,7 +474,7 @@ async fn experimental_feature_enablement_set_rejects_non_allowlisted_feature() -
);
assert!(
error.message.contains(
"apps, memories, mentions_v2, plugins, remote_control, tool_search, tool_suggest, tool_call_mcp_elicitation"
"apps, memories, mentions_v2, plugins, remote_control, tool_suggest, tool_call_mcp_elicitation"
),
"{}",
error.message
Expand Down
3 changes: 0 additions & 3 deletions codex-rs/core/src/tools/spec_plan_model_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,6 @@ async fn request_plugin_install_requires_apps_and_plugins_features() {

for disabled_feature in [Feature::Apps, Feature::Plugins] {
let mut features = Features::with_defaults();
features.enable(Feature::ToolSearch);
features.enable(Feature::ToolSuggest);
features.enable(Feature::Apps);
features.enable(Feature::Plugins);
Expand Down Expand Up @@ -832,7 +831,6 @@ async fn search_tool_is_hidden_without_deferred_tools() {
let model_info = search_capable_model_info().await;
let mut features = Features::with_defaults();
features.enable(Feature::Apps);
features.enable(Feature::ToolSearch);
let available_models = Vec::new();
let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
Expand Down Expand Up @@ -863,7 +861,6 @@ async fn search_tool_description_falls_back_to_connector_name_without_descriptio
let model_info = search_capable_model_info().await;
let mut features = Features::with_defaults();
features.enable(Feature::Apps);
features.enable(Feature::ToolSearch);
let available_models = Vec::new();
let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
Expand Down
34 changes: 4 additions & 30 deletions codex-rs/core/src/tools/spec_plan_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1653,7 +1653,6 @@ fn search_tool_description_lists_each_mcp_source_once() {
let model_info = search_capable_model_info();
let mut features = Features::with_defaults();
features.enable(Feature::Apps);
features.enable(Feature::ToolSearch);
let available_models = Vec::new();
let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
Expand Down Expand Up @@ -1726,7 +1725,7 @@ fn search_tool_description_lists_each_mcp_source_once() {
}

#[test]
fn search_tool_requires_model_capability_and_enabled_feature() {
fn search_tool_requires_model_capability() {
let model_info = search_capable_model_info();
let deferred_mcp_tools = Some(vec![deferred_mcp_tool(
"_create_event",
Expand Down Expand Up @@ -1759,26 +1758,6 @@ fn search_tool_requires_model_capability_and_enabled_feature() {
);
assert_lacks_tool_name(&tools, TOOL_SEARCH_TOOL_NAME);

let mut features_without_tool_search = Features::with_defaults();
features_without_tool_search.disable(Feature::ToolSearch);
let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
available_models: &available_models,
features: &features_without_tool_search,
image_generation_tool_auth_allowed: true,
web_search_mode: Some(WebSearchMode::Cached),
session_source: SessionSource::Cli,
permission_profile: &PermissionProfile::Disabled,
windows_sandbox_level: WindowsSandboxLevel::Disabled,
});
let (tools, _) = build_specs(
&tools_config,
/*mcp_tools*/ None,
deferred_mcp_tools.clone(),
&[],
);
assert_lacks_tool_name(&tools, TOOL_SEARCH_TOOL_NAME);

let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
available_models: &available_models,
Expand All @@ -1801,8 +1780,7 @@ fn search_tool_requires_model_capability_and_enabled_feature() {
#[test]
fn no_search_tool_when_namespaces_disabled() {
let model_info = search_capable_model_info();
let mut features = Features::with_defaults();
features.enable(Feature::ToolSearch);
let features = Features::with_defaults();
let available_models = Vec::new();
let mut tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
Expand Down Expand Up @@ -1836,8 +1814,7 @@ fn no_search_tool_when_namespaces_disabled() {
#[test]
fn search_tool_registers_for_deferred_dynamic_tools() {
let model_info = search_capable_model_info();
let mut features = Features::with_defaults();
features.enable(Feature::ToolSearch);
let features = Features::with_defaults();
let available_models = Vec::new();
let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
Expand Down Expand Up @@ -1896,8 +1873,7 @@ fn search_tool_registers_for_deferred_dynamic_tools() {
#[test]
fn search_tool_is_hidden_for_deferred_dynamic_tools_when_namespace_tools_are_disabled() {
let model_info = search_capable_model_info();
let mut features = Features::with_defaults();
features.enable(Feature::ToolSearch);
let features = Features::with_defaults();
let available_models = Vec::new();
let mut tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
Expand Down Expand Up @@ -1946,7 +1922,6 @@ fn search_tool_is_hidden_for_deferred_dynamic_tools_when_namespace_tools_are_dis
fn request_plugin_install_is_not_registered_without_feature_flag() {
let model_info = search_capable_model_info();
let mut features = Features::with_defaults();
features.enable(Feature::ToolSearch);
features.enable(Feature::Apps);
features.enable(Feature::Plugins);
features.disable(Feature::ToolSuggest);
Expand Down Expand Up @@ -2036,7 +2011,6 @@ fn request_plugin_install_description_lists_discoverable_tools() {
let mut features = Features::with_defaults();
features.enable(Feature::Apps);
features.enable(Feature::Plugins);
features.enable(Feature::ToolSearch);
features.enable(Feature::ToolSuggest);
let available_models = Vec::new();
let tools_config = ToolsConfig::new(&ToolsConfigParams {
Expand Down
4 changes: 0 additions & 4 deletions codex-rs/core/tests/suite/code_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,6 @@ if (!tool) {
.features
.enable(Feature::Apps)
.expect("test config should allow feature update");
config
.features
.enable(Feature::ToolSearch)
.expect("test config should allow feature update");
config
.features
.enable(Feature::CodeMode)
Expand Down
57 changes: 0 additions & 57 deletions codex-rs/core/tests/suite/search_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
use anyhow::Result;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerTransportConfig;
use codex_core::config::Config;
use codex_features::Feature;
use codex_login::CodexAuth;
use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem;
Expand Down Expand Up @@ -113,14 +112,6 @@ fn tool_search_output_has_namespace_child(
namespace_child_tool(&output, namespace, tool_name).is_some()
}

fn configure_apps_without_tool_search(config: &mut Config, apps_base_url: &str) {
configure_search_capable_apps(config, apps_base_url);
config
.features
.disable(Feature::ToolSearch)
.expect("test config should allow feature update");
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn search_tool_enabled_by_default_adds_tool_search() -> Result<()> {
skip_if_no_network!(Ok(()));
Expand Down Expand Up @@ -225,54 +216,6 @@ async fn always_defer_feature_hides_small_app_tool_sets() -> Result<()> {
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn tool_search_disabled_exposes_apps_tools_directly() -> Result<()> {
skip_if_no_network!(Ok(()));

let server = start_mock_server().await;
let apps_server = AppsTestServer::mount_searchable(&server).await?;
let mock = mount_sse_once(
&server,
sse(vec![
ev_response_created("resp-1"),
ev_assistant_message("msg-1", "done"),
ev_completed("resp-1"),
]),
)
.await;

let mut builder = test_codex()
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
.with_config(move |config| {
configure_apps_without_tool_search(config, apps_server.chatgpt_base_url.as_str())
});
let test = builder.build(&server).await?;

test.submit_turn_with_approval_and_permission_profile(
"list tools",
AskForApproval::Never,
PermissionProfile::Disabled,
)
.await?;

let body = mock.single_request().body_json();
let tools = tool_names(&body);
assert!(!tools.iter().any(|name| name == TOOL_SEARCH_TOOL_NAME));
assert!(
namespace_child_tool(
&body,
SEARCH_CALENDAR_NAMESPACE,
SEARCH_CALENDAR_CREATE_TOOL
)
.is_some()
);
assert!(
namespace_child_tool(&body, SEARCH_CALENDAR_NAMESPACE, SEARCH_CALENDAR_LIST_TOOL).is_some()
);

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn search_tool_is_hidden_for_api_key_auth() -> Result<()> {
skip_if_no_network!(Ok(()));
Expand Down
9 changes: 6 additions & 3 deletions codex-rs/features/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub enum Feature {
EnableMcpApps,
/// Use the new path for the host-owned apps MCP server.
AppsMcpPathOverride,
/// Enable the tool_search tool for apps.
/// Removed compatibility flag retained as a no-op now that tool_search is always enabled.
ToolSearch,
/// Always defer MCP tools behind tool_search instead of exposing small sets directly.
ToolSearchAlwaysDeferMcpTools,
Expand Down Expand Up @@ -428,6 +428,9 @@ impl Features {
"apply_patch_freeform" => {
continue;
}
"tool_search" => {
continue;
}
"image_detail_original" => {
continue;
}
Expand Down Expand Up @@ -943,8 +946,8 @@ pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::ToolSearch,
key: "tool_search",
stage: Stage::Stable,
default_enabled: true,
stage: Stage::Removed,
default_enabled: false,
},
FeatureSpec {
id: Feature::ToolSearchAlwaysDeferMcpTools,
Expand Down
8 changes: 4 additions & 4 deletions codex-rs/features/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,10 @@ fn network_proxy_is_experimental_and_disabled_by_default() {
}

#[test]
fn tool_search_is_stable_and_enabled_by_default() {
assert_eq!(Feature::ToolSearch.stage(), Stage::Stable);
assert_eq!(Feature::ToolSearch.default_enabled(), true);
fn tool_search_is_removed_and_disabled_by_default() {
assert_eq!(Feature::ToolSearch.stage(), Stage::Removed);
assert_eq!(Feature::ToolSearch.default_enabled(), false);
assert_eq!(feature_for_key("tool_search"), Some(Feature::ToolSearch));
}

#[test]
Expand Down Expand Up @@ -603,7 +604,6 @@ fn materialize_resolved_enabled_writes_all_features_and_preserves_custom_config(
features.enable(Feature::CodeMode);
features.enable(Feature::MultiAgentV2);
features.enable(Feature::NetworkProxy);
features.disable(Feature::ToolSearch);

let mut features_toml = FeaturesToml {
multi_agent_v2: Some(FeatureToml::Config(crate::MultiAgentV2ConfigToml {
Expand Down
3 changes: 1 addition & 2 deletions codex-rs/tools/src/tool_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,7 @@ impl ToolsConfig {
let include_multi_agent_v2 = features.enabled(Feature::MultiAgentV2);
let include_collab_tools = include_multi_agent_v2 || features.enabled(Feature::Collab);
let include_agent_jobs = features.enabled(Feature::SpawnCsv);
let include_search_tool =
model_info.supports_search_tool && features.enabled(Feature::ToolSearch);
let include_search_tool = model_info.supports_search_tool;
let include_tool_suggest = features.enabled(Feature::ToolSuggest)
&& features.enabled(Feature::Apps)
&& features.enabled(Feature::Plugins);
Expand Down
Loading