mod approvals; pub(crate) mod call_trace; pub(crate) mod code_mode; pub(crate) mod context; mod control_tool_analytics; pub(crate) mod events; mod executed_tool_calls; pub(crate) mod handlers; pub(crate) mod hook_names; pub(crate) mod hosted_spec; pub(crate) mod lifecycle; pub(crate) mod network_approval; pub(crate) mod orchestrator; pub(crate) mod parallel; pub(crate) mod registry; pub(crate) mod router; pub(crate) mod runtimes; pub(crate) mod sandboxing; pub(crate) mod spec_plan; pub(crate) mod tool_dispatch_trace; mod tool_namespaces_info; use std::borrow::Cow; use crate::session::turn_context::TurnContext; pub(crate) use approvals::ApprovalContext; use codex_features::Feature; use codex_protocol::exec_output::ExecToolCallOutput; use codex_protocol::openai_models::ModelInfo; use codex_protocol::openai_models::ToolMode; use codex_tools::ToolName; use codex_utils_output_truncation::TruncationPolicy; use codex_utils_output_truncation::formatted_truncate_text; use codex_utils_output_truncation::truncate_text; pub(crate) use executed_tool_calls::ExecutedToolCalls; pub use router::ToolRouter; /// Legacy boundaries such as hook payloads, telemetry tags, and Responses tool /// names still require a single flattened string. Keep comparisons and sorting /// on `ToolName` itself; use this only when crossing those boundaries. pub(crate) fn flat_tool_name(tool_name: &ToolName) -> Cow<'_, str> { if tool_name.is_default_namespace() { return Cow::Borrowed(tool_name.name.as_str()); } match tool_name.namespace.as_deref() { Some(namespace) => { let mut name = String::with_capacity(namespace.len() + tool_name.name.len()); name.push_str(namespace); name.push_str(&tool_name.name); Cow::Owned(name) } None => Cow::Borrowed(tool_name.name.as_str()), } } pub(crate) fn tool_user_shell_type( user_shell: &crate::shell::Shell, ) -> codex_tools::ToolUserShellType { match user_shell.shell_type { crate::shell::ShellType::Zsh => codex_tools::ToolUserShellType::Zsh, crate::shell::ShellType::Bash => codex_tools::ToolUserShellType::Bash, crate::shell::ShellType::PowerShell => codex_tools::ToolUserShellType::PowerShell, crate::shell::ShellType::Sh => codex_tools::ToolUserShellType::Sh, crate::shell::ShellType::Cmd => codex_tools::ToolUserShellType::Cmd, } } pub(crate) fn requested_tool_mode(turn_context: &TurnContext, model_info: &ModelInfo) -> ToolMode { model_info.tool_mode.unwrap_or_else(|| { if turn_context.config.features.enabled(Feature::CodeModeOnly) { ToolMode::CodeModeOnly } else if turn_context.config.features.enabled(Feature::CodeMode) { ToolMode::CodeMode } else { ToolMode::Direct } }) } pub(crate) fn effective_tool_mode(turn_context: &TurnContext, model_info: &ModelInfo) -> ToolMode { let requested_tool_mode = requested_tool_mode(turn_context, model_info); if !turn_context.code_mode_available && requested_tool_mode == ToolMode::CodeMode && !turn_context.config.code_mode.disable_in_process_fallback { ToolMode::Direct } else { requested_tool_mode } } /// Format the combined exec output for sending back to the model. /// Includes exit code and duration metadata; truncates large bodies safely. pub fn format_exec_output_for_model( exec_output: &ExecToolCallOutput, truncation_policy: TruncationPolicy, ) -> String { // round to 1 decimal place let duration_seconds = ((exec_output.duration.as_secs_f32()) * 10.0).round() / 10.0; let content = build_content_with_timeout(exec_output); let total_lines = content.lines().count(); let formatted_output = truncate_text(&content, truncation_policy); let mut sections = Vec::new(); sections.push(format!("Exit code: {}", exec_output.exit_code)); sections.push(format!("Wall time: {duration_seconds} seconds")); if total_lines != formatted_output.lines().count() { sections.push(format!("Total output lines: {total_lines}")); } sections.push("Output:".to_string()); sections.push(formatted_output); sections.join("\n") } pub fn format_exec_output_str( exec_output: &ExecToolCallOutput, truncation_policy: TruncationPolicy, ) -> String { let content = build_content_with_timeout(exec_output); // Truncate for model consumption before serialization. formatted_truncate_text(&content, truncation_policy) } /// Extracts exec output content and prepends a timeout message if the command timed out. fn build_content_with_timeout(exec_output: &ExecToolCallOutput) -> String { if exec_output.timed_out { format!( "command timed out after {} milliseconds\n{}", exec_output.duration.as_millis(), exec_output.aggregated_output.text ) } else { exec_output.aggregated_output.text.clone() } }