mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Reduce the surface of collaboration modes (#20149)
Collaboration modes were slightly invasive both into ThreadManager construction and ModelProvider
This commit is contained in:
@@ -83,6 +83,7 @@ pub use plan_tool::create_update_plan_tool;
|
||||
pub use request_user_input_tool::REQUEST_USER_INPUT_TOOL_NAME;
|
||||
pub use request_user_input_tool::create_request_user_input_tool;
|
||||
pub use request_user_input_tool::normalize_request_user_input_args;
|
||||
pub use request_user_input_tool::request_user_input_available_modes;
|
||||
pub use request_user_input_tool::request_user_input_tool_description;
|
||||
pub use request_user_input_tool::request_user_input_unavailable_message;
|
||||
pub use responses_api::FreeformTool;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::JsonSchema;
|
||||
use crate::ResponsesApiTool;
|
||||
use crate::ToolSpec;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::TUI_VISIBLE_COLLABORATION_MODES;
|
||||
use codex_protocol::request_user_input::RequestUserInputArgs;
|
||||
@@ -8,6 +10,17 @@ use std::collections::BTreeMap;
|
||||
|
||||
pub const REQUEST_USER_INPUT_TOOL_NAME: &str = "request_user_input";
|
||||
|
||||
pub fn request_user_input_available_modes(features: &Features) -> Vec<ModeKind> {
|
||||
TUI_VISIBLE_COLLABORATION_MODES
|
||||
.into_iter()
|
||||
.filter(|mode| {
|
||||
mode.allows_request_user_input()
|
||||
|| (features.enabled(Feature::DefaultModeRequestUserInput)
|
||||
&& *mode == ModeKind::Default)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn create_request_user_input_tool(description: String) -> ToolSpec {
|
||||
let option_props = BTreeMap::from([
|
||||
(
|
||||
@@ -85,9 +98,9 @@ pub fn create_request_user_input_tool(description: String) -> ToolSpec {
|
||||
|
||||
pub fn request_user_input_unavailable_message(
|
||||
mode: ModeKind,
|
||||
default_mode_request_user_input: bool,
|
||||
available_modes: &[ModeKind],
|
||||
) -> Option<String> {
|
||||
if request_user_input_is_available(mode, default_mode_request_user_input) {
|
||||
if available_modes.contains(&mode) {
|
||||
None
|
||||
} else {
|
||||
let mode_name = mode.display_name();
|
||||
@@ -115,23 +128,17 @@ pub fn normalize_request_user_input_args(
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
pub fn request_user_input_tool_description(default_mode_request_user_input: bool) -> String {
|
||||
let allowed_modes = format_allowed_modes(default_mode_request_user_input);
|
||||
pub fn request_user_input_tool_description(available_modes: &[ModeKind]) -> String {
|
||||
let allowed_modes = format_allowed_modes(available_modes);
|
||||
format!(
|
||||
"Request user input for one to three short questions and wait for the response. This tool is only available in {allowed_modes}."
|
||||
)
|
||||
}
|
||||
|
||||
fn request_user_input_is_available(mode: ModeKind, default_mode_request_user_input: bool) -> bool {
|
||||
mode.allows_request_user_input()
|
||||
|| (default_mode_request_user_input && mode == ModeKind::Default)
|
||||
}
|
||||
|
||||
fn format_allowed_modes(default_mode_request_user_input: bool) -> String {
|
||||
let mode_names: Vec<&str> = TUI_VISIBLE_COLLABORATION_MODES
|
||||
.into_iter()
|
||||
.filter(|mode| request_user_input_is_available(*mode, default_mode_request_user_input))
|
||||
.map(ModeKind::display_name)
|
||||
fn format_allowed_modes(available_modes: &[ModeKind]) -> String {
|
||||
let mode_names: Vec<&str> = available_modes
|
||||
.iter()
|
||||
.map(|mode| mode.display_name())
|
||||
.collect();
|
||||
|
||||
match mode_names.as_slice() {
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
use super::*;
|
||||
use crate::JsonSchema;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
fn default_mode_enabled_available_modes() -> Vec<ModeKind> {
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::DefaultModeRequestUserInput);
|
||||
request_user_input_available_modes(&features)
|
||||
}
|
||||
|
||||
fn default_available_modes() -> Vec<ModeKind> {
|
||||
request_user_input_available_modes(&Features::with_defaults())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn request_user_input_tool_includes_questions_schema() {
|
||||
assert_eq!(
|
||||
@@ -92,37 +104,28 @@ fn request_user_input_tool_includes_questions_schema() {
|
||||
#[test]
|
||||
fn request_user_input_unavailable_messages_respect_default_mode_feature_flag() {
|
||||
assert_eq!(
|
||||
request_user_input_unavailable_message(
|
||||
ModeKind::Plan,
|
||||
/*default_mode_request_user_input*/ false
|
||||
),
|
||||
request_user_input_unavailable_message(ModeKind::Plan, &default_available_modes()),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
request_user_input_unavailable_message(
|
||||
ModeKind::Default,
|
||||
/*default_mode_request_user_input*/ false
|
||||
),
|
||||
request_user_input_unavailable_message(ModeKind::Default, &default_available_modes()),
|
||||
Some("request_user_input is unavailable in Default mode".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
request_user_input_unavailable_message(
|
||||
ModeKind::Default,
|
||||
/*default_mode_request_user_input*/ true
|
||||
&default_mode_enabled_available_modes()
|
||||
),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
request_user_input_unavailable_message(
|
||||
ModeKind::Execute,
|
||||
/*default_mode_request_user_input*/ false
|
||||
),
|
||||
request_user_input_unavailable_message(ModeKind::Execute, &default_available_modes()),
|
||||
Some("request_user_input is unavailable in Execute mode".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
request_user_input_unavailable_message(
|
||||
ModeKind::PairProgramming,
|
||||
/*default_mode_request_user_input*/ false
|
||||
&default_available_modes()
|
||||
),
|
||||
Some("request_user_input is unavailable in Pair Programming mode".to_string())
|
||||
);
|
||||
@@ -131,11 +134,11 @@ fn request_user_input_unavailable_messages_respect_default_mode_feature_flag() {
|
||||
#[test]
|
||||
fn request_user_input_tool_description_mentions_available_modes() {
|
||||
assert_eq!(
|
||||
request_user_input_tool_description(/*default_mode_request_user_input*/ false),
|
||||
request_user_input_tool_description(&default_available_modes()),
|
||||
"Request user input for one to three short questions and wait for the response. This tool is only available in Plan mode.".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
request_user_input_tool_description(/*default_mode_request_user_input*/ true),
|
||||
request_user_input_tool_description(&default_mode_enabled_available_modes()),
|
||||
"Request user input for one to three short questions and wait for the response. This tool is only available in Default or Plan mode.".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::can_request_original_image_detail;
|
||||
use crate::request_user_input_available_modes;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::WebSearchConfig;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
@@ -109,7 +111,7 @@ pub struct ToolsConfig {
|
||||
pub spawn_agent_usage_hint_text: Option<String>,
|
||||
pub max_concurrent_threads_per_session: Option<usize>,
|
||||
pub wait_agent_min_timeout_ms: Option<i64>,
|
||||
pub default_mode_request_user_input: bool,
|
||||
pub request_user_input_available_modes: Vec<ModeKind>,
|
||||
pub experimental_supported_tools: Vec<String>,
|
||||
pub agent_jobs_tools: bool,
|
||||
pub agent_jobs_worker_tools: bool,
|
||||
@@ -145,8 +147,6 @@ impl ToolsConfig {
|
||||
let include_goal_tools = features.enabled(Feature::Goals);
|
||||
let include_multi_agent_v2 = features.enabled(Feature::MultiAgentV2);
|
||||
let include_agent_jobs = features.enabled(Feature::SpawnCsv);
|
||||
let include_default_mode_request_user_input =
|
||||
features.enabled(Feature::DefaultModeRequestUserInput);
|
||||
let include_search_tool =
|
||||
model_info.supports_search_tool && features.enabled(Feature::ToolSearch);
|
||||
let include_tool_suggest = features.enabled(Feature::ToolSuggest)
|
||||
@@ -228,7 +228,7 @@ impl ToolsConfig {
|
||||
spawn_agent_usage_hint_text: None,
|
||||
max_concurrent_threads_per_session: None,
|
||||
wait_agent_min_timeout_ms: None,
|
||||
default_mode_request_user_input: include_default_mode_request_user_input,
|
||||
request_user_input_available_modes: request_user_input_available_modes(features),
|
||||
experimental_supported_tools: model_info.experimental_supported_tools.clone(),
|
||||
agent_jobs_tools: include_agent_jobs,
|
||||
agent_jobs_worker_tools,
|
||||
|
||||
@@ -155,7 +155,7 @@ fn shell_zsh_fork_prefers_shell_command_over_unified_exec() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subagents_keep_request_user_input_mode_config_and_agent_jobs_workers_opt_in_by_label() {
|
||||
fn subagents_keep_request_user_input_config_and_agent_jobs_workers_opt_in_by_label() {
|
||||
let model_info = model_info();
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::DefaultModeRequestUserInput);
|
||||
@@ -175,7 +175,10 @@ fn subagents_keep_request_user_input_mode_config_and_agent_jobs_workers_opt_in_b
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
});
|
||||
|
||||
assert!(tools_config.default_mode_request_user_input);
|
||||
assert_eq!(
|
||||
tools_config.request_user_input_available_modes,
|
||||
request_user_input_available_modes(&features)
|
||||
);
|
||||
assert!(tools_config.agent_jobs_tools);
|
||||
assert!(tools_config.agent_jobs_worker_tools);
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ pub fn build_tool_registry_plan(
|
||||
|
||||
plan.push_spec(
|
||||
create_request_user_input_tool(request_user_input_tool_description(
|
||||
config.default_mode_request_user_input,
|
||||
&config.request_user_input_available_modes,
|
||||
)),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
|
||||
@@ -19,9 +19,11 @@ use crate::ToolRegistryPlanMcpTool;
|
||||
use crate::ToolsConfigParams;
|
||||
use crate::WaitAgentTimeoutOptions;
|
||||
use crate::mcp_call_tool_result_output_schema;
|
||||
use crate::request_user_input_available_modes;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::WebSearchConfig;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
@@ -88,7 +90,7 @@ fn test_full_toolset_specs_for_gpt5_codex_unified_exec_web_search() {
|
||||
}),
|
||||
create_write_stdin_tool(),
|
||||
create_update_plan_tool(),
|
||||
request_user_input_tool_spec(/*default_mode_request_user_input*/ false),
|
||||
request_user_input_tool_spec(&request_user_input_available_modes(&features)),
|
||||
create_apply_patch_freeform_tool(),
|
||||
ToolSpec::WebSearch {
|
||||
external_web_access: Some(true),
|
||||
@@ -586,7 +588,7 @@ fn request_user_input_description_reflects_default_mode_feature_flag() {
|
||||
let request_user_input_tool = find_tool(&tools, REQUEST_USER_INPUT_TOOL_NAME);
|
||||
assert_eq!(
|
||||
request_user_input_tool.spec,
|
||||
request_user_input_tool_spec(/*default_mode_request_user_input*/ false)
|
||||
request_user_input_tool_spec(&request_user_input_available_modes(&features))
|
||||
);
|
||||
|
||||
features.enable(Feature::DefaultModeRequestUserInput);
|
||||
@@ -609,7 +611,7 @@ fn request_user_input_description_reflects_default_mode_feature_flag() {
|
||||
let request_user_input_tool = find_tool(&tools, REQUEST_USER_INPUT_TOOL_NAME);
|
||||
assert_eq!(
|
||||
request_user_input_tool.spec,
|
||||
request_user_input_tool_spec(/*default_mode_request_user_input*/ true)
|
||||
request_user_input_tool_spec(&request_user_input_available_modes(&features))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2357,10 +2359,8 @@ fn assert_lacks_tool_name(tools: &[ConfiguredToolSpec], expected_absent: &str) {
|
||||
);
|
||||
}
|
||||
|
||||
fn request_user_input_tool_spec(default_mode_request_user_input: bool) -> ToolSpec {
|
||||
create_request_user_input_tool(request_user_input_tool_description(
|
||||
default_mode_request_user_input,
|
||||
))
|
||||
fn request_user_input_tool_spec(available_modes: &[ModeKind]) -> ToolSpec {
|
||||
create_request_user_input_tool(request_user_input_tool_description(available_modes))
|
||||
}
|
||||
|
||||
fn spawn_agent_tool_options(config: &ToolsConfig) -> SpawnAgentToolOptions<'_> {
|
||||
|
||||
Reference in New Issue
Block a user