From df88dc103a1630f30d24ccaa7b3ddf0fdebcc6f7 Mon Sep 17 00:00:00 2001 From: Friel Date: Fri, 3 Apr 2026 20:39:29 +0000 Subject: [PATCH] Keep request_user_input visible in subagents --- codex-rs/core/src/agent/agent_resolver.rs | 9 +++++++++ codex-rs/core/src/tools/handlers/request_user_input.rs | 7 +++++++ codex-rs/tools/src/tool_config.rs | 2 +- codex-rs/tools/src/tool_config_tests.rs | 4 ++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/codex-rs/core/src/agent/agent_resolver.rs b/codex-rs/core/src/agent/agent_resolver.rs index 14f21c731c..4dcc819a16 100644 --- a/codex-rs/core/src/agent/agent_resolver.rs +++ b/codex-rs/core/src/agent/agent_resolver.rs @@ -2,6 +2,8 @@ use crate::codex::Session; use crate::codex::TurnContext; use crate::function_tool::FunctionCallError; use codex_protocol::ThreadId; +use codex_protocol::protocol::SessionSource; +use codex_protocol::protocol::SubAgentSource; use std::sync::Arc; /// Resolves a single tool-facing agent target to a thread id. @@ -14,6 +16,13 @@ pub(crate) async fn resolve_agent_target( if let Ok(thread_id) = ThreadId::from_string(target) { return Ok(thread_id); } + if matches!(target, "parent" | "root") + && let SessionSource::SubAgent(SubAgentSource::ThreadSpawn { + parent_thread_id, .. + }) = &turn.session_source + { + return Ok(*parent_thread_id); + } session .services diff --git a/codex-rs/core/src/tools/handlers/request_user_input.rs b/codex-rs/core/src/tools/handlers/request_user_input.rs index f12defd0e7..a043960c8b 100644 --- a/codex-rs/core/src/tools/handlers/request_user_input.rs +++ b/codex-rs/core/src/tools/handlers/request_user_input.rs @@ -6,6 +6,7 @@ use crate::tools::handlers::parse_arguments; use crate::tools::registry::ToolHandler; use crate::tools::registry::ToolKind; use async_trait::async_trait; +use codex_protocol::protocol::SessionSource; use codex_protocol::request_user_input::RequestUserInputArgs; use codex_tools::REQUEST_USER_INPUT_TOOL_NAME; use codex_tools::normalize_request_user_input_args; @@ -41,6 +42,12 @@ impl ToolHandler for RequestUserInputHandler { } }; + if matches!(turn.session_source, SessionSource::SubAgent(_)) { + return Err(FunctionCallError::RespondToModel( + "request_user_input can only be used by the root thread".to_string(), + )); + } + let mode = session.collaboration_mode().await.mode; if let Some(message) = request_user_input_unavailable_message(mode, self.default_mode_request_user_input) diff --git a/codex-rs/tools/src/tool_config.rs b/codex-rs/tools/src/tool_config.rs index f48f1b8fcc..60ddfd55fe 100644 --- a/codex-rs/tools/src/tool_config.rs +++ b/codex-rs/tools/src/tool_config.rs @@ -141,7 +141,7 @@ impl ToolsConfig { let include_collab_tools = features.enabled(Feature::Collab); let include_multi_agent_v2 = features.enabled(Feature::MultiAgentV2); let include_agent_jobs = features.enabled(Feature::SpawnCsv); - let include_request_user_input = !matches!(session_source, SessionSource::SubAgent(_)); + let include_request_user_input = true; let include_default_mode_request_user_input = include_request_user_input && features.enabled(Feature::DefaultModeRequestUserInput); let include_search_tool = diff --git a/codex-rs/tools/src/tool_config_tests.rs b/codex-rs/tools/src/tool_config_tests.rs index 168c8e80a0..f22d24a7a3 100644 --- a/codex-rs/tools/src/tool_config_tests.rs +++ b/codex-rs/tools/src/tool_config_tests.rs @@ -131,7 +131,7 @@ fn shell_zsh_fork_prefers_shell_command_over_unified_exec() { } #[test] -fn subagents_disable_request_user_input_and_agent_jobs_workers_opt_in_by_label() { +fn subagents_keep_request_user_input_schema_and_agent_jobs_workers_opt_in_by_label() { let model_info = model_info(); let mut features = Features::with_defaults(); features.enable(Feature::SpawnCsv); @@ -149,7 +149,7 @@ fn subagents_disable_request_user_input_and_agent_jobs_workers_opt_in_by_label() windows_sandbox_level: WindowsSandboxLevel::Disabled, }); - assert!(!tools_config.request_user_input); + assert!(tools_config.request_user_input); assert!(!tools_config.default_mode_request_user_input); assert!(tools_config.agent_jobs_tools); assert!(tools_config.agent_jobs_worker_tools);