feat: add config allow_login_shell (#12312)

This commit is contained in:
jif-oai
2026-02-20 20:02:24 +00:00
committed by GitHub
parent 67e802e26b
commit 5034d4bd89
9 changed files with 244 additions and 56 deletions

View File

@@ -35,6 +35,7 @@ const SEARCH_TOOL_BM25_DESCRIPTION_TEMPLATE: &str =
#[derive(Debug, Clone)]
pub(crate) struct ToolsConfig {
pub shell_type: ConfigShellToolType,
pub allow_login_shell: bool,
pub apply_patch_tool_type: Option<ApplyPatchToolType>,
pub web_search_mode: Option<WebSearchMode>,
pub agent_roles: BTreeMap<String, AgentRoleConfig>,
@@ -96,6 +97,7 @@ impl ToolsConfig {
Self {
shell_type,
allow_login_shell: true,
apply_patch_tool_type,
web_search_mode: *web_search_mode,
agent_roles: BTreeMap::new(),
@@ -112,6 +114,11 @@ impl ToolsConfig {
self.agent_roles = agent_roles;
self
}
pub fn with_allow_login_shell(mut self, allow_login_shell: bool) -> Self {
self.allow_login_shell = allow_login_shell;
self
}
}
/// Generic JSONSchema subset needed for our tool definitions
@@ -211,7 +218,7 @@ fn create_approval_parameters() -> BTreeMap<String, JsonSchema> {
properties
}
fn create_exec_command_tool() -> ToolSpec {
fn create_exec_command_tool(allow_login_shell: bool) -> ToolSpec {
let mut properties = BTreeMap::from([
(
"cmd".to_string(),
@@ -234,14 +241,6 @@ fn create_exec_command_tool() -> ToolSpec {
description: Some("Shell binary to launch. Defaults to the user's default shell.".to_string()),
},
),
(
"login".to_string(),
JsonSchema::Boolean {
description: Some(
"Whether to run the shell with -l/-i semantics. Defaults to true.".to_string(),
),
},
),
(
"tty".to_string(),
JsonSchema::Boolean {
@@ -269,6 +268,16 @@ fn create_exec_command_tool() -> ToolSpec {
},
),
]);
if allow_login_shell {
properties.insert(
"login".to_string(),
JsonSchema::Boolean {
description: Some(
"Whether to run the shell with -l/-i semantics. Defaults to true.".to_string(),
),
},
);
}
properties.extend(create_approval_parameters());
ToolSpec::Function(ResponsesApiTool {
@@ -385,7 +394,7 @@ Examples of valid command strings:
})
}
fn create_shell_command_tool() -> ToolSpec {
fn create_shell_command_tool(allow_login_shell: bool) -> ToolSpec {
let mut properties = BTreeMap::from([
(
"command".to_string(),
@@ -402,6 +411,14 @@ fn create_shell_command_tool() -> ToolSpec {
},
),
(
"timeout_ms".to_string(),
JsonSchema::Number {
description: Some("The timeout for the command in milliseconds".to_string()),
},
),
]);
if allow_login_shell {
properties.insert(
"login".to_string(),
JsonSchema::Boolean {
description: Some(
@@ -409,14 +426,8 @@ fn create_shell_command_tool() -> ToolSpec {
.to_string(),
),
},
),
(
"timeout_ms".to_string(),
JsonSchema::Number {
description: Some("The timeout for the command in milliseconds".to_string()),
},
),
]);
);
}
properties.extend(create_approval_parameters());
let description = if cfg!(windows) {
@@ -1462,7 +1473,10 @@ pub(crate) fn build_specs(
builder.push_spec_with_parallel_support(ToolSpec::LocalShell {}, true);
}
ConfigShellToolType::UnifiedExec => {
builder.push_spec_with_parallel_support(create_exec_command_tool(), true);
builder.push_spec_with_parallel_support(
create_exec_command_tool(config.allow_login_shell),
true,
);
builder.push_spec(create_write_stdin_tool());
builder.register_handler("exec_command", unified_exec_handler.clone());
builder.register_handler("write_stdin", unified_exec_handler);
@@ -1471,7 +1485,10 @@ pub(crate) fn build_specs(
// Do nothing.
}
ConfigShellToolType::ShellCommand => {
builder.push_spec_with_parallel_support(create_shell_command_tool(), true);
builder.push_spec_with_parallel_support(
create_shell_command_tool(config.allow_login_shell),
true,
);
}
}
@@ -1816,7 +1833,7 @@ mod tests {
// Build expected from the same helpers used by the builder.
let mut expected: BTreeMap<String, ToolSpec> = BTreeMap::from([]);
for spec in [
create_exec_command_tool(),
create_exec_command_tool(true),
create_write_stdin_tool(),
PLAN_TOOL.clone(),
create_request_user_input_tool(),
@@ -2790,7 +2807,7 @@ Examples of valid command strings:
#[test]
fn test_shell_command_tool() {
let tool = super::create_shell_command_tool();
let tool = super::create_shell_command_tool(true);
let ToolSpec::Function(ResponsesApiTool {
description, name, ..
}) = &tool