[codex] Keep hosted tools visible in code-only mode (#25890)

## Why

`code_mode_only` moved ordinary runtime tools behind `exec`, but it also
hid hosted Responses tools. Hosted `web_search` and `image_generation`
do not have a nested `exec` runtime path, so code-only sessions lost
those capabilities entirely even when their existing provider, auth,
model, and configuration gates passed.

## What changed

- Keep hosted Responses tools top-level in `code_mode_only` sessions
after their existing gates pass.
- Preserve the existing nested-tool behavior for ordinary runtimes and
the direct-only behavior for multi-agent v2 tools.
- Add planner coverage for `code_mode_only` with default multi-agent v2
settings, hosted live web search, and hosted image generation.

## Verification

- Added focused regression coverage in
`codex-rs/core/src/tools/spec_plan_tests.rs`.
- Left execution to CI per repository workflow.
This commit is contained in:
Ahmed Ibrahim
2026-06-02 14:50:16 -07:00
committed by GitHub
Unverified
parent e7039f9844
commit 68e2c8ed69
3 changed files with 44 additions and 10 deletions
+2 -9
View File
@@ -210,15 +210,7 @@ fn build_model_visible_specs_and_registry(
specs.push(spec_for_model_request(turn_context, exposure, spec));
}
}
for spec in hosted_specs {
if !is_hidden_by_code_mode_only(
turn_context,
&ToolName::plain(spec.name()),
ToolExposure::Direct,
) {
specs.push(spec);
}
}
specs.extend(hosted_specs);
let registry = ToolRegistry::from_tools(runtimes);
let model_visible_specs = merge_into_namespaces(specs)
@@ -267,6 +259,7 @@ fn hosted_model_tool_specs(context: &CoreToolPlanContext<'_>) -> Vec<ToolSpec> {
}) {
specs.push(web_search_tool);
}
// TODO: Remove hosted image generation once the standalone extension is ready.
if image_generation_tool_enabled(turn_context)
&& !standalone_image_generation_available(turn_context, context.extension_tool_executors)
{
+36 -1
View File
@@ -1167,7 +1167,16 @@ async fn code_mode_only_can_expose_namespaced_multi_agent_v2_as_normal_tools() {
})
.await;
assert_eq!(plan.visible_names, vec!["exec", "wait", "agents"]);
assert_eq!(
plan.visible_names,
vec![
"exec",
"wait",
"agents",
// Hosted Responses tools.
"web_search",
]
);
assert!(
!plan
.namespace_function_names("agents")
@@ -1235,6 +1244,32 @@ async fn hosted_tools_follow_provider_auth_model_and_config_gates() {
}
);
let code_mode_only = probe(|turn| {
use_chatgpt_auth(turn);
set_features(turn, &[Feature::CodeModeOnly, Feature::MultiAgentV2]);
set_web_search_mode(turn, WebSearchMode::Live);
turn.model_info.input_modalities = vec![InputModality::Image];
})
.await;
assert_eq!(
code_mode_only.visible_names,
vec![
// Code-mode entrypoints.
codex_code_mode::PUBLIC_TOOL_NAME,
codex_code_mode::WAIT_TOOL_NAME,
// Multi-agent v2 tools.
"spawn_agent",
"send_message",
"followup_task",
"wait_agent",
"close_agent",
"list_agents",
// Hosted Responses tools.
"web_search",
"image_generation",
]
);
let standalone_web_search_without_web_run = probe(|turn| {
set_feature(turn, Feature::StandaloneWebSearch, /*enabled*/ true);
set_web_search_mode(turn, WebSearchMode::Live);
@@ -5,6 +5,7 @@ use codex_login::CodexAuth;
use codex_models_manager::manager::RefreshStrategy;
use codex_models_manager::manager::SharedModelsManager;
use codex_models_manager::model_info::model_info_from_slug;
use codex_protocol::openai_models::InputModality;
use codex_protocol::openai_models::ModelInfo;
use codex_protocol::openai_models::ModelPreset;
use codex_protocol::openai_models::ModelVisibility;
@@ -165,12 +166,17 @@ async fn remote_tool_mode_selector_overrides_feature_flags() -> Result<()> {
let mut code_mode_only_model = remote_model("test-tool-mode-code-mode-only");
code_mode_only_model.tool_mode = Some(ToolMode::CodeModeOnly);
code_mode_only_model.input_modalities = vec![InputModality::Text, InputModality::Image];
let code_mode_only_body = response_body_for_remote_model(code_mode_only_model, |_| {}).await?;
assert_eq!(
tool_names(&code_mode_only_body),
vec![
// Code-mode entrypoints.
codex_code_mode::PUBLIC_TOOL_NAME.to_string(),
codex_code_mode::WAIT_TOOL_NAME.to_string(),
// Hosted Responses tools.
"web_search".to_string(),
"image_generation".to_string(),
]
);