Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion codex-rs/core/src/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,7 @@ impl Session {
self.conversation_id,
sub_id,
);
turn_context.tools_config.default_shell_name = Some(self.user_shell().display_name());
if let Some(final_schema) = final_output_json_schema {
turn_context.final_output_json_schema = final_schema;
}
Expand Down Expand Up @@ -2219,10 +2220,11 @@ async fn spawn_review_thread(
review_features
.disable(crate::features::Feature::WebSearchRequest)
.disable(crate::features::Feature::WebSearchCached);
let tools_config = ToolsConfig::new(&ToolsConfigParams {
let mut tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &review_model_info,
features: &review_features,
});
tools_config.default_shell_name = Some(sess.user_shell().display_name());

let base_instructions = REVIEW_PROMPT.to_string();
let review_prompt = resolved.prompt.clone();
Expand Down
8 changes: 8 additions & 0 deletions codex-rs/core/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ impl Shell {
}
}

pub(crate) fn display_name(&self) -> String {
self.shell_path
.file_stem()
.and_then(|stem| stem.to_str())
.map(str::to_string)
.unwrap_or_else(|| self.name().to_string())
}

/// Takes a string of shell and returns the full list of command args to
/// use with `exec()` to run the shell command.
pub fn derive_exec_args(&self, command: &str, use_login_shell: bool) -> Vec<String> {
Expand Down
31 changes: 23 additions & 8 deletions codex-rs/core/src/tools/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use std::collections::HashMap;
#[derive(Debug, Clone)]
pub(crate) struct ToolsConfig {
pub shell_type: ConfigShellToolType,
pub default_shell_name: Option<String>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be part of ConfigShellToolType?

pub apply_patch_tool_type: Option<ApplyPatchToolType>,
pub web_search_request: bool,
pub web_search_cached: bool,
Expand Down Expand Up @@ -71,6 +72,7 @@ impl ToolsConfig {

Self {
shell_type,
default_shell_name: None,
apply_patch_tool_type,
web_search_request: include_web_search_request,
web_search_cached: include_web_search_cached,
Expand All @@ -80,6 +82,12 @@ impl ToolsConfig {
}
}

fn default_shell_display(default_shell_name: Option<&str>) -> String {
default_shell_name
.map(str::to_string)
.unwrap_or_else(|| "the user's default shell".to_string())
}

/// Generic JSON‑Schema subset needed for our tool definitions
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "lowercase")]
Expand Down Expand Up @@ -136,7 +144,8 @@ impl From<JsonSchema> for AdditionalProperties {
}
}

fn create_exec_command_tool() -> ToolSpec {
fn create_exec_command_tool(default_shell_name: Option<&str>) -> ToolSpec {
let default_shell_display = default_shell_display(default_shell_name);
let properties = BTreeMap::from([
(
"cmd".to_string(),
Expand All @@ -156,7 +165,9 @@ fn create_exec_command_tool() -> ToolSpec {
(
"shell".to_string(),
JsonSchema::String {
description: Some("Shell binary to launch. Defaults to /bin/bash.".to_string()),
description: Some(format!(
"Shell binary to launch. Defaults to {default_shell_display}."
)),
},
),
(
Expand Down Expand Up @@ -329,13 +340,16 @@ Examples of valid command strings:
})
}

fn create_shell_command_tool() -> ToolSpec {
fn create_shell_command_tool(default_shell_name: Option<&str>) -> ToolSpec {
let default_shell_display = default_shell_display(default_shell_name);
let properties = BTreeMap::from([
(
"command".to_string(),
JsonSchema::String {
description: Some(
"The shell script to execute in the user's default shell".to_string(),
format!(
"The shell script to execute in {default_shell_display}"
),
),
},
),
Expand Down Expand Up @@ -1127,6 +1141,7 @@ pub(crate) fn build_specs(
let mcp_handler = Arc::new(McpHandler);
let mcp_resource_handler = Arc::new(McpResourceHandler);
let shell_command_handler = Arc::new(ShellCommandHandler);
let default_shell_name = config.default_shell_name.as_deref();

match &config.shell_type {
ConfigShellToolType::Default => {
Expand All @@ -1136,7 +1151,7 @@ pub(crate) fn build_specs(
builder.push_spec(ToolSpec::LocalShell {});
}
ConfigShellToolType::UnifiedExec => {
builder.push_spec(create_exec_command_tool());
builder.push_spec(create_exec_command_tool(default_shell_name));
builder.push_spec(create_write_stdin_tool());
builder.register_handler("exec_command", unified_exec_handler.clone());
builder.register_handler("write_stdin", unified_exec_handler);
Expand All @@ -1145,7 +1160,7 @@ pub(crate) fn build_specs(
// Do nothing.
}
ConfigShellToolType::ShellCommand => {
builder.push_spec(create_shell_command_tool());
builder.push_spec(create_shell_command_tool(default_shell_name));
}
}

Expand Down Expand Up @@ -1391,7 +1406,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(None),
create_write_stdin_tool(),
create_list_mcp_resources_tool(),
create_list_mcp_resource_templates_tool(),
Expand Down Expand Up @@ -2168,7 +2183,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(None);
let ToolSpec::Function(ResponsesApiTool {
description, name, ..
}) = &tool
Expand Down
Loading