mirror of
https://github.com/openai/codex.git
synced 2026-11-01 19:33:35 +00:00
Keep request_user_input schema stable for subagents
This commit is contained in:
@@ -5,6 +5,7 @@ use crate::tools::context::ToolPayload;
|
||||
use crate::tools::handlers::parse_arguments;
|
||||
use crate::tools::registry::ToolHandler;
|
||||
use crate::tools::registry::ToolKind;
|
||||
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;
|
||||
@@ -39,6 +40,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)
|
||||
@@ -67,3 +74,72 @@ impl ToolHandler for RequestUserInputHandler {
|
||||
Ok(FunctionToolOutput::from_text(content, Some(true)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::codex::make_session_and_context;
|
||||
use crate::turn_diff_tracker::TurnDiffTracker;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[tokio::test]
|
||||
async fn request_user_input_rejects_subagent_threads() {
|
||||
let (session, mut turn_context) = make_session_and_context().await;
|
||||
turn_context.session_source = SessionSource::SubAgent(SubAgentSource::ThreadSpawn {
|
||||
parent_thread_id: ThreadId::new(),
|
||||
depth: 1,
|
||||
agent_path: None,
|
||||
agent_nickname: None,
|
||||
agent_role: None,
|
||||
});
|
||||
|
||||
let err = match (RequestUserInputHandler {
|
||||
default_mode_request_user_input: true,
|
||||
})
|
||||
.handle(ToolInvocation {
|
||||
session: Arc::new(session),
|
||||
turn: Arc::new(turn_context),
|
||||
tracker: Arc::new(Mutex::new(TurnDiffTracker::default())),
|
||||
call_id: "call-1".to_string(),
|
||||
tool_name: REQUEST_USER_INPUT_TOOL_NAME.to_string(),
|
||||
tool_namespace: None,
|
||||
payload: ToolPayload::Function {
|
||||
arguments: json!({
|
||||
"questions": [{
|
||||
"header": "Hdr",
|
||||
"question": "Pick one",
|
||||
"id": "pick_one",
|
||||
"options": [
|
||||
{
|
||||
"label": "A",
|
||||
"description": "A"
|
||||
},
|
||||
{
|
||||
"label": "B",
|
||||
"description": "B"
|
||||
}
|
||||
]
|
||||
}]
|
||||
})
|
||||
.to_string(),
|
||||
},
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => panic!("subagents should not be allowed to request user input"),
|
||||
Err(err) => err,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
err,
|
||||
FunctionCallError::RespondToModel(
|
||||
"request_user_input can only be used by the root thread".to_string(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -491,7 +491,7 @@ fn test_build_specs_agent_job_worker_tools_enabled() {
|
||||
"report_agent_job_result",
|
||||
],
|
||||
);
|
||||
assert_lacks_tool_name(&tools, "request_user_input");
|
||||
assert_contains_tool_names(&tools, &["request_user_input"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user